有什么方法可以阻止OpenCL内核的执行吗

Is there any way to stop OpenCL kernel from execution?

本文关键字:内核 OpenCL 执行 什么 方法      更新时间:2023-10-16

有什么方法可以阻止OpenCL内核的执行吗?例如,我启动内核,进行一些计算,然后在满足某些条件时停止它,否则,我会等待它完成:

clEnqueueNDRange(queue, ...); // start kernel function
// do other stuff...
// ...
if (some condition met) {
    stopKernel();
} else { 
    clFinish(queue);
}

感谢您的帮助

否。一旦您将内核排入队列,它就会运行到完成。

实现类似上面的东西的一种方法是这样做:

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. 创建两个内核,一个用来完成工作,另一个用来停止执行。每个内核都可以访问一个共享的全局缓冲区
  3. 将第一个内核加载到队列1中
  4. 当您想停止执行时,将第二个内核加载到队列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访问它们,以降低在循环中从global读取的成本。不利的一面是,您的状态将是不确定的:如果没有更多的变量来计算执行等,您将不知道有多少工作项以及哪些工作项已经执行。

内核:

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;
}

一种方法是分块完成工作负载,因此如果您有一个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中实现加载条。