Какова цель функции "clRetainKernel"? - PullRequest
0 голосов
/ 03 октября 2019

Невозможно использовать один и тот же объект ядра для параллельного выполнения двух экземпляров одного и того же ядра.

Для параллельного выполнения нескольких экземпляров одного и того же ядра необходимо создать несколько объектов ядра из одной и той же программы. объект и поставлен в очередь в различные очереди команд.

Даже если код хоста распараллелен, нет смысла использовать два потока ЦП, сохраняющих один и тот же объект ядра. Так какова цель API "clRetainKernel"?

1 Ответ

0 голосов
/ 03 октября 2019

Так, какова цель API "clRetainKernel"?

Из источника https://www.khronos.org/registry/OpenCL/specs/opencl-1.2.pdf

Страница 18:

Счетчик ссылок: Срок службы объекта OpenCL определяется его счетчиком ссылок - внутренним счетчиком количества ссылок на объект. Когда вы создаете объект в OpenCL, его счетчик ссылок устанавливается равным единице. Последующие обращения к соответствующему retainAPI (например, clRetainContext, clRetainCommandQueue) увеличивают счетчик ссылок. Вызовы к соответствующему releaseAPI (например, clReleaseContext, clReleaseCommandQueue) уменьшают счетчик ссылок. После того как счетчик ссылок достигнет нуля, ресурсы объекта освобождаются OpenCL.

Он увеличивает внутренние счетчики соответствующего объекта opencl и может использоваться вне некоторого блока RAII . Я не использовал его, потому что RAII уже было достаточно. Но если бы возникла проблема «совместного использования», это удержание помогло бы использовать его за пределами его охвата. Таким образом, каждый должен делать свою часть сохранения и освобождения, если он делится чем-то вне его области (особенно, если вместо этого используется C api). В привязках C ++, https://github.khronos.org/OpenCL-CLHPP/cl2_8hpp_source.html#l05668 вы можете видеть, что конструктор

explicit Kernel(const cl_kernel& kernel, bool retainObject = false) :  ...

становится владельцем вместо увеличения счетчика ссылок. (сохранить = ложь). Затем, после нескольких строк кода,

(с сохранением)

 2447         // We must retain things we obtain from the API to avoid releasing
 2448         // API-owned objects.
 2449         if (devices) {
 2450             devices->resize(ids.size());
 2451 
 2452             // Assign to param, constructing with retain behaviour
 2453             // to correctly capture each underlying CL object
 2454             for (size_type i = 0; i < ids.size(); i++) {
 2455                 (*devices)[i] = Device(ids[i], true); // true: retain
 2456             }
 2457         }

(без сохранения)

 6457             kernels->resize(value.size());
 6458 
 6459             // Assign to param, constructing with retain behaviour
 6460             // to correctly capture each underlying CL object
 6461             for (size_type i = 0; i < value.size(); i++) {
 6462                 // We do not need to retain because this kernel is being created 
 6463                 // by the runtime
 6464                 (*kernels)[i] = Kernel(value[i], false); // false: no retain
 6465             }
 6466         }

ясно говорит: «если вы его создаливам не нужно его сохранять ".

Если это вещь, принадлежащая API, она будет выпущена внутри нее, поэтому, если вам нужно ее использовать, сохраните. Если вы что-то создаете, вы просто создаете и отпускаете.

Невозможно использовать один и тот же объект ядра для параллельного выполнения двух экземпляров одного и того же ядра.

Нет, это возможно, если вы используете различное смещение при каждом запуске nd-диапазона.

cl_event evt;
clEnqueueWriteBuffer(queue,buffer,CL_FALSE,0,100,myCharArray.data(),0,NULL,&evt);

size_t global_work_size = 50;
clEnqueueNDRangeKernel(queue,kernel,1,NULL,&global_work_size,NULL,0, NULL, NULL);

size_t global_work_size_2 = 50;
size_t global_offset_2 = 50;
cl_event evt2;  clEnqueueNDRangeKernel(queue2,kernel,1,&global_offset_2,&global_work_size_2,NULL,1, &evt, &evt2);
clEnqueueReadBuffer(queue,buffer,CL_FALSE,0,100,myCharArray.data(),1,&evt2,NULL);

clFlush(queue);
clFlush(queue2);
clFinish(queue2);
clFinish(queue);

Убедитесь, что между очередями имеется синхронизация событий, чтобы можно было увидеть "последние биты"данные в ядре, но с другим смещением при выполнении.

Вторая очередь синхронизируется с первой командой копирования данных (параметр evt). После того, как данные скопированы, их событие сигнализирует о другой очереди (queue2), чтобы они могли теперь вычислять. Но в первой очереди синхронизация неявна, так что постановка в очередь вычислений сразу после постановки в очередь копии данных без события в порядке, потому что используемая очередь здесь в порядке очереди. После того, как queue2 завершает вычисления, он сообщает readBuffer (по evt2);

Это из одного примера GPU, для нескольких GPU вам также необходимо скопировать данные.

Даже если код хоста распараллелен, нет смысла использовать два потока ЦП

Если синхронизация выполняется с ожиданием опроса событийцикл, он полностью занимает свою нить. Если у вас есть несколько командных очередей с одинаковым циклом ожидания вращения, тогда эти два потока необходимы;Вы также можете опрашивать два события одно за другим в пределах одного и того же цикла, но для этого необходимо позаботиться об обработке событий в случае динамического изменения количества очередей команд. С опросом для каждого потока легче управлять масштабируемостью строк кода.

Чтобы параллельно выполнить несколько экземпляров одного и того же ядра, необходимо создать несколько объектов ядра

Если ядро ​​будет использоваться одновременно на нескольких графических процессорах или на одном и том же графическом процессоре, но с разными буферами, то должны быть разные объекты ядра. Потому что установка аргументов ядра не является операцией постановки в очередь. Он возвращается, когда это сделано, и это не должно быть сделано во время работы ядра, и вы не можете знать точное время запуска ядра без получения события после его завершения. Но вы можете добавить защелку перед выполнением ядра и сделать обратный вызов, чтобы установить аргументы вовремя. Это должно быть медленно, поэтому несколько объектов быстрее и проще.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...