我有以下 OpenCL 代码,使用 C++ Wrapper 和英特尔的 OpenCL 工具包:
#include <Eigen/StdVector>
...
typedef Sample_t float
typedef std::vector<Sample_t, Eigen::aligned_allocator<Sample_t> > SampleArray;
...
SampleArray data(ns * nt);
...
mdata = cl::Buffer(context, CL_MEM_READ_ONLY, sizeof(Sample_t) * data.size());
queue.enqueueWriteBuffer(mdata, CL_FALSE, 0, sizeof(Sample_t) * data.size(), &data[0]);
当使用 -O3、march=native 和 mtune=native 标志编译时,它会导致来自 TBB 代码的以下段错误:
__memcpy_sse2_unaligned() at memcpy-sse2-unaligned.S:116 0x7ffff6e64ba4
没有任何优化,程序运行良好。
我将问题追溯到 queue.enqueueWriteBuffer 调用,没有它我没有任何问题。
我试图注释掉修改变量“数据”的部分代码,以防我访问无效的内存位置,但问题仍然存在。
如果我从 std::vector 中删除 aligned_allocator,没有优化的构建也会开始中断。
我总共有 70MB 试图存储在此缓冲区中,远小于 CL_DEVICE_MAX_MEM_ALLOC_SIZE 报告的 3.8GB。但是如果我减小数组的大小,问题就会停止。我在后面的案例中尝试的大小是 5。
我还决定打印 vector 分配的地址,它是 0x7f21b797f010,所以它至少对齐到 16 个字节。
编辑:关于多线程,数组的创建以及 OpenCL 操作发生在同一个方法中,并且发生在主线程中。命令队列不是用异步标志创建的,缓冲区写入后有一个 flush() 操作。
可能是什么问题?
谢谢
最佳答案
正如在评论中的对话中确认的那样,这里的问题是 enqueueWriteBuffer()
操作是非阻塞的(CL_FALSE
作为阻塞 参数)并且源缓冲区(SampleArray
vector )在底层复制操作保证完成之前超出范围。
至少有 4 种可能的解决方案:
- 使用
enqueueWriteBuffer()
的阻塞形式。如文档所示,在这种情况下函数返回后将不会访问源缓冲区。 - 捕获返回的事件并在
SampleArray()
超出范围之前调用clWaitForEvents()
或调用clFinish()
。只有当您的程序在此期间做任何实质性的事情时,这才真正优于阻塞变体。 - 将源数据保存足够长的时间。
- 不要使用
enqueueWriteBuffer()
的复制形式:创建一个带有 NULL 源的缓冲区,将其映射到应用程序的内存空间,将数据写入其中,然后取消映射。这有可能避免完全复制,至少在集成 GPU/APU 上是这样)
这些大致按照并行度/效率的递增顺序排列。
关于c++ - OpenCL的enqueueWriteBuffer导致__memcpy_sse2_unaligned segmentation fault,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46615388/