Измерение и минимизация накладных расходов 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
Я измерил время и получил следующее:
- Системное время составляет 4:30 часа (измеряется Linux
time
команда) - Чистое время на основе событий opencl составляет 3:30 часа (загрузка + вычисление + сохранение)
Я хотел бы знать:
- Насколько велика минимальная нагрузка на программу OpenCL? В моем случае это как 35%
- Должен ли я доверять событиям на основе событий?
- Добавляет ли включение профилирования значительное время на выполнение программы?
Я знаю, что накладные расходы зависят от программы, и я знаю, что 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 это должно быть примерно так же)
"Для процессорных устройств время запуска ядра быстро (десятки мкс), но для дискретных устройств с графическим процессором оно может составлять несколько сотен мкс"
Смотри цитату выше
- "Включение профилирования в очереди команд добавляет от 10 до 40 мкс служебной информации ко всем вызовам clEnqueue".