在 OpenCL 结构中使用矢量数据类型会导致 Visual Studio 中的 Watch 问题
Using vector data types in OpenCL structs causes Watch problems in Visual Studio
考虑以下 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,我在将项目(结构)添加到数组后发生内存损坏。下一项的成员被奇怪的值覆盖(我假设内存填充)。
在下面的屏幕截图中,您可以看到循环第一次迭代后的调试值。红色是所有更改的值。将第一个结构项添加到数组中,导致更改第二个项的值成员。
在第二次迭代中,第三项的值设置为 'unknown' 值。但是第二项的position值也是错误的
谁能解释一下这种奇怪的行为?但是,当我用两个 int 成员替换 int2 成员时,一切都按预期进行。对我来说,这似乎是向量数据类型的内存对齐错误。
编辑
Intel CPU 上的代码是 运行,安装了最新的 Intel SDK。 运行 CPU 设备上的 OpenCL 代码是通过设置断点调试内核的唯一可能。 IDE 是 Visual Studio 2015 Update 3,带有适用于 OpenCL 的英特尔插件。
已解决
这似乎是 Visual Studio 的 Watch window 中的一个 bug。在 OpenCL 内核中调试具有矢量数据类型成员的结构时显示错误值。
我已经在我的 GPU 上验证了你的代码,它没有问题。
你要的东西do/check:
1.Make确保您安装了最新的 OpenCL 驱动程序和图形驱动程序。
2.Make 确定这不是 "Watch" 问题。将数据复制到 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]
一定是对齐问题。根据设备和主机,它可能会或可能不会工作,因此您需要确保对齐在主机和设备端都明确兼容。
如果你能看到结果,它已经被复制到内存中。将结果复制到 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.
考虑以下 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,我在将项目(结构)添加到数组后发生内存损坏。下一项的成员被奇怪的值覆盖(我假设内存填充)。
在下面的屏幕截图中,您可以看到循环第一次迭代后的调试值。红色是所有更改的值。将第一个结构项添加到数组中,导致更改第二个项的值成员。
在第二次迭代中,第三项的值设置为 'unknown' 值。但是第二项的position值也是错误的
谁能解释一下这种奇怪的行为?但是,当我用两个 int 成员替换 int2 成员时,一切都按预期进行。对我来说,这似乎是向量数据类型的内存对齐错误。
编辑
Intel CPU 上的代码是 运行,安装了最新的 Intel SDK。 运行 CPU 设备上的 OpenCL 代码是通过设置断点调试内核的唯一可能。 IDE 是 Visual Studio 2015 Update 3,带有适用于 OpenCL 的英特尔插件。
已解决
这似乎是 Visual Studio 的 Watch window 中的一个 bug。在 OpenCL 内核中调试具有矢量数据类型成员的结构时显示错误值。
我已经在我的 GPU 上验证了你的代码,它没有问题。
你要的东西do/check:
1.Make确保您安装了最新的 OpenCL 驱动程序和图形驱动程序。
2.Make 确定这不是 "Watch" 问题。将数据复制到 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]
一定是对齐问题。根据设备和主机,它可能会或可能不会工作,因此您需要确保对齐在主机和设备端都明确兼容。
如果你能看到结果,它已经被复制到内存中。将结果复制到 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.