2014-10-02 8 views
5

Sto lavorando a un'app OS X in una configurazione multi-GPU (Mac Pro a fine 2013) che utilizza OpenCL (sulla GPU secondaria) per generare un trama che viene successivamente disegnata sullo schermo con OpenGL (sulla GPU primaria). L'applicazione è CPU-bound a causa di chiamate a glBindTexture() e glBegin(), entrambi i quali spendono praticamente tutto il loro tempo in:OpenGL/OpenCL Prestazioni di interoperabilità in glBindTexture(), glBegin()

_platform_memmove$VARIANT$Ivybridge 

che è una parte del driver video:

AMDRadeonX4000GLDriver 

Setup: crea l'OpenGL trama (glPixelBuffer) e poi la sua controparte OpenCL (clPixelBuffer).

cl_int clerror = 0; 
GLuint glPixelBuffer = 0; 
cl_mem clPixelBuffer = 0; 

glGenTextures(1, &glPixelBuffer); 
glBindTexture(GL_TEXTURE_2D, glPixelBuffer); 
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2048, 2048, 0, GL_RGBA, GL_FLOAT, NULL); 
glBindTexture(GL_TEXTURE_2D, 0); 

clPixelBuffer = clCreateFromGLTexture(_clShareGroupContext, CL_MEM_WRITE_ONLY, GL_TEXTURE_2D, 0, glPixelBuffer, &clerror); 

Codice disegno: esegue il mapping della trama OpenGL sulla vista. L'intera NSOpenGLView è solo questa trama.

glClear(GL_COLOR_BUFFER_BIT); 

glBindTexture(GL_TEXTURE_2D, _glPixelBuffer); // <- spends cpu time here, 
glBegin(GL_QUADS);        // <- and here 
glTexCoord2f(0., 0.); glVertex3f(-1.f, 1.f, 0.f); 
glTexCoord2f(0., hr); glVertex3f(-1.f, -1.f, 0.f); 
glTexCoord2f(wr, hr); glVertex3f(1.f, -1.f, 0.f); 
glTexCoord2f(wr, 0.); glVertex3f(1.f, 1.f, 0.f); 
glEnd(); 
glBindTexture(GL_TEXTURE_2D, 0); 

glFlush(); 

Dopo aver acquisito il controllo della memoria texture (via clEnqueueAcquireGLObjects()), il kernel OpenCL scrive i dati alla struttura e quindi rilascia il controllo di esso (via clEnqueueReleaseGLObjects()). I dati di trama non dovrebbero mai esistere nella memoria principale (se capisco tutto correttamente).

La mia domanda è: è previsto che si spenda così tanto tempo di CPU in memmove()? È indicativo di un problema nel mio codice? O un bug nel driver, forse? Il mio (infondato) sospetto è che i dati delle texture si muovano tramite: GPUx -> CPU/RAM -> GPUy, che vorrei evitare.

+0

Avete una connessione crossfire/sli? Qual è la tua versione e larghezza di banda pci-e? Quanto è grande la tua texture? –

+0

Questo è Mac OS X, quindi non è disponibile il supporto Crossfire o SLI. Ogni GPU ha 15,7 GB/sec di larghezza di banda PCIe 3.0 (16 corsie ciascuna). E la mia app sta lavorando con (a seconda della configurazione) tra una e tre trame a 2048x2048. – senojsitruc

risposta

2

Prima di tocco sul trasferimento di memoria, la mia prima osservazione è che si sta utilizzando clBegin(), che non sta per essere il vostro migliore amico, perché

1) Questo disegno diretto non funziona bene con il driver . Usa VBO, ecc., In modo che questi dati possano vivere sulla GPU.

2) Su OS X significa che ci si trova nel vecchio contesto di compatibilità anziché nel nuovo contesto principale. Come (capisco) il nuovo contesto è una completa riscrittura, questo è dove le future ottimizzazioni finiranno mentre il contesto che stai usando è (probabilmente) semplicemente mantenuto.

Quindi al trasferimento di memoria .... sul lato GL stai mettendo in glCreateSyncFromCLeventARB() e glWaitSync() su quello? Non ci dovrebbe essere bisogno del glFlush() che vedo nel tuo codice. Una volta eliminato il disegno della modalità immediata (come menzionato sopra) e si stanno utilizzando oggetti di sincronizzazione tra le due API, il codice host non dovrebbe fare nulla (tranne chiedere al driver di dire alla GPU di fare qualcosa). Questo ti darà la tua migliore possibilità di avere copie tampone veloci ...

Sì, copie: (Perché la tua texture CL vive fisicamente su un diverso pezzo di memoria GPU alla texture GL ci dovrà essere una copia su Bus PCIe che sarà lento (er) .Questo è ciò che stai vedendo nel tuo profilo. Quello che sta realmente accadendo è che la CPU sta mappando la memoria GPU A e la memoria GPU B nella memoria host bloccata e quindi copierà tra loro (si spera) con un DMA. Dubito che i dati tocchino effettivamente la memoria di sistema, quindi lo spostamento è GPUx -> GPUy

Prova a mettere i tuoi contesti CL e GL sulla stessa GPU e penso che vedrai il tuo tempo di trasferimento sparire.

Pensiero finale: se il tuo calcolo CL è sminuito dal tempo di trasferimento è probabilmente meglio attaccare i contesti sulla stessa CPU. Hai il classico problema di suddivisione delle attività CPU/GPU.

+0

Grazie per la risposta. Farò una prova il prima possibile! – senojsitruc

Problemi correlati