【问题标题】:OpenCL struct values correct on CPU but not on GPUOpenCL 结构值在 CPU 上正确,但在 GPU 上不正确
【发布时间】:2014-08-18 12:07:26
【问题描述】:

我在一个文件中确实有一个结构,它包含在主机代码和内核中

typedef struct {
    float x, y, z,
          dir_x, dir_y, dir_z;
    int     radius;
} WorklistStruct;

我正在我的 c++ 主机代码中构建这个结构,并通过缓冲区将它传递给 OpenCL 内核。

如果我选择一个 CPU 设备进行计算,我会得到以下结果:

 printf ( "item:[%f,%f,%f][%f,%f,%f]%d,%d\n", item.x, item.y, item.z, item.dir_x, item.dir_y,
                 item.dir_z , item.radius ,sizeof(float));

主持人:

item:[20.169043,7.000000,34.933712][0.000000,-3.000000,0.000000]1,4

设备(CPU):

item:[20.169043,7.000000,34.933712][0.000000,-3.000000,0.000000]1,4

如果我选择 GPU 设备 (AMD) 进行计算,就会发生奇怪的事情:

主持人:

item:[58.406261,57.786015,58.137501][2.000000,2.000000,2.000000]2,4

设备(GPU):

item:[58.406261,2.000000,0.000000][0.000000,0.000000,0.000000]0,0

值得注意的是 sizeof(float) 在 gpu 上是垃圾。

我认为浮动在不同设备上的布局存在问题。

注意:该结构包含在此类型的结构数组中,该数组中的每个结构在 GPU 上都是垃圾

任何人都知道为什么会出现这种情况以及我如何预测这种情况?

编辑我在 and 处添加了一个 %d 并将其替换为 1,结果为:1065353216

编辑:这里有两个我正在使用的结构

typedef struct {
      float x, y, z,//base coordinates 
      dir_x, dir_y, dir_z;//directio
      int     radius;//radius
} WorklistStruct;

typedef struct {
    float base_x, base_y, base_z; //base point 
    float radius;//radius 
    float dir_x, dir_y, dir_z; //initial direction
} ReturnStruct;

我测试了一些其他的东西,它看起来像是 printf 的问题。价值观似乎是正确的。我将参数传递给返回结构,读取它们并且这些值是正确的。

我不想发布所有相关代码,这将是几百行。 如果没有人知道我会压缩一下。

啊,对于打印,我使用的是#pragma OPENCL EXTENSION cl_amd_printf : enable

编辑: 看起来真的像 printf 的问题。我只是不再使用它了。

【问题讨论】:

  • %d 不是打印sizeof 结果的合适格式。对于符合 C99 的编译器,它应该是 %zu
  • 从混合中移除缓冲传输;只需填写结构值并尝试首先让 printf 工作。为了证明 sizeof(float) 是 4,在 else 之前和之后添加一个它的条件 == 4 和一个 printf 以查看采用哪条路径。
  • 你能展示一下包含在内核和主机端代码以及内存对象创建和读/写代码中的标头吗?

标签: c++ c floating-point opencl gpu


【解决方案1】:

有一个简单的方法可以检查发生了什么:

1 - 创建主机端数据并对其进行初始化:

int num_points = 128;

std::vector<WorklistStruct> works(num_points);
std::vector<ReturnStruct> returns(num_points);

for(WorklistStruct &work : works){
    work = InitializeItSomehow();
    std::cout << work.x << " " << work.y << " " << work.z << std::endl;
    std::cout << work.radius << std::endl;
}

// Same stuff with returns
...

2 - 使用 COPY_HOST_PTR 标志创建设备端缓冲区,对其进行映射并检查数据一致性:

cl::Buffer dev_works(..., COPY_HOST_PTR, (void*)&works[0]);
cl::Buffer dev_rets(..., COPY_HOST_PTR, (void*)&returns[0]);

// Then map it to check data
WorklistStruct *mapped_works = dev_works.Map(...);
ReturnStruct *mapped_rets = dev_rets.Map(...);

// Output values & unmap buffers
...

3 - 像以前一样检查设备端的数据一致性。

另外,请确保内核和主机端代码都包含的代码(可能是 - 标头)是纯 OpenCL C(AMD 编译器有时会“吞下”一些错误)并且您已导入包含目录搜索,在构建 OpenCL 内核时(clBuildProgramm 阶段的“-I”标志)

已编辑: 在每一步,请收集返回码(或捕获异常)。除此之外,clBuildProgramm 阶段的“-Werror”标志也很有帮助。

【讨论】:

  • 但这正是他已经在做的事情,不是吗? (至少我们认为他已经在做的事情)。我们需要知道结构定义(主机/设备)以及他如何使用数据,以便查看过程中的任何错误。
  • 是的,你是对的 - 我们没有关于 TS 代码的确切信息,所以我建议进行这样的小测试。
  • 我将我正在使用的结构添加到问题中。我从主机和设备大小代码中的同一个文件中导入这些。明天我将发布我的数据到设备复制代码。
【解决方案2】:

看来我在编译时使用了错误的 OpenCL 头文件。如果我在英特尔平台(OpenCL 1.2)上尝试代码,一切都很好。但在我的 AMD 平台 (OpenCL 1.1) 上,我得到了奇怪的值。

我会尝试其他标题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-15
    • 1970-01-01
    相关资源
    最近更新 更多