考虑以下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成员。
在第二次迭代中,第三项的值被设置为“未知”&#39;值。但是,第二项的位置值也是错误的。
有人可以解释这种奇怪的行为吗?但是,当我用两个int成员替换 int2 成员时,一切都按预期工作。对我来说,它似乎是矢量数据类型的错误内存对齐。
修改
代码在Intel CPU上运行,安装了最新的Intel SDK。在CPU设备上运行OpenCL代码是通过设置断点来调试内核的唯一可能性。 IDE是带有OpenCL的英特尔插件的Visual Studio 2015 Update 3。
解决
在Visual Studio的Watch窗口中似乎是 bug 。在OpenCL内核中使用向量数据类型成员调试struct时,它显示错误的值。
答案 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上使用它,则需要在双方都具有兼容性。这种兼容性通常在结构中进行了一些简单的编辑。按对齐排序字段就是其中之一。例如:
(结构)
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.