Измерение и минимизация накладных расходов OpenCL

У меня есть программа pyopencl, которая делает длинный расчет (~3-5 часов за цикл). У меня есть несколько ядер, запускаемых одно за другим в цикле. Итак, у меня есть что-то вроде этого:

prepare_kernels_and_data()

for i in range(big_number): # in my case big_number is 400000
  load_data_to_device(i)    # ~0.0002s
  run_kernel1(i)            # ~0.0086s
  run_kernel2(i)            # ~0.00028s
  store_data_from_device(i) # ~0.0002s

Я измерил время и получил следующее:

  1. Системное время составляет 4:30 часа (измеряется Linux time команда)
  2. Чистое время на основе событий opencl составляет 3:30 часа (загрузка + вычисление + сохранение)

Я хотел бы знать:

  1. Насколько велика минимальная нагрузка на программу OpenCL? В моем случае это как 35%
  2. Должен ли я доверять событиям на основе событий?
  3. Добавляет ли включение профилирования значительное время на выполнение программы?

Я знаю, что накладные расходы зависят от программы, и я знаю, что Python не так быстр, как чистый C или CPP. Но я считаю, что когда я перенесу все свои тяжелые вычисления в ядра OpenCL, я могу потерять не более 5-7%. Пожалуйста, поправьте меня, если я ошибаюсь.

PS AMD OpenCL, AMD GPU

1 ответ

Решение

Как вы измеряете время OCL? Используя только что-то вроде:

my_event.profile.end - my_event.profile.start

Если это так, вы можете также взять другую метрику:

my_event.profile.start - my_event.profile.queued

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

Команды, представленные в виде пакетного отчета, имеют одинаковое время начала и одинаковое время окончания.

Если я хорошо помню, NVIDIA передает команды. Но в любом случае вы можете использовать это, чтобы уменьшить накладные расходы. Например, вместо:

Cl_prog.kernel1(…).wait()
Cl_prog.kernel2(…).wait()

Вы могли бы сделать что-то вроде:

Event1 =   Cl_prog.kernel1(…)
Event2 = Cl_prog.kernel2(…)
Event1.wait()
Event2.wait()

И так далее.
Но я отвлекся; Теперь, чтобы ответить конкретно на ваши вопросы, вот некоторые материалы, взятые из того же раздела, который я упомянул выше (это от AMD, но я думаю, что для NVIDIA это должно быть примерно так же)

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

  2. Смотри цитату выше

  3. "Включение профилирования в очереди команд добавляет от 10 до 40 мкс служебной информации ко всем вызовам clEnqueue".
Другие вопросы по тегам