OpenCL 2.x поддерживает динамический параллелизм, который позволяет 1 рабочему элементу запускать новые ядра.Если при каждом запуске ядра не требуется передача данных gpu-cpu, вы можете иметь 1 рабочий элемент для запуска 1000 ядер и ждать, пока каждое из них не завершится к этому рабочему элементу.Используйте события, чтобы все дочерние ядра работали за другим.
В OpenCL 1.2 вы могли бы использовать атомарность и цикл для выполнения синхронизации ядра "в полете потоков", но это не было бы быстрее, чем запуск нового ядраimo, и это не переносимый способ их синхронизации.
Если каждый запуск ядра стоит больше времени, чем каждый запуск ядра, то на GPU недостаточно работы.Вы можете просто сделать c = a + b на графическом процессоре, и это не будет достаточно быстро только из-за того, что для планирования ядра на конвейерах gpu требуется больше времени, чем для c = a + b.
Но вы все равно можете выполнить следующий подход, используя clEnqueueWaitForEvents
и очереди команд по порядку:
thread-0:
enqueue user event, not triggered
enqueue 1000 kernels, they don't start yet because of untriggered wait
thread-1:
nothing
следующий шаг:
thread-0:
enqueue new user event on a new command queue, not triggered
enqueue 1000 kernels on new command queue so they don't start yet
thread-1:
run the old command queue from last timestep by triggering the user event
, чтобы поставить в очередьи бег может быть «перекрыт» как минимум.Если вам нужно больше очереди для запуска коэффициента перекрытия,
thread-0 to thread-N-2:
enqueue new user event on a new command queue, not triggered
enqueue 1000 kernels on new command queue so they don't start yet
thread-N-1:
iterate all command queues
run currently selected command queue from last timestep by triggering the user event
теперь, когда у вас в N-1 раз быстрее постановка в очередь, запуск их будет только при накладных расходах планирования на стороне GPU.Если у вас много накладных расходов на планирование на GPU (1M рабочих элементов для 1M c = a + b calcs), вам следует выполнять больше работы на каждый рабочий элемент.
Может быть, лучше сделать запуск ядра в стиле производитель-потребитель, где 7 потоковсоздавать заполненные очереди команд, ожидающие запуска по своим собственным пользовательским событиям, и 8. потреблять их потоком, вызывая их.Это будет работать, даже если им нужно загрузить данные для загрузки в / из GPU.
Даже старые графические процессоры, такие как HD7870, поддерживают 32 + очереди команд (на каждый графический процессор) одновременно, так что вы можете масштабировать производительность очереди высокопроизводительными процессорами.
Если мост pci-e (высокая задержка у стояков?) Вызывает узкое место, то динамический параллелизм OpenCL2.x должен быть лучше, чем шаблон производитель-потребитель на стороне процессора.