Подтвердить что ты не робот

В чем разница между созданием объекта буфера с помощью clCreateBuffer + CL_MEM_COPY_HOST_PTR против clCreateBuffer + clEnqueueWriteBuffer?

Я видел обе версии в учебниках, но я не мог узнать, каковы их преимущества и недостатки. Какой из них правильный?

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

против.

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

Спасибо.

[Обновление]

Я добавил CL_MEM_COPY_HOST_PTR, во второй пример, чтобы сделать его правильным.

4b9b3361

Ответ 1

Я предполагаю, что inputdata не является NULL.

В этом случае второй подход не должен работать вообще, поскольку в спецификациях указано, что clCreateBuffer возвращает NULL и ошибку, если:

CL_INVALID_HOST_PTR, если host_ptr равно NULL, а CL_MEM_USE_HOST_PTR или CL_MEM_COPY_HOST_PTR установлены в флагах или если host_ptr не является NULL, но CL_MEM_COPY_HOST_PTR или CL_MEM_USE_HOST_PTR не установлены во флаги.

поэтому вы имеете в виду либо

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

или

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

Первый должен быть более или менее таким же, как и первый подход, который вы указали, в то время как второй не будет фактически копировать данные, но вместо этого используйте предоставленное место для хранения буфера (кэширование частей или всего этого в память устройства). Какой из этих двух вариантов лучше всего зависит от сценария использования.

Персоналий Я предпочитаю использовать двухэтапный подход, сначала назначая буфер, а затем заполняя его writeToBuffer, так как мне легче видеть, что происходит (конечно, один шаг может быть быстрее (или, может быть, нет, это просто думаю))

Ответ 2

Во время моей работы с OpenCL я нашел очень важное различие между

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

и

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

Для первого подхода OpenCL скопирует указатель хоста не напрямую на GPU. Сначала он будет выделять второй временный буфер на хосте, который может вызвать проблемы, если вы загружаете на GPU большой материал, такой как CT. В течение короткого времени необходимая память вдвое превышает размер CT. Кроме того, данные не копируются во время этой функции. Он копируется во время установки аргумента в функцию ядра, которая использует объект 3D-изображения.

Второй подход напрямую копирует данные на графический процессор. OpenCL не предусматривает дополнительных ассигнований. Я думаю, что это, вероятно, одно и то же для обычных объектов буфера.

Ответ 3

Одно существенное отличие, с которым я столкнулся:

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

Этот первый набор команд создаст пустой буфер и запустит команду в вашей командной очереди для заполнения буфера.

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

Эта вторая команда создаст буфер и заполнит его немедленно. Обратите внимание, что в этом списке аргументов нет очереди команд, поэтому она использует содержимое входных данных, как сейчас.

Если вы уже используете CL-код, а указатель исходного кода зависит от предыдущей команды в завершении очереди команд (например, оцифрованное чтение предыдущего выходного буфера), вы определенно хотите использовать 1-й метод. Если вы попытаетесь создать и заполнить буфер одной командой, вы получите условие гонки, в котором содержимое буфера не будет должным образом ждать завершения вашего предыдущего чтения буфера.

Ответ 4

Хорошим аспектом первого подхода является то, что "clEnqueueWriteBuffer" позволяет назначить событие копии буфера. Итак, скажем, вы хотите измерить время, необходимое для копирования данных на GPU с использованием параметров GPU_Profiling, вы сможете сделать это с помощью первого подхода, но не со вторым.

Второй подход более компактный, более легкий для чтения и требует меньше строк для кодирования.

Ответ 5

Ну, главное отличие этих двух заключается в том, что первый выделяет память на устройстве, а затем копирует данные в эту память. Второй выделяет.

Или вы имели в виду clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,sizeof(float) * DATA_SIZE, inputdata, NULL);?