【发布时间】:2019-08-14 12:49:38
【问题描述】:
我在使用内核时遇到了一些问题,该内核使用了我在 c++ 中定义的一些结构。 cuda-memcheck 给我的错误是对齐问题。
我尝试使用的结构包含一些指针,我猜这给我带来了问题。我已经在 .cu 文件和内核的主机函数中打印了 C++ 端和 CUDA 端的结构大小以控制台。这给出了不同的结果,这解释了我看到的问题,但我不确定它为什么会发生或如何解决它。
我使用的结构如下
struct Node {};
struct S
{
Node *node0;
Node *node1;
Node *node2;
double p0;
double p1;
double p2;
double p3;
Eigen::Matrix<double, 3, 2> f1;
Eigen::Matrix<double, 3, 2> f2;
}
在 C++ 中它的大小为 160 字节,但在 CUDA 中为 152 字节。为了传输数据,我分配了一个 CUDA 端缓冲区并执行 cudaMemcpy
std::vector<S> someVector; // Consider it exists
S *ptr;
cudaMalloc(&ptr, sizeof(S) * someVector.size());
cudaMemcpy(ptr, someVector.data(), sizeof(S)*someVector.size(), cudaMemcpyHostToDevice);
我猜这是错误的,因为 CUDA 和 C++ 中的大小不同。
当我尝试在内核中访问 S::node0、S::node1 或 S::node3 时,我会收到未对齐的访问错误。
所以我对这个问题有三个问题:
- 为什么尺寸不同?
- 我应该如何更改代码或执行复制以使其正常工作?
- 我应该有一个 CUDA 侧结构并执行特殊复制吗?
编辑:
感谢接受的答案,我能够理解我遇到的问题的原因。 Eigen 尽可能使用 vectorizacion 并为此请求 16 字节对齐。当 Eigen 对象大小是 16 字节的倍数时,将启用矢量化。在我的特殊情况下,两个Eigen::Matrix<double, 3,2> 对矢量化有效。
但是,在 CUDA 中,Eigen 不要求 16 字节对齐。
由于我的结构有 4 个双精度数和 3 个指针,计算为 56 个字节,这不是 16 的倍数,因此在 CPU 中它必须添加 8 个填充字节,因此 Eigen 矩阵是 16 个字节对齐的。在 CUDA 中不会发生这种情况,因此大小不同。
我实现的解决方案是手动添加 8 个填充字节,因此 CPU 和 CUDA 中的结构相同。这解决了问题,并且不需要禁用矢量化。我发现另一个可行的解决方案是将Eigen::Matrix<double,3,2> 更改为2 Eigen::Matrix<double,3,1>。 Eigen::Matrix<double,3,1> 不满足向量化的要求,因此不需要在 CPU 中添加 8 个填充字节。
【问题讨论】:
-
我确实警告过你......
-
太好了,帮助很大,它解决了我的问题,将来可能会帮助其他用户
-
CUDA 架构师非常努力地确保主机和设备之间的结构相同。当然,有多种方法可以打破这一点,答案指出了一条明显的路径:使用 CUDA 或 CUDA 主机/设备差异的存在或不存在来做一些影响对齐或大小的不同事情。这是一个非常糟糕的主意,不幸的是,您的 Eigen 版本似乎正在这样做。如果 master/top-of-tree Eigen 也这样做,我会考虑提交 Eigen 问题。
-
我强烈建议使用当前的开发分支(“默认”),或者在使用 Eigen 和 CUDA 时等待 Eigen 3.4。在 Eigen 3.3 中,CUDA 是 officially still experimental。如果你对默认分支也有问题,我也鼓励你to file a bug。
-
@talonmies 我怀疑如果没有指向您之前警告的链接,您的评论会帮助任何未来的读者......