Was ist der Unterschied ein Puffer-Objekt mit clCreateBuffer + CL_MEM_COPY_HOST_PTR vs. clCreateBuffer + clEnqueueWriteBuffer zwischen dem Erstellen?

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

  •  26-09-2019
  •  | 
  •  

Frage

Ich habe beiden Versionen in Tutorials gesehen, aber ich kann nicht herausfinden, was ihre Vor- und Nachteile sind. Welches ist die richtige ist?

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);

Danke.

[Update]

Ich habe CL_MEM_COPY_HOST_PTR, dem zweiten Beispiel es richtig zu machen.

War es hilfreich?

Lösung

gehe ich davon aus, dass Eingangsdaten nicht NULL ist.

In diesem Fall ist der zweite Ansatz nicht funktionieren sollte überhaupt, da die Spezifikationen sagt, dass clCreateBuffer gibt NULL zurück, und ein Fehler, wenn:

  

CL_INVALID_HOST_PTR wenn host_ptr NULL ist und CL_MEM_USE_HOST_PTR oder CL_MEM_COPY_HOST_PTR gesetzt in den Flaggen oder wenn host_ptr nicht NULL ist aber CL_MEM_COPY_HOST_PTR oder CL_MEM_USE_HOST_PTR sind in Flags nicht gesetzt.

Sie meinen also entweder

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

oder

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

Die erste sollte mehr oder weniger der gleiche wie der erste Ansatz, den Sie zeigte, während der zweite wird nicht wirklich die Daten zu kopieren, sondern verwenden Sie die mitgelieferte Speicherstelle für Pufferspeicher (Caching Teile oder alles davon in Gerätespeicher). Welche der beiden letztgenannten ist, hängt besser auf dem Einsatzszenario offensichtlich.

Personaly Ich ziehe es mit dem zweistufigen Ansatz zunächst die Puffer Aufteilung und danach mit einem writeToBuffer Füllung, da ich es einfacher finden, um zu sehen, was (natürlich ein Schritt passiert sein könnte schneller (oder auch nicht, das ist nur ein guess))

Andere Tipps

Während meiner Arbeit mit OpenCL Ich fand einen sehr wichtigen Unterschied zwischen

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

und

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);

Für den ersten Ansatz OpenCL wird der Host-Zeiger nicht direkt auf die GPU kopieren. Zunächst wird es einen zweiten temporären Puffer auf dem Host zuweisen, die Probleme verursachen können, wenn Sie große Sachen wie ein CT an die GPU laden. Für kurze Zeit ist der benötigte Speicher doppelt so groß wie CT Größe. Auch werden die Daten nicht in dieser Funktion kopiert. Es wird während des Arguments Einstellung auf die Kernel-Funktion kopiert, die das Objekt 3D-Bild verwendet wird.

Der zweite Ansatz direkt kopiert die Daten auf die GPU. Es gibt keine zusätzliche Zuweisungen von OpenCL getan. Ich denke, das ist wahrscheinlich das gleiche für normale Puffer-Objekte.

Der schöne Aspekt des ersten Ansatzes ist, dass „clEnqueueWriteBuffer“ ermöglicht es Ihnen, ein Ereignis an die Kopie eines Puffers zuweisen. Also, sagen wir, Sie die Zeit messen wollen es braucht, um Daten an die GPU kopieren Sie die GPU_Profiling Optionen verwenden, werden Sie in der Lage sein, so mit dem ersten Ansatz zu tun, aber nicht mit dem zweiten.

Der zweite Ansatz ist kompakter, leichter zu lesen und erfordert weniger Zeilen Code.

Ein großer Unterschied, dass ich laufe in:

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);

Dieser erste Satz von Befehlen einen leeren Puffer erstellen und einen Befehl in der Befehlswarteschlange einreihen, den Puffer zu füllen.

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

Dieser zweite Befehl wird der Puffer erstellen und sofort füllen. Beachten Sie, dass es in diesem Argument Liste keine Befehlswarteschlange ist, so dass er den Inhalt der Eingangsdaten verwendet, wie es jetzt ist.

Wenn Sie bereits laufen CL-Code und Ihr Quellenzeiger ist abhängig von einem frühen Befehl in der Befehlswarteschlange abgeschlossen (beispielsweise eine Warteschlange eingereiht einen vorherigen Ausgangspuffer gelesen), mögen Sie auf jeden Fall die erste Methode verwenden. Wenn Sie versuchen, den Puffer in einem einzigen Befehl zu erstellen und füllen, werden Sie mit einer Race-Bedingung am Ende, in dem der Pufferinhalt nicht richtig auf dem Abschluss des Stand der Pufferlese warten wird.

Nun, der Hauptunterschied zwischen diesen beiden ist, dass der erste Speicher zuordnet auf dem Gerät und kopiert dann Daten zu diesem Speicher. Die zweite nur zuordnet.

Oder meinten Sie clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,sizeof(float) * DATA_SIZE, inputdata, NULL);?

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top