当我在Cuda-SDK中读取nbody代码时,我在代码中经历了一些行,我发现它与他们在GPUGems3“使用CUDA进行快速N体仿真”中的论文略有不同。
我的问题是:首先,为什么blockIdx.x仍然参与从全局加载内存到共享内存,如下面的代码所示?
for (int tile = blockIdx.y; tile < numTiles + blockIdx.y; tile++)
{
sharedPos[threadIdx.x+blockDim.x*threadIdx.y] =
multithreadBodies ?
positions[WRAP(blockIdx.x + q * tile + threadIdx.y, gridDim.x) * p + threadIdx.x] : //this line
positions[WRAP(blockIdx.x + tile, gridDim.x) * p + threadIdx.x]; //this line
__syncthreads();
// This is the "tile_calculation" function from the GPUG3 article.
acc = gravitation(bodyPos, acc);
__syncthreads();
}
根据纸张不应该是这样吗?我想知道为什么
sharedPos[threadIdx.x+blockDim.x*threadIdx.y] =
multithreadBodies ?
positions[WRAP(q * tile + threadIdx.y, gridDim.x) * p + threadIdx.x] :
positions[WRAP(tile, gridDim.x) * p + threadIdx.x];
其次,在每个主体的多个线程中为什么还要涉及threadIdx.x?它不应该是一个固定值或根本不涉及,因为总和只是由于threadIdx.y
if (multithreadBodies)
{
SX_SUM(threadIdx.x, threadIdx.y).x = acc.x; //this line
SX_SUM(threadIdx.x, threadIdx.y).y = acc.y; //this line
SX_SUM(threadIdx.x, threadIdx.y).z = acc.z; //this line
__syncthreads();
// Save the result in global memory for the integration step
if (threadIdx.y == 0)
{
for (int i = 1; i < blockDim.y; i++)
{
acc.x += SX_SUM(threadIdx.x,i).x; //this line
acc.y += SX_SUM(threadIdx.x,i).y; //this line
acc.z += SX_SUM(threadIdx.x,i).z; //this line
}
}
}
任何人都可以向我解释这个吗?是否为更快的代码进行了某种优化?
答案 0 :(得分:4)
我是此代码和论文的作者。编号的答案对应于您编号的问题。
本文未提及到WRAP
宏的blockIdx.x偏移量,因为这是一个微优化。我甚至不确定它是否值得。目的是确保不同的SM访问不同的DRAM存储体而不是同时在同一个存储体上进行全部冲击,以确保在这些负载期间最大化存储器吞吐量。如果没有blockIdx.x
偏移量,则所有同时运行的线程块将同时访问同一地址。由于整体算法是计算而不是带宽限制,因此这绝对是次要的优化。可悲的是,它使代码更加混乱。
如你所说,总和在threadIdx.y
之间,但每个线程需要单独计算一个总和(每个线程计算一个单独体的引力)。因此,我们需要使用threadIdx.x
索引(概念上的2D)共享内存数组的右列。
要回答SystmD的问题(不是真的正确),gridDim.y
在(默认/常见)1D区块案例中只有1个。
答案 1 :(得分:0)
1) 在同步每个块的线程(使用__syncthreads())之前,将数组SharedPos加载到每个块的共享存储器(即每个块)中。根据算法,blockIdx.x是图块的索引。
每个线程(索引threadIdx.x threadIdx.y)加载共享数组SharedPos的一部分。 blockIdx.x指的是tile的索引(没有多线程)。
2) acc是body索引的float3 blockIdx.x * blockDim.x + threadIdx.x(参见integrateBodies函数的开头)
我发现multithreadBodies = true在这个总和中有一些问题,q> 4(128个体,p = 16,q = 8 gridx = 8)。 (使用GTX 680)。在整个blockDim.y中没有完成一些总和......
我改变了代码以避免这种情况,它有效,但我不知道为什么......
if (multithreadBodies)
{
SX_SUM(threadIdx.x, threadIdx.y).x = acc.x;
SX_SUM(threadIdx.x, threadIdx.y).y = acc.y;
SX_SUM(threadIdx.x, threadIdx.y).z = acc.z;
__syncthreads();
for (int i = 0; i < blockDim.y; i++)
{
acc.x += SX_SUM(threadIdx.x,i).x;
acc.y += SX_SUM(threadIdx.x,i).y;
acc.z += SX_SUM(threadIdx.x,i).z;
}
}
另一个问题: 在第一个循环中:
for (int tile = blockIdx.y; tile < numTiles + blockIdx.y; tile++)
{
}
我不知道为什么因为grid.y = 1而使用了blockIdx.y。
3)对于更快的代码,我使用异步H2D和D2D内存副本(我的代码只使用引力内核)。