【发布时间】:2022-08-14 20:16:41
【问题描述】:
最近我写了一个分子动力学代码,使用 CUDA 并行计算计算离子-电子力。 内核列表如下:
__global__ void (*x,*y,*z,N){
int i = (blockIdx.x * blockDim.x) + threadIdx.x;
while(i<N) {
double dx;
double dy;
double dz;
double dr;
double Fx;
double Fy;
double Fz;
for (int j = 0; j < N; j++){
dx=x[i]-x[j];
dy=y[i]-y[j];
dz=z[i]-z[j];
dr=sqrt(dx*dx+dy*dy+dz*dz)
dr=dr*dr*dr
Fx+=k*q*q*dx/dr
Fy+=k*q*q*dy/dr
Fz+=k*q*q*dz/dr //force=kq^2r/r^3 written in Cartesian coordinate
}
//rest of the code manipulate force is irrelevant to my question and I want to keep my code short
i += blockDim.x * gridDim.x;
}
}
x,y,z 是粒子的位置,dx,dy,dz 是 xyz 距离,for 循环中的 Fx,Fy,Fz 是施加在第 i 个粒子上的力的总和,更具体地说,您需要计算 x[i ]-x[j] 并遍历所有 js 以找到合力,让内核并行执行所有 i。
我发现这很慢,因为我知道 GPU 正在从全局内存中读取数组。当我将 x[i] 更改为一个数字时,它会变得快 10 倍,因为它正在从寄存器(L1 缓存)中读取。我的数组太大(超过 20000 个元素,双浮点数)无法放入寄存器。但是使用其他内存还能快一点吗?我知道有常量内存和共享内存,但我不知道如何实现。我认为 x[i] 位于全球内存中,导致它很慢,并且所有线程都试图同时读取 x[i]。有什么办法可以提高速度?
-
我会担心正确性而不是性能。您的代码无法计算可重复的正确结果。它甚至不将任何内容存储到全局内存中,这意味着如果您在优化的情况下编译代码,它应该编译为执行时间为零的空内核
-
我在发布此代码时确实更改了我的代码,原始代码很长,需要对这些变量和算法进行更仔细的处理,抱歉,只显示我的部分代码,它过于简单,Fx Fy 和 Fz 绝对需要存储在某个地方,我想念那部分。我的问题是由于循环,每个线程都在读取相同的 x[i] N 次并读取 x[j] N^2 次。有什么方法可以减少读取相同变量的次数或加快读取变量的速度
-
分块平铺方法可以正常工作。基本上将 i 和 j 视为矩阵中的行和列。使用与优化矩阵-矩阵乘法相同的分块评估方案。如果我有时间,我可能稍后会写一个正确的答案
-
发布无法编译的、损坏的代码并询问优化策略有什么意义?细节很重要
-
请注意,在这样的 N 体代码中,由于
1 / dr因子对于“长”距离非常小(它以O(1 / (n^3))的速率减小),因此假设某些力可以忽略是很常见的。因此,您通常可以丢弃大部分计算而不存储它。四叉树和 AMR 方法有助于做到这一点(尽管它并不简单)。此外,存储结果通常不是一个好主意:您需要动态计算它以获得快速代码。现在内存比计算单元慢得多,而且它不会很快变得更好(恰恰相反)。
标签: performance memory cuda pairwise