OpenCL 的 CPU 使用率意外
Unexpected CPU utilization with OpenCL
我编写了一个简单的 OpenCL 内核来计算 GPU 上两个图像的互相关。但是,当我使用 enqueueNDRangeKernel
执行内核时,一个内核的 CPU 使用率上升到 100%,但主机代码除了等待排队命令完成外什么都不做。这是 OpenCL 程序的正常行为吗?这是怎么回事?
OpenCL 内核(如果相关(:
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
像素,其中X
和Y
在编译时设置。我正在使用X = 2048
和Y = 2048
测试上述内核。
附加信息:我在 OpenCL 版本 1.2 的 Nvidia GPU 上运行内核。C++程序是使用 OpenCL C++ Wrapper API 编写的,并使用大黄蜂软件包中的 optirun 在 Debian 上执行。
根据要求,这里有一个最小的工作示例:
#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;
}
你没有说你如何调用enqueueNDRangeKernel - 这是关键位。据我了解,对于NVidia,呼叫是阻塞的(尽管我认为这不是标准的一部分。您可以通过让一个单独的线程调用 enqueueNDRangeKernel 并让该线程在其上阻塞,而您的其他线程继续,并且阻塞线程可以在完成时发出事件信号来解决此问题。
这里有一个关于它的讨论 - 它提出了一些关于并行发生对排队的多个调用的警告。
相关文章:
- 在C++中对T*类型执行std::move的意外行为
- 使用取消引用的指针的多态性会产生意外的结果.为什么?
- 处理除以零会导致<csignal>意外行为
- vscode下的Arduino代码出现意外编译错误
- 使用++运算符会导致意外的结果
- 套接字读取后,我在缓冲区中看到意外输入
- 更改.cpp程序的输入文件中数据的位置会意外更改输出
- 使用vscode调试时,GDB意外退出
- 编写一个函数以使用 n 百分比的 CPU 使用率
- 此测试()中发生了什么意外过程?为什么总是覆盖 ch[0 1 2..]?
- 尝试将字符串/字符转换为整数会产生意外结果
- 错误 C2760:语法错误:映射迭代器上意外的标记"标识符",预期的";"
- C++标头错误 C2238 意外标记";"
- C++中意外的多头值
- vector.size() 在比较中意外工作
- 使用 malloc() 时出现意外大小
- 多线程程序中出现意外的内存泄漏
- 为什么static_cast基础类型的枚举类int8_t获得意外值?
- 字符串比较中的意外输出
- OpenCL 的 CPU 使用率意外