c++ - OpenCL的enqueueWriteBuffer导致__memcpy_sse2_unaligned segmentation fault

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

我有以下 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 种可能的解决方案:

  1. 使用enqueueWriteBuffer() 的阻塞形式。如文档所示,在这种情况下函数返回后将不会访问源缓冲区。
  2. 捕获返回的事件并在 SampleArray() 超出范围之前调用 clWaitForEvents() 或调用 clFinish()。只有当您的程序在此期间做任何实质性的事情时,这才真正优于阻塞变体。
  3. 将源数据保存足够长的时间。
  4. 不要使用 enqueueWriteBuffer() 的复制形式:创建一个带有 NULL 源的缓冲区,将其映射到应用程序的内存空间,将数据写入其中,然后取消映射。这有可能避免完全复制,至少在集成 GPU/APU 上是这样)

这些大致按照并行度/效率的递增顺序排列。

关于c++ - OpenCL的enqueueWriteBuffer导致__memcpy_sse2_unaligned segmentation fault,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46615388/

相关文章:

c++ - 使用 avr-gcc : uint8_t vs. uint16_t 隐式转换为 float

c++ - 返回时指针的值是垃圾

c - 你如何在C中正确分配空间

TensorFlow 和 OpenCL

c++ - 在OpenCL中以编程方式选择最佳GPU的最佳方法是什么?

coding-style - 如何构建大型 OpenCL 内核?

c++ - sprintf 的内部工作

c++ - 复制构造函数优于移动构造函数?

c - Malloc、空闲和段错误

c++ - JNI 从 c 调用 java 得到段错误(核心转储)