如何避免在OpenCL中重新读取

如何避免在OpenCL中重新读取,opencl,Opencl,我正在用OpenCL实现一个算法。我将在C++中多次循环,每次调用一个相同的OpenCL内核。内核将生成下一次迭代的输入数据以及这些数据的数量。目前,我在每个循环中读回这个数字有两种用法: 我使用这个数字来决定下一个循环需要多少工作项;及 我使用这个数字来决定何时退出循环(当数字为0时) 我发现阅读占据了循环的大部分时间。有什么办法可以避免吗 一般来说,如果您需要重复调用内核,并且退出条件取决于内核生成的结果(不是固定数量的循环),那么如何才能有效地执行此操作?是否有类似OpenGL中的遮挡查询

我正在用OpenCL实现一个算法。我将在C++中多次循环,每次调用一个相同的OpenCL内核。内核将生成下一次迭代的输入数据以及这些数据的数量。目前,我在每个循环中读回这个数字有两种用法:

  • 我使用这个数字来决定下一个循环需要多少工作项;及
  • 我使用这个数字来决定何时退出循环(当数字为0时)
  • 我发现阅读占据了循环的大部分时间。有什么办法可以避免吗


    一般来说,如果您需要重复调用内核,并且退出条件取决于内核生成的结果(不是固定数量的循环),那么如何才能有效地执行此操作?是否有类似OpenGL中的遮挡查询的内容,您可以只执行一些查询,而不必从GPU读取?

    您在这里有两个选项:

  • 如果可能,您可以简单地将循环和条件移动到内核中?使用一个方案,其中额外的工作项根据当前迭代的输入不起任何作用
  • 如果1。这是不可能的,我建议您将“决策”内核生成的数据存储在一个缓冲区中,并使用该缓冲区“指导”其他内核

  • 这两个选项都允许您跳过回读。

    从GPU内核回读一个数字总是需要10到1000微秒或更长时间

    如果控制数总是在减少,您可以保留在全局内存中,并根据全局id对其进行测试,并确定内核在每次迭代中是否工作。使用全局内存屏障同步所有线程

    kernel void x(global int * the_number, constant int max_iterations, ... )
    {
        int index = get_global_id(0);
        int count = 0;    // stops an infinite loop
    
         while( index  < the_number[0] && count < max_iterations )
         {
          count++;
          // loop code follows
    
          ....
    
          // Use one thread decide what to do next 
          if ( index  == 0 )
          {
              the_number[0] = ... next value
          }
    
          barrier( CLK_GLOBAL_MEM_FENCE ); //  Barrier to sync threads
        }
    }
    
    kernelvoid x(全局整数*整数,常量整数最大迭代次数,…)
    {
    int index=get_global_id(0);
    int count=0;//停止无限循环
    而(索引<数量[0]&计数<最大迭代次数)
    {
    计数++;
    //循环代码如下
    ....
    //使用一个线程决定下一步要做什么
    如果(索引==0)
    {
    _编号[0]=…下一个值
    }
    barrier(CLK_GLOBAL_MEM_FENCE);//同步线程的屏障
    }
    }
    
    我刚刚完成一些研究,我们必须解决这个确切的问题

    我们发现了两件事:

  • 使用两个(或更多)缓冲区!进行内核的第一次迭代 对b1中的数据进行操作,然后对b2中的下一个数据进行操作,然后再次对b1进行操作。在里面 在每次内核调用之间,读回另一个缓冲区的结果 并检查是否该停止迭代。当内核花费的时间超过读取时间时,效果最佳。使用分析工具确保您没有等待读取(如果是,请增加缓冲区的数量)

  • 过射!向每个内核添加一个完成检查,并调用它 在将数据复制回之前进行几次(100秒)。如果你的内核是 低成本,这可以很好地工作


  • 如果我启动了许多工作项(比如1000个),而其中大多数(比如990个)什么都不做。例如,他们测试一个条件,如果条件为假,则立即返回。它的速度是否与仅仅启动10个工作项的速度相似?还是会慢得多?我不明白为什么那会是件坏事。只要没有回读,它应该只需要工作组中运行时间最长的工作项,对吗?我真正的程序更复杂。我在每个循环中调用许多内核。我认为不可能将整个循环的工作实现到内核中(我明白了,我会修改我的答案。你原来的问题让我觉得很简单:)