OpenCL 结构对齐错误
OpenCL struct alignment errors
我在 OpenCL 中对齐主机和设备之间的结构时遇到了问题。我在主机和设备上定义了许多自定义结构,除了一个之外,它们似乎都运行良好。
我正在发送一个数组中的两个结构。第一个结构 (sObject[0]) 中的所有值都在设备中被正确读取,但第二个 (sObject[1]) 正在以一种看似损坏的方式读取,其中所有值都混淆了,有些值丢失了。
据我所知,这可能是数据对齐的问题,其中主机和设备可能具有不同的类型分配或填充,但我已验证数据类型在主机和设备上具有相同的大小device 和我尝试使用 #pragma pack(8)
、__attribute__ ((aligned (128)))
和 __attribute__ ((packed))
等对齐方式,尽管我不确定它们是否与编译器 (VS2017) 一起正常工作。
这是主机和设备上的结构代码:
主持人:
typedef struct _cl_tag_sObject {
cl_double3 m_vCenter;
cl_double3 m_vBounds1;
cl_double3 m_vBounds2;
cl_double m_dRadius;
cl_bool m_type;
} sObject;
设备:
typedef struct _cl_tag_sObject {
double3 m_vCenter;
double3 m_vBounds1;
double3 m_vBounds2;
double m_dRadius;
bool m_type;
} sObject;
以下是主机上的分配值和从设备读取的值:
主持人:
m_vCenter = (0,-100.5,0)
m_vBounds1 = (2,2,2)
m_vBounds2 = (3,3,3)
m_dRadius = 100
m_type = 0
设备:
m_vCenter = (0,0,2)
m_vBounds1 = (2,0,3)
m_vBounds2 = (3,0,100)
m_dRadius = 1
m_type = 0
似乎省略了值 -100.5
,(2,2,2)
和 (3,3,3)
中的中间值取代了填充,尽管我是 OpenCL 的新手并且不确定至于这个过程实际上是如何工作的。
是什么导致了这个问题,如何解决?
谢谢。
WRT 结构打包:__attribute__ ((packed))
导致 GCC 和 LLVM 上的结构元素之间 零填充 。我不知道您的设备的实现是否使用它们。我几乎没有使用 VS 的经验,但我认为 #pragma pack(1)
是您在主机端获得零填充所需要的。
除了打包之外,您需要注意 cl_<type>3
类型在 CL/cl_platform.h header 中被类型定义为 cl_<type>4
类型。所以在 host 方面,它们本质上是相同的。
因此,即使打包,您的结构也有 cl_double4 和 4 个元素,并且在主机内存中应该如下所示(转换为双精度数组):
0 100.5 0 0 | 2 2 2 0 | 3 3 3 0 | 100
我 怀疑 您设备的编译器忽略了主机约定并为 double3 使用真正的 3 元素向量。您可以简单地通过将 device-side 结构更改为使用 double4:
来验证
double4 m_vCenter;
double4 m_vBounds1;
double4 m_vBounds2;
不幸的是,结构在 OpenCL 中是一个灰色区域。可能最好避免结构内部的 3 元素向量..
我在 OpenCL 中对齐主机和设备之间的结构时遇到了问题。我在主机和设备上定义了许多自定义结构,除了一个之外,它们似乎都运行良好。
我正在发送一个数组中的两个结构。第一个结构 (sObject[0]) 中的所有值都在设备中被正确读取,但第二个 (sObject[1]) 正在以一种看似损坏的方式读取,其中所有值都混淆了,有些值丢失了。
据我所知,这可能是数据对齐的问题,其中主机和设备可能具有不同的类型分配或填充,但我已验证数据类型在主机和设备上具有相同的大小device 和我尝试使用 #pragma pack(8)
、__attribute__ ((aligned (128)))
和 __attribute__ ((packed))
等对齐方式,尽管我不确定它们是否与编译器 (VS2017) 一起正常工作。
这是主机和设备上的结构代码:
主持人:
typedef struct _cl_tag_sObject {
cl_double3 m_vCenter;
cl_double3 m_vBounds1;
cl_double3 m_vBounds2;
cl_double m_dRadius;
cl_bool m_type;
} sObject;
设备:
typedef struct _cl_tag_sObject {
double3 m_vCenter;
double3 m_vBounds1;
double3 m_vBounds2;
double m_dRadius;
bool m_type;
} sObject;
以下是主机上的分配值和从设备读取的值:
主持人:
m_vCenter = (0,-100.5,0)
m_vBounds1 = (2,2,2)
m_vBounds2 = (3,3,3)
m_dRadius = 100
m_type = 0
设备:
m_vCenter = (0,0,2)
m_vBounds1 = (2,0,3)
m_vBounds2 = (3,0,100)
m_dRadius = 1
m_type = 0
似乎省略了值 -100.5
,(2,2,2)
和 (3,3,3)
中的中间值取代了填充,尽管我是 OpenCL 的新手并且不确定至于这个过程实际上是如何工作的。
是什么导致了这个问题,如何解决?
谢谢。
WRT 结构打包:__attribute__ ((packed))
导致 GCC 和 LLVM 上的结构元素之间 零填充 。我不知道您的设备的实现是否使用它们。我几乎没有使用 VS 的经验,但我认为 #pragma pack(1)
是您在主机端获得零填充所需要的。
除了打包之外,您需要注意 cl_<type>3
类型在 CL/cl_platform.h header 中被类型定义为 cl_<type>4
类型。所以在 host 方面,它们本质上是相同的。
因此,即使打包,您的结构也有 cl_double4 和 4 个元素,并且在主机内存中应该如下所示(转换为双精度数组):
0 100.5 0 0 | 2 2 2 0 | 3 3 3 0 | 100
我 怀疑 您设备的编译器忽略了主机约定并为 double3 使用真正的 3 元素向量。您可以简单地通过将 device-side 结构更改为使用 double4:
来验证 double4 m_vCenter;
double4 m_vBounds1;
double4 m_vBounds2;
不幸的是,结构在 OpenCL 中是一个灰色区域。可能最好避免结构内部的 3 元素向量..