Qual è la differenza tra la creazione di un oggetto buffer con clCreateBuffer + CL_MEM_COPY_HOST_PTR vs. clCreateBuffer + clEnqueueWriteBuffer?

StackOverflow https://stackoverflow.com/questions/3832963

  •  26-09-2019
  •  | 
  •  

Domanda

ho visto entrambe le versioni a tutorial, ma non ho potuto sapere, quali sono i loro vantaggi e svantaggi sono. Quale è quello giusto?

cl_mem input = clCreateBuffer(context,CL_MEM_READ_ONLY,sizeof(float) * DATA_SIZE, NULL, NULL);
clEnqueueWriteBuffer(command_queue, input, CL_TRUE, 0, sizeof(float) * DATA_SIZE, inputdata, 0, NULL, NULL);

vs.

cl_mem input = clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, ,sizeof(float) * DATA_SIZE, inputdata, NULL);

Grazie.

[Aggiornamento]

ho aggiunto CL_MEM_COPY_HOST_PTR, al secondo esempio per renderlo corretto.

È stato utile?

Soluzione

Presumo che InputData non è NULL.

In questo caso il secondo approccio non dovrebbe lavoro a tutti, dal momento che le specifiche dice che clCreateBuffer restituisce NULL e un errore, se:

  

CL_INVALID_HOST_PTR se host_ptr è NULL e CL_MEM_USE_HOST_PTR o CL_MEM_COPY_HOST_PTR sono impostati in bandiere o se host_ptr non è NULL, ma CL_MEM_COPY_HOST_PTR o CL_MEM_USE_HOST_PTR non sono impostate in bandiere.

in modo da significare sia

clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,sizeof(float) * DATA_SIZE, inputdata, NULL);

o

clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR,sizeof(float) * DATA_SIZE, inputdata, NULL);

Il primo dovrebbe essere più o meno lo stesso come il primo approccio che ha mostrato, mentre il secondo non sarà effettivamente copiare i dati, ma invece utilizzare la posizione di memoria in dotazione per memorizzazione temporanea (caching porzioni o tutto in memoria del dispositivo). Quale di questi due è migliore dipende dal modo di utilizzo, ovviamente.

Personalmente preferisco utilizzando l'approccio in due fasi della prima allocazione del buffer e poi lo riempie di un writeToBuffer, dal momento che trovo più facile per vedere cosa succede (ovviamente un passo potrebbe essere più veloce (o non potrebbe, questo è solo un supposizione))

Altri suggerimenti

Durante il mio lavoro con OpenCL ho trovato una differenza molto importante tra il

cl_mem CT = clCreateImage3DContext, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR , Volume_format, X, Y, Z, rowPitch, slicePitch, sourceData, &error);

e

cl_mem CT = clCreateImage3D(Context, CL_MEM_READ_ONLY , Volume_format, X, Y, Z, 0, 0, 0, &error);
error = clEnqueueWriteImage(CommandQue, CT, CL_TRUE, origin, region, rowPitch, slicePitch, sourceData, 0, 0, 0);

Per il primo approccio OpenCL copierà il puntatore ospitante non diretto alla GPU. In primo luogo che assegnerà un secondo buffer temporanea dell'host che può causare problemi se si carica roba grossa come una TAC alla GPU. Per un breve tempo la memoria necessaria è il doppio CT. Anche i dati non vengono copiati durante questa funzione. Esso viene copiato durante l'impostazione argomento della funzione del kernel che utilizza l'oggetto 3D.

L'copie dirette secondo approccio i dati alla GPU. Non ci sono assegnazioni supplementari fatto da OpenCL. Penso che questo è probabilmente lo stesso per i normali oggetti buffer.

L'aspetto piacevole del primo approccio, è che "clEnqueueWriteBuffer" consente di assegnare un evento alla copia di un buffer. Quindi, diciamo che si vuole misurare il tempo necessario per copiare i dati alla GPU utilizzando le opzioni GPU_Profiling, si sarà in grado di farlo con il primo approccio, ma non con la seconda.

Il secondo approccio è più compatta, facile da leggere, e richiede meno linee di codice.

Una grossa differenza che ho incontrato:

cl_mem input = clCreateBuffer(context,CL_MEM_READ_ONLY,sizeof(float) * DATA_SIZE, NULL, NULL); clEnqueueWriteBuffer(command_queue, input, CL_TRUE, 0, sizeof(float) * DATA_SIZE, inputdata, 0, NULL, NULL);

Questa prima serie di comandi creerà un buffer vuoto e accodare un comando nella coda di comandi per riempire il buffer.

cl_mem input = clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, ,sizeof(float) * DATA_SIZE, inputdata, NULL)

Questo secondo comando creerà il buffer e riempirlo immediatamente. Nota che non c'è coda di comandi in questo elenco di argomenti, in modo che utilizza il contenuto dei dati di input come lo è adesso.

Se hai già stato in esecuzione il codice CL e il puntatore fonte dipende da un comando precedente nella coda di comando completamento (ad esempio un accodato lettura di un buffer di uscita precedente), è sicuramente desidera utilizzare il metodo 1 °. Se si tenta di creare e riempire il buffer in un unico comando, vi ritroverete con una condizione di competizione in cui i contenuti del buffer non correttamente l'ora per il completamento della vostra lettura del buffer prima.

Bene la differenza principale tra questi due è che la prima memoria uno alloca sul dispositivo e quindi copia dati a quella memoria. La seconda solo alloca.

O volevi dire clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,sizeof(float) * DATA_SIZE, inputdata, NULL);?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top