cudaEventRecord() Nu cronometrează corect pe codul Visual Studio CPU (Programare, C, Windows, Visual Studio 2013, Timp, Cuda)

Ander Biguri a intrebat.

În timp ce făceam câteva exemple de bază de CUDA realizate de NVIDIA am copiat un cod pentru a testa creșterea de viteză de la calculul pe CPU la cel pe GPU pentru înmulțirea matricelor.

După 30 de minute în care m-am uitat la rezultate și am văzut cum CPU-ul meu (da, CPU) efectua calcule de 1000 de ori mai rapide decât GPU-ul meu, mi-am dat seama că sincronizarea nu funcționa corect. Un fragment din cod arată astfel (acesta este codul de la NVIDIA):

//Create timers
cudaEvent_t start;
cudaEvent_t stop;
float simpleKernelTime;
float optimisedKernelTime;

//start timer
cudaEventCreate(&start);
cudaEventCreate(&stop);
cudaEventRecord(start, 0);

matrixMultKernel<<<grid, block >>>(a_d, b_d, c_d, N);

cudaEventRecord(stop, 0);
cudaEventSynchronize(stop);
cudaEventElapsedTime(&elapsedTime, start, stop);

// Print time and do other things

cudaEventRecord(start, 0);

matrixMultCPU(a_h, b_h, d_, N);

cudaEventRecord(stop, 0)
cudaEventSynchronize(stop);
cudaEventElapsedTime(&elapsedTime, start, stop);

// Print time

Acest cod funcționează bine pe o mașină Linux (am copiat același cod ca și persoana de lângă mine și el obținea o sincronizare bună), dar pe o mașină Windows 8 cu Visual Studio 2013, sincronizarea pe partea de CPU (a doua jumătate a fragmentului) nu funcționa (dădea întotdeauna ~0,003ms).

De ce se întâmplă acest lucru? Am rezolvat problema folosind <time.h> (eliminând cudaEventRecord() apelurilor și folosind abordări standard de sincronizare a codului C), deci nu vreau să știu cum se repară, ci mai mult de ce se întâmplă acest lucru.

Comentarii

  • @buttifulbuttefly nononono, am eliminat cudaEventRecord apelurile și am folosit sincronizarea standard a codului C. –  > Por Ander Biguri.
  • În legătură cu votul închis: „Acest cod funcționează și știu cum să îl fac să funcționeze corect. Nu cer ajutor pentru depanarea codului, este o întrebare teoretică bună, cred eu. –  > Por Ander Biguri.
  • Pe Linux și Windows, activitatea driverului TCC este trimisă direct de la driver în bufferul de împingere al GPU. Pe Windows, activitatea driverului WDDM este trimisă într-o coadă software. Atunci când aceasta se supraaglomerează, activitatea este transmisă către driverul WDDM în modul kernel într-un buffer de comandă, iar driverul transmite întregul buffer de comandă către GPU. Dacă adăugați apelul cudaEventQuery(0) după cudaEventRecord(start…), ar trebui să vedeți un comportament mai apropiat de cel din Linux, deoarece acest apel va goli coada. Acestea fiind spuse, nu folosiți cudaEventRecord sau clock pentru a cronometra ceasul CPU. Folosiți cronometrul de mare precizie al platformei. –  > Por Greg Smith.
1 răspunsuri
Grzegorz Szpetkowski

Din câte am înțeles, evenimentele CUDA nu sunt concepute pentru a măsura timpul dedicat numai CPU (numai gazdă) în sine, ci mai degrabă execuția kernelului și apelurile API CUDA. De la Ghid de programare CUDA C 3.2.5.6. Evenimente (sublinierea îmi aparține):

Timpul de execuție oferă, de asemenea, o modalitate de a monitoriza îndeaproape progresul dispozitivului, , precum și de a efectua o cronometrare precisă, permițând aplicației să înregistreze în mod asincron evenimente în orice punct al programului și să interogheze când aceste evenimente sunt finalizate.

Sunt, de asemenea, surprins că obțineți vreun timp (lansările de kernel sunt asincrone), deoarece codul dvs. lipsește cudaEventSynchronize():

cudaEventRecord(stop, 0);
cudaEventSynchronize(stop);
cudaEventElapsedTime(&elapsedTime, start, stop);

A se vedea, de asemenea Cum să implementați măsurători de performanță în CUDA C/C++.

Pentru măsurarea timpului doar pentru CPU, consultați acest fir de discuție.

EDIT:

Pentru a obține timpul corect pentru matrixMultCPU() trebuie să adăugați sincronizarea pentru start eveniment:

cudaEventRecord(start, 0);
cudaEventSynchronize(start);

Comentarii

  • Opps, greșeala mea! Eu folosesc cudaEventSynchronize(stop); în codul meu original. Cu toate acestea, nu este necesar să se utilizeze cudaEventRecord() funcționează pe CPU în alte sisteme/compilatoare (nu știu sigur de ce). Adică, codul este scris de NVIDIA, nu de mine, și l-am văzut corect timp în alte sisteme de operare/compilatoare, doar că nu funcționează pe sistemul meu. –  > Por Ander Biguri.
  • Poate că întrebarea mea ar fi trebuit să fie formulată invers atunci: De ce cudaEventRecord() funcționează pentru cronometrarea codului non-GPU pe Linux cu nvcc ? –  > Por Ander Biguri.
  • @AnderBiguri: Mi-am editat răspunsul. Vezi dacă funcționează pentru tine. Probabil că implementarea GNU/Linux sincronizează start în mod implicit. –  > Por Grzegorz Szpetkowski.
  • Înțeleg, mulțumesc. Voi lăsa această problemă deschisă pentru o vreme, deoarece mă interesează de ce se întâmplă acest lucru…  > Por Ander Biguri.