2013-11-04 48 views
1

这完全让我感到困惑。两组逻辑上应该相同的代码集合只在GPU上崩溃,而在CPU上运行良好。下面是测试代码:部分封装OpenCL导致段错误,包含代码示例

#include <iostream> 
#include <CL/cl.hpp> 

class Device 
{ 
public: 
    cl::Platform platform_; 
    cl::Device device_; 
    cl::Context context_; 
    cl::CommandQueue queue_; 

    Device(void) : platform_() 
        , device_() 
        , context_() 
        , queue_() {} 

    Device(int32_t platform, int32_t device) : platform_() 
              , device_() 
              , context_() 
              , queue_() 
    { 
     std::vector<cl::Platform> platforms; 
     cl::Platform::get(&platforms); 
     platform_ = platforms[platform]; 

     std::vector<cl::Device> devices; 
     platform_.getDevices(CL_DEVICE_TYPE_GPU, &devices); 
     device_ = devices[device]; 

     cl_context_properties properties[3] = { 
      CL_CONTEXT_PLATFORM, 
      (cl_context_properties)(platform_)(), 
      0 
     }; 

     cl_int clErr = CL_SUCCESS; 
     context_ = cl::Context(device_, properties, NULL, NULL, &clErr); 
     queue_ = cl::CommandQueue(context_,device_,0,&clErr); 
    } 
}; 

int main() 
{ 
    Device device(0,0); 

    cl::Program::Sources source; 
    std::string src = 
    "__kernel void Pointless(uint total, __global uint *data)"\ 
    "{"\ 
    " uint perStream=total/get_global_size(0);"\ 
    " __global uint *dest=data+get_global_id(0)*perStream;"\ 
    " for(uint i=0;i<perStream;i++)"\ 
    "  dest[i] = 1;"\ 
    "}"; 

    source.push_back({src.c_str(),src.length()}); 

    cl_int clErr = CL_SUCCESS; 
    cl::Program program = cl::Program(device.context_,source,&clErr); 
    if (clErr != CL_SUCCESS) 
    { 
     std::cerr << "Failed to create program: " << clErr << std::endl; 
     return 1; 
    } 

    clErr = program.build({device.device_}); 
    if(clErr != CL_SUCCESS) 
    { 
     std::cerr << "Failed to build program: " << clErr << std::endl; 
     std::cerr << program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device.device_) << std::endl; 
     return 1; 
    } 

    uint32_t samples = 16*256; 
    cl::make_kernel<cl_uint,cl::Buffer> Pointless(cl::Kernel(program,"Pointless")); 
    cl::Buffer device_samples(device.context_,CL_MEM_READ_WRITE,sizeof(cl_uint)*samples); 
    Pointless(cl::EnqueueArgs(device.queue_, cl::NDRange(16)), samples, device_samples).wait(); 

    std::vector<cl_uint> host_samples(samples); 
    device.queue_.enqueueReadBuffer(device_samples,CL_TRUE,0,sizeof(cl_uint)*samples,host_samples.data()); 

    for (auto x: host_samples) 
     std::cout << x; 
    std::cout << std::endl; 

    return 0; 
} 

上面似乎失败:我得到enqueueReadBuffer段故障。更有趣的是,它只在GPU(英特尔P4000)上失效。 CPU(i3 3xxx)运行时没有问题(将CL_DEVICE_TYPE_GPU更改为CL_DEVICE_TYPE_CPU以在CPU上测试)。

下面的代码适用于两种设备类型。

#include <iostream> 
#include <CL/cl.hpp> 

int main() 
{ 
    std::vector<cl::Platform> platforms; 
    cl::Platform::get(&platforms); 
    cl::Platform platform = platforms[0]; 

    std::vector<cl::Device> devices; 
    platform.getDevices(CL_DEVICE_TYPE_GPU, &devices); 
    cl::Device device = devices[0]; 

    cl_context_properties properties[3] = { 
     CL_CONTEXT_PLATFORM, 
     (cl_context_properties)(platform)(), 
     0 
    }; 

    cl_int clErr = CL_SUCCESS; 
    cl::Context context(device, properties, NULL, NULL, &clErr); 

    cl::CommandQueue queue(context,device,0,&clErr); 

    cl::Program::Sources source; 
    std::string src = 
    "__kernel void Pointless(uint total, __global uint *data)"\ 
    "{"\ 
    " uint perStream=total/get_global_size(0);"\ 
    " __global uint *dest=data+get_global_id(0)*perStream;"\ 
    " for(uint i=0;i<perStream;i++)"\ 
    "  dest[i] = 1;"\ 
    "}"; 

    source.push_back({src.c_str(),src.length()}); 

    cl::Program program = cl::Program(context,source,&clErr); 

    clErr = program.build({device}); 
    if(clErr != CL_SUCCESS) 
    { 
     std::cerr << program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device) << std::endl; 
    } 

    uint32_t samples = 16*256; 
    cl::make_kernel<cl_uint,cl::Buffer> Pointless(cl::Kernel(program,"Pointless")); 
    cl::Buffer device_samples(context,CL_MEM_READ_WRITE,sizeof(cl_uint)*samples); 
    Pointless(cl::EnqueueArgs(queue, cl::NDRange(16)), samples, device_samples).wait(); 

    std::vector<cl_uint> host_samples(samples); 
    queue.enqueueReadBuffer(device_samples,CL_TRUE,0,sizeof(cl_uint)*samples,host_samples.data()); 

    for (auto x: host_samples) 
     std::cout << x; 
    std::cout << std::endl; 

    return 0; 
} 

显然我在这里错过了一些非常基本的东西。他们都使用英特尔ICD(我没有这个系统上的AMD设备)。

+0

你所有的opencl文件版本是否相互匹配? –

+0

@huseyin GPU和CPU可能有不同版本的ICD,但我不确定这是否重要:如果是ICD,GPU上面的两组代码都不会失败?目前,它只有第一组代码才会失败。 – bhimberg

+0

@huseyin两者都使用相同的DLL:IntelOpenCL64.dll,版本1.0.1.1003。 – bhimberg

回答

2

(刚开始张贴所以我尚未对此发表评论)

我采用了NVIDIA的实现(使用英特尔槽ICD)测试你的代码。 C++编译器是G ++ 4.7.3。您的两个示例都可以在GPU上正常工作,也可以在可用的Intel CPU上运行。

所以这个问题几乎肯定只在英特尔GPU的实施中受到限制。

0

因此,我可能偶然发现了cl.hpp包装中的一个错误。 cl::Context context_; context_ = cl::Context(...);未正确分配底层对象地址。但是,cl::Context context_ = cl::Context(...)cl::Context context_(...);都可以正常工作。

我在G ++ 4.8.1和MSVC 2010都进行了测试,结果都一样。也许,它可以很好地与CPU指向英特尔ICD中的错误。虽然Khronos Group关于cl::Context的文档声明它隐含地保留了一个关于应用程序的简短评论,该应用程序能够在封装程序不知道的情况下发布底层对象。

谢谢Sharpneli,DarkZeros。