Большое время выполнения 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*/, ... );
Другие вопросы по тегам