【问题标题】:Why can't I copy data in a struct to an openCL cl_mem buffer correctly?为什么我不能正确地将结构中的数据复制到 openCL cl_mem 缓冲区?
【发布时间】:2011-10-10 21:33:55
【问题描述】:

好的,所以我已将其隔离为一个非常具体的问题。

我的印象是您可以在数组缓冲区中传递 OpenCL 任何类型的数据;整数、字符、您自己的自定义结构,只要它们只是数据并且不包含指向 GPU 无法检索的堆对象的指针。

现在,我已经尝试过了,我认为它适用于大量整数数组,但不适用于我的结构数组。具体来说,

cl_mem log_buffer = clCreateBuffer(context, CL_MEM_READ_WRITE, 
  num_elements * sizeof(int), NULL, NULL);

int* error_codes_in = (int*)malloc(num_elements * sizeof(int));

for (i = 0; i < num_elements; i++) {
  error_codes_in[i] = i;
}

error = clEnqueueWriteBuffer(command_queue, log_buffer, CL_TRUE,
  0, num_elements * sizeof(int), error_codes_in, 0, NULL, NULL);

这很好用,我在 GPU 上获得了一组数字,并且可以并行地成功操作它们。

但是,当我使用自己的自定义结构时:

typedef struct {
  float position[2];
  float velocity[2];
  float radius;
  float resultant_force[2];
} ocl_element_2d_t;

(也在内核中定义,as)

const char* kernel_string = 
  "typedef struct { float position[2]; float velocity[2]; float radius; float resultant_force[2]; } ocl_element_2d_t;"...

我使用相同/非常相似的代码写入我的结构数组的 GPU 版本:

cl_mem gpu_buffer = clCreateBuffer(context, CL_MEM_READ_WRITE,
  num_elements * sizeof(ocl_element_2d_t), NULL, NULL);

error = clEnqueueWriteBuffer(command_queue, (cl_mem)gpu_buffer, CL_TRUE,
  0, num_elements * sizeof(ocl_element_2d_t), host_buffer, 0, NULL, NULL);

我在 GPU 中得到空白值,并且偶尔为结构内的所有浮点值生成垃圾(350 中的三个或四个值)。两个返回值都是CL_SUCCESS

关于我哪里出错了有什么建议吗?我唯一的想法是 GPU 编译器在内存中生成了一个具有不同间隙的结构,并且由于复制方法忽略了项目的内部结构并只是复制了一个连续的 RAM 块,因此最终会出现不匹配和可能的异相项目。我的操作系统是否可能是 i7(四核)上的 64 位(OS X Lion),而我的 GPU 运行的是 32 位,这就是问题所在?它是 ATI Radeon HD 5750,不支持双精度,并声称拥有 128 位总线(可能相关,也可能不相关,我不知道这东西的确切含义。)

有没有正确的方法来做到这一点?对于结构中的不同属性,我是否必须使用所有 FORTRAN 并拥有 7 个不同的数组,每个数组都有自己的内核参数?

【问题讨论】:

  • 我看不到你实际上在哪里传递你的结构。你传入大小,否则它不会被使用。
  • @0A0D 抱歉,这些只是 sn-ps。我将缓冲区添加为内核参数并成功执行内核;我知道那部分正在工作,因为我可以得到整数。如果您愿意,我可以发布更多代码,但是帖子已经变得很长了...编辑:哦,您的意思是主机数据不是吗?这是最后一个 sn-p 中 clEnqueueWriteBufferhost_buffer 参数。
  • 你应该发布相关的代码来证明你的问题。
  • 失败的操作是将结构数组复制到 GPU 内存空间的代码 - 已经提供了所有设置以及库调用本身。我不相信任何其他代码是相关的。
  • 这就是我不明白的......它在哪里将结构复制到主机缓冲区?

标签: c opencl


【解决方案1】:

感谢@0A0D 怀疑我的选择性代码示例。问题确实在于我未能正确初始化结构

我的借口只是我习惯使用结构指针,而不是结构,所以写作

ocl_element_2d_t element = host_buffer[i];
element.position[0] = 1.2;
element.position[1] = 5.7;

是向对象添加属性的标准方法。快速搜索了结构体后,我发现了一个非常基础的 C 教程,http://www.asic-world.com/scripting/structs_c.html 指出

struct_instance = other_struct_instance;

执行深拷贝,而不是参考拷贝。

因此,当我测试 local 结构变量的输出时,我期望的值在那里,但仍然离host_buffer 中的数组不远。

这里大概有两个教训:

  1. 确保在询问 StackOverflow 问题时发布所有相关代码 - 包括所有初始化 - 以便考虑所有可能的问题。
  2. 在使用库时,尤其是像 OpenCL 这样复杂的库,不要以为它的开发人员会犯愚蠢的错误 - 它们几乎肯定是你自己的!

【讨论】:

  • 在将结构传递给我的内核时,我也遇到了一个非常奇怪的问题。到目前为止,我没有任何问题。现在我在返回主机数组中得到了奇怪的值。为了进行测试,我实际上只是使用了一个测试内核,它接受结构并将结构中的某个值写入返回缓冲区。这不是传入的内容。我检查了主机端代码以确保正确实例化结构。我完全不知所措。
  • 我的错误是 C 初始化的一个基本位 - openCL 工作正常!我只能建议您多做一点rubber duck debugging,如果失败,请启动一个新问题,准确发布您如何初始化结构、调用 OpenCL 库、测试内核的内容等等。道歉!
【解决方案2】:

我不确定您的编译器如何对齐您的“浮动”结构,但您可以尝试使用 gcc:

#pragma pack(1)

使其对齐没有间隙。

要撤消此打包使用:

#pragma pack()

您也可以尝试重新排列成员,如下所示:

typedef struct {
  float position[2];
  float velocity[2];
  float resultant_force[2];
  float radius;
} ocl_element_2d_t;

【讨论】:

  • 感谢您的建议,不幸的是,这些技术都没有任何作用;分开或一起。
猜你喜欢
  • 1970-01-01
  • 2013-06-19
  • 1970-01-01
  • 2014-11-03
  • 2021-08-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多