有没有办法阻止OpenCL内核执行? 例如,我启动内核,进行一些计算,然后在满足某些条件时停止它,否则,我等到它完成:
clEnqueueNDRange(queue, ...); // start kernel function
// do other stuff...
// ...
if (some condition met) {
stopKernel();
} else {
clFinish(queue);
}
感谢您的帮助
答案 0 :(得分:7)
没有。一旦你将你的内核排队,它就会运行完成。
完成上述某事的一种方法是:
while ( data_left_to_process ) {
clEnqueueNDRangeKernel( ..., NDRange for a portion of the data, ... )
// other work
if (condition) {
break;
}
// adjust NDRange for next execution to processes the next part of your data
}
clFinish(queue);
这使您可以避免处理所有数据,显而易见的是,您现在以较小的块提交工作,这可能会对性能产生影响。
答案 1 :(得分:2)
可能。
或者,您可以使用无序队列并将第二个内核加载到同一个命令队列中以暂停执行。你必须要小心一点(必要时使用clFinish / clFlush),但这是一种更自然的方法。
一些伪代码(用于多个队列):
clEnqueueNDRange(queue1, kernel1, ...); //start work kernel
// do other stuff
// ...
if (condition)
clEnqueueNDRange(queue2, kernel2, ...); //stop work kernel
clFinish(queue1);
clFinish(queue2); // entirely unnecessary if using in-order queues
使用int或float的缓冲区作为停止变量,并通过内核中的global_id访问它们,以降低循环中从全局读取的成本。缺点是你的状态将是不确定的:没有进一步的变量来计算执行等,你将不知道有多少工作项和哪些已被执行。
内核:
void kernel1( ... ,global int * g_stop)
{
int index_from_ids = ...;
while (g_stop[index_from_ids] == 0) // or 'if' for single pass execution
{
// do work here
}
}
void kernel2( ... ,global int * g_stop)
{
int index_from_ids = ...;
g_stop[index_from_ids] = 1;
}
答案 2 :(得分:0)
一种方法是分块完成工作负载,例如,如果您有一个 10000X10000 的全局工作器,如下所示:
clEnqueueNDRangeKernel(queue, kernel, 2, NDRange(0,0), NDRange(10000,10000),... );
您可以分块进行,如下所示:
for(int i=0; i<100; i++)
for(int j=0; j<100; j++)
if(condition)
clEnqueueNDRangeKernel(queue, kernel, 2, NDRange(i*100,j*100),DRange(100,100),... );
在某些情况下,您可能需要在循环中调用 queuefinish。这还有其他优势,例如不会在硬件中超时以终止耗时过长的应用程序,例如 nvidia 的看门狗定时器,并且如果需要,它还允许您在 GUI 中实现加载栏。