OpenCL的enqueueWriteBuffer导致__memcpy_sse2_unaligned分段错误

时间:2017-10-07 00:02:26

标签: c++ segmentation-fault opencl memory-alignment

我有以下OpenCL代码,使用C ++ Wrapper和Intel的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 flag编译它时,它会导致以下来自TBB代码的分段错误:

  

__ memcpy_sse2_unaligned()在memcpy-sse2-unaligned.S:116 0x7ffff6e64ba4

没有任何优化,程序运行正常。

我将问题追溯到queue.enqueueWriteBuffer调用,没有它我没有任何问题。

我试图注释掉修改变量&#34; data&#34;的部分代码,以防我访问无效的内存位置,但问题仍然存在。

如果我从std :: vector中删除了aligned_allocator,那么没有优化的构建也会开始中断。

总共我有70MB,我试图存储在这个缓冲区中,远远低于CL_DEVICE_MAX_MEM_ALLOC_SIZE报告的3.8GB。但是,如果我减小数组的大小,问题就会停止。我在后面的案例中尝试过的大小为5。

我还决定打印矢量分配的地址,它是0x7f21b797f010,因此它至少对齐16个字节。

编辑:关于多线程,数组的创建以及OpenCL操作都在同一个方法和主线程中进行。命令队列不是用asynchonous标志创建的,并且在缓冲区写入后有一个flush()操作。

可能是什么问题?

谢谢

1 个答案:

答案 0 :(得分:2)

正如评论中的对话中所确认的那样,问题是enqueueWriteBuffer()操作是非阻塞的(CL_FALSE作为阻止参数传递)并且源是缓冲区(SampleArray vector)在保证基础复制操作完成之前超出范围。

至少有4种可能的解决方案:

  1. 使用enqueueWriteBuffer()的屏蔽形式。如文档所示,在该情况下函数返回后将不会访问源缓冲区。
  2. 捕获返回的事件并在clWaitForEvents()超出范围之前致电clFinish()或致电SampleArray()。如果您的程序在过渡期间做了大量工作,那么这只能阻止变种。
  3. 保留源数据足够长的时间。
  4. 不要使用enqueueWriteBuffer()的复制形式:创建一个带有NULL源的缓冲区,将其映射到应用程序的内存空间,将数据写入其中,然后取消映射。这可能完全避免复制,至少在集成的GPU / APU上)
  5. 这些大致是并行/效率的递增顺序。