我正在尝试使用CUDA将NBody问题解决代码移植到GPU。
Nvidia在CUDA SDK附带的样本中提供了一个NBody解决模拟。它在samples / 5_Simulations / nbody中。
我不是C ++或CUDA的专家,很难理解他们的代码分布在几个文件中,所以我最终决定编写我自己的http://docs.nvidia.com/cuda/samples/5_Simulations/nbody/doc/nbody_gems3_ch31.pdf中描述的算法实现。
我的实施很快就成功了,我能够在GTX Titan上每秒计算250亿次双精度交互。当我使用-benchmark -fp64运行它们的实现时,我获得了相同的性能。这对我来说是令人惊讶的,因为在我上面链接的文章中,它们在200Gflop(单精度)卡上每秒达到100亿次单精度交互。 GTX titan大约是1.3 Tflops(双精度)因此我预计双精度每秒650亿次交互。
当我用-benchmark -fp64 -numdevices = 6运行它们的实现时,为了增加神秘感,计算速度提高了18倍。这相当于300%缩放???通过将-numbodies设置为比其默认值大十倍,为GPU添加更多工作会产生450%缩放???
我应该补充一点,我正在运行CUDA SDK 5.5版本的nbody实现,并且该系统基于6个相同的GTX巨头。
我已经尝试了很多东西来在我的单个GPU代码上获得超过250亿次交互,但是根据nvvp,内存访问效率接近100%并且占用率为50%(所有增加的尝试次数),它似乎真的达到了顶峰它没有为表现做任何事情。)
是否有任何可以让GPU具有300%缩放率的机制?
我的代码是否真的像我预期的那样,通过翻牌来判断它的运行速度提高2-3倍?
cuda提供的样本是否有问题?
以防万一这是内核的简单版本:
__global__
void Force_GPU(double4 *d_r,double3 *d_F){
unsigned int idx=threadIdx.x;
unsigned int index=blockIdx.x*blockDim.x+idx;
__shared__ double4 sharedpos[tilesize];
double4 position=d_r[index];
double3 temp_r,force={0.0,0.0,0.0};
double temp_d;
#pragma unroll
for(int tile=0;tile<numtiles;tile++){
sharedpos[idx]=d_r[tile*tilesize+idx];
__syncthreads();
#pragma unroll
for(int j=0;j<tilesize;j++){
temp_r.x = position.x -sharedpos[j].x;
temp_r.y = position.y -sharedpos[j].y;
temp_r.z = position.z -sharedpos[j].z;
temp_d = temp_r.x * temp_r.x + temp_r.y * temp_r.y + temp_r.z * temp_r.z+1e-23;
temp_d = rsqrt(temp_d);
temp_d *= temp_d*temp_d;
temp_d *=sharedpos[j].w;
force.x += temp_r.x * temp_d;
force.y += temp_r.y * temp_d;
force.z += temp_r.z * temp_d;
}
__syncthreads();
}
d_F[index]=force;
}
我有更多令人困惑的优化内存流并摆脱软化参数1e-23,但性能影响对于内存优化(我认为不是很多数据)和小(但很清楚)都不存在软化参数(需要更复杂的控制流程以避免计算粒子本身的力)。正如我所说,我也尝试增加占用率,但它受到每个SM 2048个中1024个线程的寄存器的限制。强制降低寄存器使用率会产生可怜的性能,还需要弄乱磁贴以减少共享内存的使用。
非常感谢任何帮助和意见。
答案 0 :(得分:2)
cuda提供的样本是否有问题?
我相信通过CUDA 5.5的nbody示例代码中存在/是一个错误,它在多GPU设置中开始生效4 GPU或更多(甚至可能有2个GPU或更多)。您可以通过使用cuda-memcheck
运行nbody示例代码来获得一些指示。
它可以在目前可用的CUDA 6 RC跌落中修复,我还没有检查过。