首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >OpenCL的意外CPU使用率

OpenCL的意外CPU使用率
EN

Stack Overflow用户
提问于 2018-01-30 23:51:56
回答 1查看 349关注 0票数 0

我已经写了一个简单的OpenCL内核来计算两幅图像在图形处理器上的互相关度。但是,当我使用enqueueNDRangeKernel执行内核时,一个内核的CPU使用率上升到100%,但是主机代码除了等待排队的命令完成之外,什么也不做。这是OpenCL程序的正常行为吗?那是怎么回事?

OpenCL内核(如果相关):

代码语言:javascript
复制
kernel void cross_correlation(global double *f,
                              global double *g,
                              global double *res) {
  // This work item will compute the cross-correlation value for pixel w
  const int2 w = (int2)(get_global_id(0), get_global_id(1));

  // Main loop
  int xy_index = 0;
  int xy_plus_w_index = w.x + w.y * X;

  double integral = 0;
  for ( int y = 0; y + w.y < Y; ++y ) {
    for ( int x = 0; x + w.x < X; ++x, ++xy_index, ++xy_plus_w_index ) {
      // xy_index is equal to x + y * X
      // xy_plus_w_index is equal to (x + w.x) + (y + w.y) * X
      integral += f[xy_index] * g[xy_plus_w_index];
    }

    xy_index += w.x;
    xy_plus_w_index += w.x;
  }

  res[w.x + w.y * X] = integral;
}

图像f, g, res的大小为X乘以Y像素,其中XY是在编译时设置的。我正在用X = 2048Y = 2048测试上面的内核。

附加信息:我在装有OpenCL 1.2版的Nvidia图形处理器上运行内核。C++程序是使用OpenCL C++包装器API编写的,并使用来自bumblebee包的optirun在Debian上执行。

按照要求,下面是一个最小的工作示例:

代码语言:javascript
复制
#include <CL/cl.hpp>

#include <sstream>
#include <fstream>

using namespace std;

int main ( int argc, char **argv ) {
  const int X = 2048;
  const int Y = 2048;

  // Create context
  cl::Context context ( CL_DEVICE_TYPE_GPU );

  // Read kernel from file
  ifstream kernel_file ( "cross_correlation.cl" );
  stringstream buffer;
  buffer << kernel_file.rdbuf ( );
  string kernel_code = buffer.str ( );

  // Build kernel
  cl::Program::Sources sources;
  sources.push_back ( { kernel_code.c_str ( ), kernel_code.length ( ) } );
  cl::Program program ( context, sources );
  program.build ( " -DX=2048 -DY=2048" );

  // Allocate buffer memory
  cl::Buffer fbuf ( context, CL_MEM_READ_WRITE, X * Y * sizeof(double) );
  cl::Buffer gbuf ( context, CL_MEM_READ_WRITE, X * Y * sizeof(double) );
  cl::Buffer resbuf ( context, CL_MEM_WRITE_ONLY, X * Y * sizeof(double) );

  // Create command queue
  cl::CommandQueue queue ( context );

  // Create kernel
  cl::Kernel kernel ( program, "cross_correlation" );

  kernel.setArg ( 0, fbuf );
  kernel.setArg ( 1, gbuf );
  kernel.setArg ( 2, resbuf );

  // Set input arguments
  double *f = new double[X*Y];
  double *g = new double[X*Y];

  for ( int i = 0; i < X * Y; i++ )
    f[i] = g[i] = 0.001 * i;

  queue.enqueueWriteBuffer ( fbuf, CL_TRUE, 0, X * Y * sizeof(double), f );
  queue.enqueueWriteBuffer ( gbuf, CL_TRUE, 0, X * Y * sizeof(double), g );

  // Execute kernel
  queue.enqueueNDRangeKernel ( kernel, cl::NullRange, cl::NDRange ( X, Y ), cl::NullRange, NULL, NULL );
  queue.finish ( );

  return 0;
}
EN

回答 1

Stack Overflow用户

发布于 2018-01-31 00:03:00

您没有说明如何调用enqueueNDRangeKernel -这是关键之处。据我所知,对于NVidia,调用是阻塞的(尽管我不认为它应该是标准的一部分)。你可以通过让一个单独的线程调用enqueueNDRangeKernel来解决这个问题,当你的其他线程继续时,让这个线程阻塞在它上面,阻塞线程可以在它完成时发出一个事件信号。

有一个关于here的讨论-它提出了一些关于并行发生对入队的多个调用的警告。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48525489

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档