我运行以下(简化)代码,该代码运行一个简化的内核几秒钟,然后检查结果。前400,000左右的结果是正确的,然后下一个都是零。内核应该将相同的值(4228)放入450万个元素的输出数组的每个元素中。看起来好像在某个地方,有些东西超时,或者没有同步,但我有点困惑,因为我:
结果如下:
user@pear:~/git/machinelearning/prototyping/build$ ./testcltimeout
out[442496] != 4228: 0
我期望发生的事情是:代码应该运行完成,没有错误。
上下文:运行于:
内核是:
kernel void test_read( const int one, const int two, global int *out) {
const int globalid = get_global_id(0);
int sum = 0;
int n = 0;
while( n < 100000 ) {
sum = (sum + one ) % 1357 * two;
n++;
}
out[globalid] = sum;
}
测试代码(我尽可能地简化了这个......)
#include <iostream>
#include <sstream>
#include <stdexcept>
using namespace std;
#include "CL/cl.hpp"
template<typename T>
std::string toString(T val ) {
std::ostringstream myostringstream;
myostringstream << val;
return myostringstream.str();
}
void checkError( cl_int error ) {
if (error != CL_SUCCESS) {
throw std::runtime_error( "Error: " + toString(error) );
}
}
int main( int argc, char *argv[] ) {
cl_int error;
cl_device_id *device_ids;
cl_uint num_platforms;
cl_uint num_devices;
cl_platform_id platform_id;
cl_device_id device;
cl_context context;
cl_command_queue queue;
cl_program program;
checkError( clGetPlatformIDs(1, &platform_id, &num_platforms) );
checkError( clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_GPU, 1, &device, &num_devices) );
device_ids = new cl_device_id[num_devices];
checkError( clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_GPU, num_devices, device_ids, &num_devices) );
device = device_ids[0];
context = clCreateContext(0, 1, &device, NULL, NULL, &error);
checkError(error);
queue = clCreateCommandQueue(context, device, 0, &error);
checkError(error);
string kernel_source = string( "kernel void test_read( const int one, const int two, global int *out) {\n" ) +
" const int globalid = get_global_id(0);\n" +
" int sum = 0;\n" +
" int n = 0;\n" +
" while( n < 100000 ) {\n" +
" sum = (sum + one ) % 1357 * two;\n" +
" n++;\n" +
" }\n" +
" out[globalid] = sum;\n" +
"}\n";
const char *source_char = kernel_source.c_str();
size_t src_size = strlen( source_char );
program = clCreateProgramWithSource(context, 1, &source_char, &src_size, &error);
checkError(error);
checkError( clBuildProgram(program, 1, &device, 0, NULL, NULL) );
cl_kernel kernel = clCreateKernel(program, "test_read", &error);
checkError(error);
const int N = 4500000;
int *out = new int[N];
if( out == 0 ) throw runtime_error("couldnt allocate array");
int c1 = 3;
int c2 = 7;
checkError( clSetKernelArg(kernel, 0, sizeof(int), &c1 ) );
checkError( clSetKernelArg(kernel, 1, sizeof(int), &c2 ) );
cl_mem outbuffer = clCreateBuffer(context, CL_MEM_WRITE_ONLY, sizeof(int) * N, 0, &error);
checkError(error);
checkError( clSetKernelArg(kernel, 2, sizeof(cl_mem), &outbuffer) );
size_t globalSize = N;
size_t workgroupsize = 512;
globalSize = ( ( globalSize + workgroupsize - 1 ) / workgroupsize ) * workgroupsize;
checkError( clEnqueueNDRangeKernel( queue, kernel, 1, NULL, &globalSize, &workgroupsize, 0, NULL, NULL) );
checkError( clFinish( queue ) );
checkError( clEnqueueReadBuffer( queue, outbuffer, CL_TRUE, 0, sizeof(int) * N, out, 0, NULL, NULL) );
checkError( clFinish( queue ) );
for( int i = 0; i < N; i++ ) {
if( out[i] != 4228 ) {
cout << "out[" << i << "] != 4228: " << out[i] << endl;
exit(-1);
}
}
return 0;
}
答案 0 :(得分:1)
你的内核似乎很长。我怀疑你是TDR(超时),Linux(Beignet)比Windows更默默地处理这个问题。因此,我有几个想法。
dmesg
是否有TDR消息。我没有使用过Beignet或Linux OpenCL实现,但Beignet documentation页面(在#34;已知问题&#34;下)表示您可以通过dmesg
进行检查。< / LI>
要检查GPU是否挂起,您可以执行dmesg并检查是否 它有以下消息:[17909.175965] [drm:i915_hangcheck_hung] ERROR Hangcheck计时器已过...如果是,则表示GPU挂起。通常,这意味着内核中存在错误,因为它表明了 OCL内核还没有完成大约6秒甚至更长时间。
文档继续说你可以禁用超时检查,如果你真的知道内核需要花费更长的时间才能完成,但警告说你冒着机器挂起的风险。
在Windows 上试用on Intel HD 4000 Graphics 。如果内核耗时超过几秒钟,它将超时并且驱动程序实际崩溃(但自动重启)。
尝试使用Intel OpenCL CPU实现的内核(或任何其他没有TRD限制的内核)。检查其运行的正确性和长度(10秒钟~10分钟?)。我不认为CPU实施会超时。