OpenCL 的部分封装导致分段错误,包括代码示例
Partial encapsulation of OpenCL causing segmentation fault, code sample included
这完全让我感到困惑。两组代码在逻辑上应该是相同的,一组仅在 GPU 上崩溃,而两者都在 CPU 上运行良好。以下是测试代码:
#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 设备)。
(刚开始发帖,所以我还不能发表评论)
我使用 Nvidia 实现(通过英特尔 ICD 使用)测试了您的代码。C++编译器是G++ 4.7.3。您的两个示例在 GPU 上都完美运行,在可用的英特尔 CPU 上也是如此。
因此,几乎可以肯定,这个问题仅限于英特尔 GPU 实施。
可能偶然发现了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。
- VS Code C++:不准确的系统包括路径错误(wchar.h,boost/lambda/lambda.hpp)
- 链接错误,包括我创建的相同头文件 - C++
- 标头,包括在 Swift 项目中使用C++文件时的错误
- cpp 在主源文件中包括.cpp文件导致错误"duplicate symbol"
- C++ ZBar cmake 错误"找不到文件"时包括
- 错误:不支持 GLSL 3.30.支持的版本包括:1.10、1.20、1.30、1.00 ES、3.00 ES、3.10
- 强制链接器失败并出现多重定义错误,即使包括 --whole-archive
- 包括DLL中的OpenVDB;将错误与Visual Studio 2015联系起来
- VC 链接器错误使用Dllimport/DLLEXPORT宏将标题包括在多个项目中
- C 包括文件会导致未知错误
- 将框架包括在Xcode C 项目中 - 链接器错误
- 致命错误包括现有标头
- Visual Studio 14.0 和 Windows 工具包中的错误包括文件夹
- C++ 3 路标头中的多个定义错误包括
- 使用 python 编译引脚工具的错误包括,得到错误 C2872:'UINT32':不明确的符号
- 错误包括gtkmm.h
- OpenCV 3.0错误包括ocl.hp
- 得到LNK2005和KNK1169错误-包括一个类在另一个
- Visual Studio 2010 - C++和DirectX文件中的链接错误包括问题
- c++编译错误包括X11/X.h X11/Xlib.h