2011-10-07 16 views
5

Ecco due parti di codice da un kernel OpenCL su cui sto lavorando; mostrano tempi di esecuzione molto diversi.OpenCL: Perché le prestazioni differiscono notevolmente tra questi due casi?

Il codice è piuttosto complicato, quindi l'ho semplificato in basso.

Questa versione viene eseguito in meno di un secondo:

for (int ii=0; ii<someNumber;ii++) 
{ 
    for (int jj=0; ii<someNumber2;jj++) 
    { 
     value1 = value2 + value3; 
     value1 = value1 * someFunction(a,b,c); 
     double nothing = value1; 
    } 
} 

e questa versione impiega circa 38 secondi per eseguire:

for (int ii=0; ii<someNumber;ii++) 
{ 
    for (int jj=0; ii<someNumber2;jj++) 
    { 
     value1 = value2 + value3; 
     value1 = value1 * someFunction(a,b,c); 
    } 
    double nothing = value1; 
} 

Come ho detto, il codice è un po 'più complicato di questo (non c'è molte altre cose in corso nei loop), ma la variabile "niente" passa realmente da subito prima a subito dopo il tutore.

Sono molto nuovo a OpenCL e non riesco a capire cosa sta succedendo, tanto meno come risolverlo. Inutile dire che il caso lento è in realtà ciò di cui ho bisogno nella mia implementazione. Ho provato a fare scherzi con gli spazi degli indirizzi (tutte le variabili qui sono in __private).

Posso solo immaginare che per qualche motivo la GPU stia spingendo la variabile "value1" nella memoria più lenta quando la parentesi si chiude. Questa è una spiegazione probabile? Cosa posso fare?

Grazie in anticipo!

AGGIORNAMENTO: Funziona anche in meno di un secondo: (ma con la scomparsa di entrambe le linee, si torna a una lentezza estrema). Questo è senza apportare altre modifiche ai loop e value1 è ancora dichiarato nello stesso posto di prima.

for (int ii=0; ii<someNumber;ii++) 
{ 
    for (int jj=0; ii<someNumber2;jj++) 
    { 
//  value1 = value2 + value3; 
//  value1 = value1 * someFunction(a,b,c); 
    } 
    double nothing = value1; 
} 

UPDATE 2: Il codice è stato in realtà annidato in un altro ciclo come questo, con la dichiarazione di value1 come mostrato:

double value1=0; 
for (int kk=0; kk<someNumber3;kk++) 
{ 
    for (int ii=0; ii<someNumber;ii++) 
    { 
     for (int jj=0; ii<someNumber2;jj++) 
     { 
      value1 = value2 + value3; 
      value1 = value1 * someFunction(a,b,c); 
     } 
     double nothing = value1; 
    } 
} 

Moving dove value1 è dichiarato inoltre ci si rimette al caso speedy:

for (int kk=0; kk<someNumber3;kk++) 
{ 
    double value1=0; 
    for (int ii=0; ii<someNumber;ii++) 
    { 
     for (int jj=0; ii<someNumber2;jj++) 
     { 
      value1 = value2 + value3; 
      value1 = value1 * someFunction(a,b,c); 
     } 
     double nothing = value1; 
    } 
} 

Sembra OpenCL è un'arte estremamente difficile! Ancora non capisco cosa sta succedendo, ma almeno so come aggiustarlo ora!

+0

Questo è piuttosto strano. Sei sicuro di aver bisogno di usare la versione più lenta? Da questi frammenti sembrano funzionalmente identici. – Chriszuma

+0

Grazie per la risposta. Sì, ne sono sicuro, ma hai ragione che gli esempi che ho dato sono funzionalmente identici. Il codice nelle parentesi interne dovrebbe avere un + =. – carthurs

+0

Non vedo alcuna ragione per cui il secondo dovrebbe essere più lento sulla base di quei frammenti di codice. Direi che lo spostamento del compito deve avere effetti collaterali da qualche parte, come l'aumento della ramificazione (una unità di lavoro esegue il comando "if", il successivo esegue "else"), che può davvero rallentare la GPU. –

risposta

4

Quale implementazione stai utilizzando? Mi aspetterei che "double nothing = value1;" essere eliminato come codice morto in uno qualsiasi dei casi da qualsiasi compilatore ragionevole.

+0

Penso di aver trovato il problema, grazie al tuo post. Nel caso 1 (la prima casella della mia domanda), penso che il compilatore ottimizzi "eliminando come codice morto" il ciclo interno. Nel caso 2, si rende conto che la variabile 'value1' è necessaria al di fuori del ciclo interno, quindi lo esegue. La funzione 'someFunction (a, b, c)' è molto lenta, quindi questo causa il rallentamento. FYI l'implementazione è SDK di AMD per Linux. Grazie per l'aiuto a tutti! – carthurs

+0

Stai dicendo che poiché value1 non è utilizzato, il compilatore ottimizza la chiamata a someFunction. Come può essere sicuro che una funzione non abbia un effetto collaterale? – vocaro

+0

Perché "niente" non è utilizzato. Non stavo parlando di value1. – arsenm

2

Il primo caso è solo un ciclo (con ottimizzazioni del compilatore) Ma il secondo è un ciclo con un ciclo annidato. Questo è il grande problema. Un sacco di controlli delle variabili globali/locali (certo che siano private? Hai dichiarato tutto ciò che è contenuto nel kernel?)

Ti consiglio di salvare come variabile privata (somenum e somenumber2) prima di iniziare il ciclo. Perché in questo modo verrai controllato ogni volta con dati privati. Come esperienza personale, ogni var utilizzata come caso di controllo di un ciclo OpenCL deve essere privata. Questo può risparmiare fino all'80% dell'accesso alla memoria globale. (Soprattutto se il ciclo è molto breve o semplice)

A titolo di esempio, questo dovrebbe funzionare veloce:

int c_somenumber = someNumber; 
for (int ii=0; ii<c_someNumber;ii++) 
{ 
    int c_somenumber2 = someNumber2;  
    for (int jj=0; ii<c_someNumber2;jj++) 
    { 
     value1 = value2 + value3; 
     value1 = value1 * someFunction(a,b,c); 
    } 
    double nothing = value1; 
} 

EDIT: Inoltre, valore1 DOVREBBE essere memorizzate nella cache in memoria privata.(Come hai fatto nella tua ultima modifica)

+0

Sì, tutto è salvato come privato. Vedi la mia spiegazione del problema come commento sull'altra risposta! – carthurs

Problemi correlati