在OpenCL结构中使用矢量数据类型会导致Visual Studio中的Watch问题

时间:2017-02-06 13:56:57

标签: visual-studio opencl

考虑以下OpenCL示例

typedef struct MyStruct
{
  float value;

  // Causes wrong memory alignment
  int2 position;
} MyStruct;


__kernel void foo()
{
   MyStruct structs[10];

   for (int i = 0; i < 10; i++)
   {
      int2 pos = { i, i };
      MyStruct newStruct = { i * i, pos };
      structs[i] = newStruct;
   }
}    

当我使用矢量数据类型(如OpenCL结构中的int2)时,在向数组添加项(结构)后,内存损坏。下一项的成员被奇怪的值覆盖(我假设内存填充)。

在下面的屏幕截图中,您可以在循环的第一次迭代后看到调试值。红色都是更改的值。将第一个struct项添加到数组中会导致更改第二个项的value成员。

Iteration 1

在第二次迭代中,第三项的值被设置为“未知”&#39;值。但是,第二项的位置值也是错误的。

Iteration 2

有人可以解释这种奇怪的行为吗?但是,当我用两个int成员替换 int2 成员时,一切都按预期工作。对我来说,它似乎是矢量数据类型的错误内存对齐。

修改

代码在Intel CPU上运行,安装了最新的Intel SDK。在CPU设备上运行OpenCL代码是通过设置断点来调试内核的唯一可能性。 IDE是带有OpenCL的英特尔插件的Visual Studio 2015 Update 3。

解决

在Visual Studio的Watch窗口中似乎是 bug 。在OpenCL内核中使用向量数据类型成员调试struct时,它显示错误的值。

2 个答案:

答案 0 :(得分:1)

我已经在我的GPU上验证了您的代码,并且没有问题。

你要做的事/检查:

1.确保安装了最新的OpenCL驱动程序和图形驱动程序。

2.确保这不是“观察”问题。将数据复制到CPU并检查。例如:

#!/usr/bin/env python

import numpy as np
import pyopencl as cl

a_np = np.zeros(10).astype(np.float32)
b_np = np.zeros(20).astype(np.int32)

ctx = cl.create_some_context()
queue = cl.CommandQueue(ctx)

mf = cl.mem_flags
a_g = cl.Buffer(ctx, mf.READ_WRITE | mf.USE_HOST_PTR, hostbuf=a_np)
b_g = cl.Buffer(ctx, mf.READ_WRITE | mf.USE_HOST_PTR, hostbuf=b_np)

prg = cl.Program(ctx, """
typedef struct MyStruct
{
  float value;

  // Causes wrong memory alignment
  int2 position;
} MyStruct;

__kernel void foo(
    __global float *a_g, __global int *b_g)
{
   MyStruct structs[10];

   for (int i = 0; i < 10; i++)
   {
      int pos = { i, i };
      MyStruct newStruct = { i * i, pos };
      structs[i] = newStruct;
   }


   for (int i = 0; i < 10; i++)
   {
      a_g[i] = structs[i].value;
      b_g[2*i] = structs[i].position.x;
      b_g[2*i+1] = structs[i].position.y;
   }
}
""").build()

prg.foo(queue, (1,1), (1,1), a_g, b_g)

cl.enqueue_copy(queue, a_np, a_g)
cl.enqueue_copy(queue, b_np, b_g)

print a_np
print b_np

输出:

[  0.   1.   4.   9.  16.  25.  36.  49.  64.  81.]
[0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9]

答案 1 :(得分:1)

必须是对齐问题。根据设备和主机的不同,它可能会也可能不会起作用,因此您需要确保主机和设备端的对齐明显兼容。

如果您可以观看结果,它已被复制到RAM。将结果复制到RAM时,应确保使用正确的对齐方式。 in2有8个字节对齐,而两个int有4个字节对齐。第一项(value)也是4个字节。

在opencl设备中,您可以自由地使用结构中的任何字段顺序,但如果您要在RAM上使用它,则需要在双方都具有兼容性。这种兼容性通常在结构中进行了一些简单的编辑。按对齐排序字段就是其中之一。例如:

  • 从最大到最小(最大的第一个)的对齐大小的排序。因为硬件使用特殊的内存操作优化来快速读取结构,这使得它在RAM上不可知。只有设备知道它,除非您明确订单字段。例如:

(结构)

int2 var0;  // biggest alignment (8)
float var1; // smallest alignment (4)

another example:  

int4 var0;
float4 var1;
int2 var2;
int2 var3;
int2 var4;
char var5;  // 57 bytes total
char dummy1; // to have struct size equal to power of 2.
char dummy2; // to have struct size equal to power of 2.
char dummy3; // to have struct size equal to power of 2.
char dummy4; // to have struct size equal to power of 2.
char dummy5; // to have struct size equal to power of 2.
char dummy6; // to have struct size equal to power of 2.
char dummy7; // to have struct size equal to power of 2.