【问题标题】:CUDA: is there a faster way of writing to global memory?CUDA:有没有更快的写入全局内存的方法?
【发布时间】:2016-08-11 17:41:50
【问题描述】:

我在写一个n体模拟,基本上整个操作是:

-Prepare CUDA memory
 loop {
    -Copy data to CUDA
    -Launch kernel
    -Copy data to host
    -Operations using data (drawing etc.)
 }

我注意到几乎 90% 的时间都花在了将数据写入内核中的全局设备内存上。这是内核:

 __global__ void calculateForcesCuda(float *deviceXpos, float *deviceYpos, float *deviceZpos,
                                    float *deviceXforces, float *deviceYforces, float *deviceZforces,
                                    float *deviceMasses, int particlesNumber) {
     int tid = threadIdx.x + blockIdx.x * blockDim.x;
     if (tid <= particlesNumber) {
         float particleXpos = deviceXpos[tid];
         float particleYpos = deviceYpos[tid];
         float particleZpos = deviceZpos[tid];
         float xForce = 0.0f;
         float yForce = 0.0f;
         float zForce = 0.0f;
         for (int index=0; index<particlesNumber; index++) {
             if (tid != index) {
                 float otherXpos = deviceXpos[index];
                 float otherYpos = deviceYpos[index];
                 float otherZpos = deviceZpos[index];
                 float mass = deviceMasses[index];
                 float distx = particleXpos - otherXpos;
                 float disty = particleYpos - otherYpos;
                 float distz = particleZpos - otherZpos;
                 float distance = sqrt((distx*distx + disty*disty + distz*distz) + 0.01f);
                 xForce += 10.0f * mass / distance * (otherXpos - particleXpos);
                 yForce += 10.0f * mass / distance * (otherYpos - particleYpos);
                 zForce += 10.0f * mass / distance * (otherZpos - particleZpos);
             }
         }
         deviceXforces[tid] += xForce;
         deviceYforces[tid] += yForce;      
         deviceZforces[tid] += zForce;
     }
 }

运行它的设备是 GTX 970。执行时间约为 8.0 秒,但添加这些标志后:-gencode arch=compute_52,code=sm_52 strong>,性能提升到 6.7 秒左右。注释掉写入全局设备内存的代码后:

deviceXforces[tid] += xForce;
deviceYforces[tid] += yForce;      
deviceZforces[tid] += zForce;

... 总执行时间减少到 0.92 秒左右,这意味着写入全局设备内存大约需要 86% 的执行时间。有没有办法提高这些写入的性能?

【问题讨论】:

  • 您误解了正在发生的事情。内存写入不是此代码中的瓶颈。删除它们只是让编译器优化你的大部分代码
  • @talonmies 上帝,你说得对。所以计算本身实际上很慢。我会留下这个问题,以防其他人犯同样的错误。
  • 我怀疑计算是问题所在。循环内的内存负载将是最大的问题。开始考虑数据重用和缓存性能
  • 正如 talonmies 所说,代码可能受内存限制。但是,附带说明一下:在性能方面,此代码中执行的计算将受益于 rnorm3d() 函数的使用。

标签: c++ cuda


【解决方案1】:

内存通常是这种计算的瓶颈,即使它没有像您测量的那样占用 90% 的时间。我会建议两件事。

device...[index] 加载到共享内存中

就目前而言,所有线程都读取相同的deviceXpos[index]deviceYpos[index]deviceZpos[index]deviceMasses[index]。相反,您可以将它们加载到共享内存中:

static const int blockSize = ....;

__shared__ float shXpos[blockSize];
__shared__ float shYpos[blockSize];
__shared__ float shZpos[blockSize];
__shared__ float shMasses[blockSize];
for (int mainIndex=0; mainIndex<particlesNumber; index+=blockSize) {
    __syncthreads(); //ensure computation from previous iteration has completed
    shXpos[threadIdx.x] = deviceXpos[mainIndex + threadIdx.x];
    shYpos[threadIdx.x] = deviceYpos[mainIndex + threadIdx.x];
    shZpos[threadIdx.x] = deviceZpos[mainIndex + threadIdx.x];
    shMasses[threadIdx.x] = deviceMasses[mainIndex + threadIdx.x];
    __syncthreads(); //ensure all data is read before computation starts
    for (int index=0; index<blockSize; ++index) {
        .... //your computation, using sh....[index] values
    }
}

这应该会减少全局内存读取量,因为每个线程读取不同的数据,而不是全部读取相同的数据。

但是请注意,如果驱动程序正确管理 L1 缓存,此建议可能不会那么有效。试试吧!

每个线程处理超过 1 个(接收)粒子

您可能希望一次计算多个粒子。您可以同时拥有几个 {particleX/Y/Zpos, x/y/zForce},而不是只有一组 {x/y/zForce},代表单个粒子接收力。 这样,通过在循环中加载一次源,您可以处理多个接收器。

这可能会显着降低您的内存压力,但同时会增加您的寄存器数量。寄存器太多 - 您将无法启动那么多线程。

检查您的线程已有多少个寄存器,并查阅 CUDA 占用计算器,看看您还能使用多少个。也许将占用率从 1 减少到 0.5 或 0.75,但同时处理更多的粒子会是有益的?您需要进行试验,因为这可能因 GPU 而异。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-07-11
    • 2014-04-06
    • 2013-08-26
    • 2012-12-09
    • 2011-06-12
    • 1970-01-01
    • 2019-04-02
    • 2020-05-08
    相关资源
    最近更新 更多