Cosa sta aspettando la mia GPU?


11

Sto scrivendo un programma OpenCL da utilizzare con la mia GPU AMD Radeon HD serie 7800. Secondo la guida alla programmazione OpenCL di AMD , questa generazione di GPU ha due code hardware che possono funzionare in modo asincrono.

5.5.6 Coda di comando

Per le isole meridionali e successive, i dispositivi supportano almeno due code di calcolo hardware. Ciò consente a un'applicazione di aumentare il throughput di piccoli invii con due code di comando per l'invio asincrono e possibilmente l'esecuzione. Le code di calcolo dell'hardware sono selezionate nel seguente ordine: prima coda = anche code dei comandi OCL, seconda coda = code OCL dispari.

Per fare ciò, ho creato due code di comando OpenCL separate per inviare dati alla GPU. All'incirca, il programma in esecuzione sul thread host è simile al seguente:

static const int kNumQueues = 2;
cl_command_queue default_queue;
cl_command_queue work_queue[kNumQueues];

static const int N = 256;
cl_mem gl_buffers[N];
cl_event finish_events[N];

clEnqueueAcquireGLObjects(default_queue, gl_buffers, N);

int queue_idx = 0;
for (int i = 0; i < N; ++i) {
  cl_command_queue queue = work_queue[queue_idx];

  cl_mem src = clCreateBuffer(CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, ...);

  // Enqueue a few kernels
  cl_mem tmp1 = clCreateBuffer(CL_READ_WRITE);
  clEnqueueNDRangeKernel(kernel1, queue, src, tmp1);

  clEnqueueNDRangeKernel(kernel2, queue, tmp1, tmp1);

  cl_mem tmp2 = clCreateBuffer(CL_READ_WRITE);
  clEnqueueNDRangeKernel(kernel2, queue, tmp1, tmp2);

  clEnqueueNDRangeKernel(kernel3, queue, tmp2, gl_buffer[i], finish_events + i);

  queue_idx = (queue_idx + 1) % kNumQueues;
}

clEnqueueReleaseGLObjects(default_queue, gl_buffers, N);
clWaitForEvents(N, finish_events);

Con kNumQueues = 1, questa applicazione funziona praticamente come previsto: raccoglie tutto il lavoro in una singola coda di comandi che viene quindi eseguita fino al completamento con la GPU che è abbastanza occupata per tutto il tempo. Sono in grado di vedere questo guardando l'output del profiler CodeXL:

inserisci qui la descrizione dell'immagine

Tuttavia, quando ho impostato kNumQueues = 2, mi aspetto che accada la stessa cosa, ma con il lavoro suddiviso uniformemente su due code. Semmai, mi aspetto che ogni coda abbia le stesse caratteristiche singolarmente dell'unica coda: che inizi a lavorare in sequenza fino a quando non viene fatto tutto. Tuttavia, quando si utilizzano due code, posso vedere che non tutto il lavoro è suddiviso tra le due code hardware:

inserisci qui la descrizione dell'immagine

All'inizio del lavoro della GPU, le code riescono a far funzionare alcuni kernel in modo asincrono, anche se sembra che nessuno dei due occupi completamente le code hardware (a meno che la mia comprensione non sia errata). Verso la fine del lavoro della GPU, sembra che le code aggiungano lavoro in sequenza solo a una delle code hardware, ma ci sono anche volte in cui nessun kernel è in esecuzione. Cosa dà? Ho dei malintesi fondamentali su come dovrebbe comportarsi il runtime?

Ho alcune teorie sul perché questo sta accadendo:

  1. Le clCreateBufferchiamate intervallate stanno costringendo la GPU ad allocare le risorse del dispositivo da un pool di memoria condiviso in modo sincrono che blocca l'esecuzione dei singoli kernel.

  2. L'implementazione OpenCL sottostante non associa le code logiche alle code fisiche e decide solo dove posizionare gli oggetti in fase di esecuzione.

  3. Poiché sto usando oggetti GL, la GPU deve sincronizzare l'accesso alla memoria appositamente allocata durante le scritture.

Qualcuno di questi presupposti è vero? Qualcuno sa cosa potrebbe causare l'attesa della GPU nello scenario a due code? Qualsiasi intuizione sarebbe apprezzata!


Non riesco a trovare dove si dice che ci sono due code hardware nella guida alla programmazione. Potresti pubblicare un preventivo dal documento? Menziona quale capitolo dice che ci sono due code? Il numero di code hardware è interrogabile in runtime utilizzando OpenCL?
Andreas,

Ho aggiornato il mio post. Dice possibile esecuzione, ma se può fare alcuni perché non può fare tutti loro? Inoltre, il runtime OpenCL non ha alcuna nozione di coda hardware, quindi non è qualcosa su cui puoi interrogare.
Mokosha,

Risposte:


2

Le code di calcolo in generale non significano necessariamente che ora puoi fare 2x invii in parallelo. Una singola coda che satura completamente le unità di calcolo avrà un throughput migliore. Più code sono utili se una coda consuma meno risorse (memoria condivisa o registri), quindi le code secondarie possono quindi sovrapporsi sulla stessa unità di calcolo.

Per il rendering in tempo reale questo è particolarmente vero con cose come il rendering delle ombre che sono molto leggere su compute / shader ma pesanti su hardware a funzione fissa, liberando così lo scheduler GPU per eseguire la coda secondaria asincrona.

Ho trovato anche questo nelle note di rilascio. Non so se è lo stesso problema, ma potrebbe essere che CodeXL non sia eccezionale. Mi aspetto che potrebbe non avere la migliore strumentazione per la quale sono in corso spedizioni.

https://developer.amd.com/wordpress/media/2013/02/AMD_CodeXL_Release_Notes.pdf

Per un'applicazione che esegue il trasferimento simultaneo di dati asincroni e l'esecuzione del kernel, la sequenza temporale mostrata nella vista della sessione Traccia applicazione non mostrerà queste operazioni sovrapposte. Questo perché il driver e l'hardware costringono queste operazioni a essere sincrone durante la creazione del profilo. (333981)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.