Большое время выполнения OpenCL Kernel вызывает сбой
В настоящее время я создаю ray marcher, чтобы смотреть на такие вещи, как mandelbox и т. Д. Он прекрасно работает. Однако в моей нынешней программе каждый работник использует луч, проецируемый из глаза. Это означает, что на одного работника приходится большое количество казней. Поэтому, когда я смотрю на невероятно сложный объект или пытаюсь выполнить рендеринг с достаточно большой точностью, это приводит к сбою моих драйверов дисплея, потому что ядру потребовалось слишком много времени для выполнения на одном работнике. Я пытаюсь избежать изменения значений в моем реестре, чтобы увеличить время ожидания, так как я хочу, чтобы это приложение работало на нескольких компьютерах.
Есть ли способ исправить это? В данном случае выполнение каждого рабочего элемента полностью не зависит от соседних рабочих элементов. Я думал о подписке буфера на графический процессор, который будет хранить текущий прогресс на этом луче и выполнять только небольшое количество итераций. Затем я просто вызывал бы программу снова и снова, и результат, надеюсь, улучшился бы немного больше. Проблема в том, что я не уверен, как бороться с ветвящимися лучами (например, отражающими и преломляющими), если у меня нет максимального количества каждого из них, которое можно предвидеть.
У кого-нибудь есть указания на то, что я должен сделать, чтобы исправить эту проблему? Я настоящий приверженец OpenCL, и у меня уже давно есть эта проблема. Мне кажется, что я делаю что-то не так или неправильно использую OpenCL, в основном, потому что у моих отдельных рабочих элементов много логики, но я не знаю, как разделить задачу, поскольку это всего лишь последовательность шагов, проверок и корректировок.
1 ответ
Сбой, который вы испытываете, вызван сторожевым таймером HW nVIDIA. Кроме того, операционная система может также обнаружить GPU как не отвечающий и перезагрузить его (по крайней мере, Windows7 делает это).
Вы можете избежать этого многими способами:
- Улучшите / оптимизируйте код ядра, чтобы он занимал меньше времени
- Купить быстрее аппаратное обеспечение ($$$$)
- Отключить сторожевой таймер (но это не простая задача, и не все устройства имеют эту функцию)
- Уменьшайте объем работы, помещаемой в очередь на устройстве, каждый раз, запуская несколько маленьких ядер (ПРИМЕЧАНИЕ. Это делает небольшую нагрузку, связанную с запуском каждого маленького ядра)
Более простое и понятное решение - последнее. Но если вы можете, попробуйте первый тоже.
Например, вызов, подобный этому (1000x1000 = 1M рабочих элементов, глобальный размер):
clEnqueueNDRangeKernel(queue, kernel, 2, NDRange(0,0)/*Offset*/, NDRange(1000,1000)/*Global*/, ... );
Может быть разделен на множество небольших вызовов ((100x100)x(10x10) = 1M). Поскольку глобальный размер теперь в 100 раз меньше, сторожевой таймер не должен срабатывать:
for(int i=0; i<10; i++)
for(int j=0; j<10; j++)
clEnqueueNDRangeKernel(queue, kernel, 2, NDRange(i*100,j*100)/*Offset*/, NDRange(100,100)/*Global*/, ... );