OpenCL重用具有不同DEFINE(-D)的cl_kernel

时间:2018-08-08 23:25:28

标签: c++ oop opencl

我的目标是减少调用cl_kernel时的调用开销 我从创建名为 clfunctor

的仿函数类开始

该类由具有“内核源代码”,“主函数名称”和编译“ options”作为参数的构造函数组成       然后构造函数将调用 set_kernel_code(...)来编译和构建具有这些参数的代码。最终将获得' mykernel '作为' set_kernel_code '函数的输出

class clfunctor 
{
      // comile sourcecode to cl_kernel
      void set_kernel_code(const std::string& sourcecode, const std::string& 
                           program_name, const std::string& options="")
      { 
              char* kernel_source = new char[ sourcecode.size() + 1 ];
              std::copy( sourcecode.begin(), sourcecode.end(), kernel_source 
              );
              kernel_source[ sourcecode.size() ] = '\0'; // opencl need \0 to end kernel_code

              cl_program program;

              program = clCreateProgramWithSource( myclcontext, 1, (const char **)&kernel_source, NULL, &err);
              if( err != 0 ) echo_error( cl_error_string(err) ); // if error here.. call cl_init() ???

              //build program from opencl device
              clBuildProgram(program, 1, &device[iplatform][idevice], options.c_str(), NULL, NULL);
              if( err != 0 ) echo_error( cl_error_string(err) );

              // no have kernel
              mykernel = clCreateKernel( program, program_name.c_str(), &err );
              const size_t LOG_SIZ = 2040;


              clReleaseProgram( program );
              delete kernel_source;
       }





public:

cl_kernel           mykernel;
std::vector<size_t> local_nd;
std::vector<size_t> global_nd;



clfunctor(const std::string& sourcecode, const std::string& program_name, const std::string& options)
{
    set_kernel_code( sourcecode, program_name, options );
}




void operator()() const
{
    cl_int err;


    //-----------------------------------
    //        create GPU queue
    //----------------------------------
    cl_command_queue queue = clCreateCommandQueue( myclcontext, device[iplatform][idevice], 0, &err);
    if( err != 0 ) echo_error( cl_error_string(err) );



    cl_uint work_dim = local_nd.size(); // ND dimension ( N )
    err = clEnqueueNDRangeKernel( queue, kernel, work_dim, NULL, global_nd.data(), local_nd.data(), 0, NULL, NULL);
    if( err != 0 ) echo_error( cl_error_string(err) );
    clFinish( queue );




    clReleaseCommandQueue( queue );
}


virtual ~clfunctor()
{
    // relase kernel with object is destroyed
    clReleaseKernel( mykernel );
}

};

我有一个示例cl文件'nothing.cl'是

kernel void nothing()
{
    printf("[ echo ]: %d\n", MYID  );
}

之后,我通过创建该仿函数对象

clfunctor0 hello( file2code("nothing.cl"), "nothing", "-DMYID=100");
hello.local_nd  = {1,1,1};
hello.global_nd = {1,1,1};
hello();   // print 100


clfunctor0 hello2( file2code("nothing.cl"), "nothing", "-DMYID=123");
hello2.local_nd  = {1,1,1};
hello2.global_nd = {1,1,1};
hello2(); // print 123


hello();  // THIS IS WRONG I expect it to print 100 but it print 123

如上面的代码,您可以看到我创建了两个对象。一个是“ hello”,另一个是“ hello2”,两个对象都共享来自nothing.cl的相同代码,但是在DEFINE(-D)编译方面有所不同。 'hello'使用 -DMYID = 100 (MYID = 100)但hello2使用 -DMYID = 123 (MYID = 123)

我希望这些对象拥有不同的mykernel,因为编译选项不同。首先我叫 hello()我正确打印'100'

然后我调用 hello2(),它也会正确打印'123'

但是,当我再次调用hello()而不是打印'100'时 它从hello2打印参数是123

如何仅使用-D(DEFINE)编译参数来使每个对象的内核不同。或者我对opencl内核做错了或误解了。

1 个答案:

答案 0 :(得分:1)

恐怕会发生缓存。编译器生成的二进制文件内部包含123,可以简单地重用。 创建带有随机名称的即时cl文件,并且u始终具有正确的值。或者最好不要使用标志,而只是将参数传递给内核