Java CUDA校准要求:我应该更改数据结构吗?

Java CUDA校准要求:我应该更改数据结构吗?,java,cuda,memory-alignment,Java,Cuda,Memory Alignment,在《CUDA C编程指南》中,有一部分说明: 全局内存指令支持读取或写入大小相同的单词 等于1、2、4、8或16字节。任何访问(通过变量或 指向驻留在全局内存中的数据的指针)编译为单个全局内存 内存指令当且仅当数据类型的大小为1,2, 4、8或16字节,数据自然对齐(即其地址 是该尺寸的倍数) 如果未满足此尺寸和对齐要求,则访问 编译为具有交错访问模式的多条指令 防止这些指令完全合并。因此 建议对以下数据使用符合此要求的类型: 驻留在全局内存中 我正在使用Java包装器在代码(JCuda)中使用

在《CUDA C编程指南》中,有一部分说明:

全局内存指令支持读取或写入大小相同的单词 等于1、2、4、8或16字节。任何访问(通过变量或 指向驻留在全局内存中的数据的指针)编译为单个全局内存 内存指令当且仅当数据类型的大小为1,2, 4、8或16字节,数据自然对齐(即其地址 是该尺寸的倍数)

如果未满足此尺寸和对齐要求,则访问 编译为具有交错访问模式的多条指令 防止这些指令完全合并。因此 建议对以下数据使用符合此要求的类型: 驻留在全局内存中

我正在使用Java包装器在代码(JCuda)中使用CUDA。我已经用Java定义了自己的
float3
等价物(它只是一个交错的x、y和z元素的
float[]
数组)。
我的问题是,既然我定义的
float3
占用
3 x sizeof(float)=12个字节
,并且12个字节不等于CUDA获取的字的长度,我是否应该在末尾手动添加一个padding元素,并将其设为16个字节

作为一个非常相关的附带问题:
我的内核需要一个指向
float3
数据的指针,因此当我从Java调用它时,我会将我拥有的float[]数据传递给它,它包含Java端的所有
float3
元素。现在我的java
float3
没有对齐,我是否处理了错误的值?我这样问是因为在《编程指南》的另一部分中,它说:

读取非自然对齐的8字节或16字节字会产生 结果不正确(用几句话表示),因此必须特别小心 保持任何值或数组的起始地址对齐 这些类型的值。这是一个很容易解决的典型案例 忽略的是,在使用某些自定义全局内存分配方案时, 多个数组的分配(通过对 cudaMalloc()或cuMemAlloc()被单个 大内存块被分割成多个数组,在这种情况下 每个数组的起始地址与块的起始地址偏移 地址

那么,这是否意味着当我的数据没有对齐,并且我请求该数据中的某个偏移量时,我获取了错误的值


提前感谢您的回答:-)

因此,经过一些尝试和错误之后,使用padded
float3
显然可以提高程序的性能。因此,我决定使用填充的
float3
和跨步内存(使用
cudamallocitch


但是,对于我问题的第二部分,我仍然没有听到一个好的答案。

这个问题有两个方面:

  • 正确访问内存的要求是什么
  • 如何优化内存访问的吞吐量
  • 对于第一项:正如CUDA文档所指出的,为了正确加载和存储数据,每个访问的地址必须能被访问的大小平均分割。例如,
    float
    类型的对象的大小为四个字节,因此必须在四的倍数的地址访问它。如果违反对齐要求,数据将被错误地读取和存储,即数据将变得混乱

    对于内置的非复合类型,所需的对齐方式等于类型的大小,这称为“自然对齐”。对于用户定义的复合类型(如结构),所需的对齐方式是最大构件类型的对齐方式。这适用于问题中的用户定义的
    float3
    类型,该类型具有四字节对齐要求,因为最大组件的类型为
    float
    。程序员可以使用
    \uuuu align\uuuu()
    属性来增加所需的对齐。见:

    对于内置复合类型,CUDA需要与复合类型大小相等的对齐。例如,类型为
    int2
    float2
    的对象必须在8字节边界上对齐,而类型为
    float4
    double2
    的对象必须在16字节边界上对齐

    第二项:GPU能够执行对齐的4字节、8字节和16字节访问,通常,每次访问越宽,总体内存吞吐量越高。GPU硬件的一个大大简化的视图是,硬件内部有固定大小的队列,用于跟踪每个内存访问。每次内存访问越宽,可以排队等待传输的字节总数就越大,这反过来又提高了延迟容忍度和总体内存吞吐量


    因此,如果可能的话,我建议从自定义的
    float3
    类型切换到内置的
    float4
    类型。前者将导致数据以4字节的块加载,而后者允许数据以16字节的块加载。

    关于第一部分,这取决于设备的计算能力和设备中是否存在缓存。看看这篇文章,它使用不同的设备检查了不同的场景。关于第二部分,我个人不理解你的元素是如何不对齐的。它们不是以{a0.x,a0.y,a0.z,a1.x,a1.y,a1.z,…}的形式放在内存中吗?然而,CUDA C编程指南特别指出,对地址的访问不是字长的倍数,不会完全合并。这是我在这里主要关心的问题,因为读取我的输入数据似乎没有完全合并。关于您的第二条评论,它们完全按照您提到的方式放置,但是,目前它们似乎不符合文档指定的单词对齐要求。我只是觉得引用的段落的措词很简单