CUDA的内存访问性能非常差

CUDA的内存访问性能非常差,cuda,Cuda,我是CUDA的新手,正在尝试编写一个测试程序。 我在GeForce GT 520卡上运行应用程序,但性能非常差 该应用程序用于处理一些图像,每一行由单独的线程处理。 下面是该应用程序的简化版本。请注意,在实际应用程序中,所有常量实际上都是变量,只要调用者是 运行下面的代码时,需要超过20秒才能完成执行 但与使用malloc/free相反,当l_srciintegral被定义为本地数组(如注释行中所示)时,完成执行所需的时间不到1秒 由于阵列的实际大小是动态的(而不是1700),因此无法在实际应用

我是CUDA的新手,正在尝试编写一个测试程序。 我在GeForce GT 520卡上运行应用程序,但性能非常差

该应用程序用于处理一些图像,每一行由单独的线程处理。 下面是该应用程序的简化版本。请注意,在实际应用程序中,所有常量实际上都是变量,只要调用者是

运行下面的代码时,需要超过20秒才能完成执行

但与使用malloc/free相反,当
l_srciintegral
被定义为本地数组(如注释行中所示)时,完成执行所需的时间不到1秒

由于阵列的实际大小是动态的(而不是1700),因此无法在实际应用中使用此本地阵列

任何关于如何提高这段相当简单代码的性能的建议都将不胜感激

#include "cuda_runtime.h"
#include <stdio.h>

#define d_MaxParallelRows 320
#define d_MinTreatedRow   5
#define d_MaxTreatedRow   915
#define d_RowsResolution  1
#define k_ThreadsPerBlock 64

__global__ void myKernel(int Xi_FirstTreatedRow)
{
  int l_ThreadIndex = blockDim.x * blockIdx.x + threadIdx.x;
  if (l_ThreadIndex >= d_MaxParallelRows)
    return;
  int l_Row = Xi_FirstTreatedRow + (l_ThreadIndex * d_RowsResolution);
  if (l_Row <= d_MaxTreatedRow) {

    //float l_SrcIntegral[1700];
    float* l_SrcIntegral = (float*)malloc(1700 * sizeof(float));

    for (int x=185; x<1407; x++) {
      for (int i=0; i<1700; i++)
        l_SrcIntegral[i] = i;
    }

    free(l_SrcIntegral);
  }
}

int main()
{
  cudaError_t cudaStatus;

  cudaStatus = cudaSetDevice(0);

  int l_ThreadsPerBlock = k_ThreadsPerBlock;
  int l_BlocksPerGrid = (d_MaxParallelRows + l_ThreadsPerBlock - 1) / l_ThreadsPerBlock;

  int l_FirstRow = d_MinTreatedRow;
  while (l_FirstRow <= d_MaxTreatedRow) {
    printf("CUDA: FirstRow=%d\n", l_FirstRow);
    fflush(stdout);

    myKernel<<<l_BlocksPerGrid, l_ThreadsPerBlock>>>(l_FirstRow);

    cudaDeviceSynchronize();

    l_FirstRow += (d_MaxParallelRows * d_RowsResolution);
  }

  printf("CUDA: Done\n");

  return 0;
}
#包括“cuda_runtime.h”
#包括
#定义d_MaxParallelRows 320
#定义d_MinCreateDrow 5
#定义d_MaxTreatedRow 915
#定义d_行解决方案1
#定义k_螺纹锁64
__全局无效myKernel(int Xi_FirstTreatedRow)
{
int l_ThreadIndex=blockDim.x*blockIdx.x+threadIdx.x;
如果(l_ThreadIndex>=d_MaxParallelRows)
返回;
int l_行=Xi_FirstTreatedRow+(l_线程索引*d_行解决方案);

如果(l_Row您仍然可以使用共享内存使用动态数组大小。只需在内核调用的
中传递第三个参数。这就是每个块的共享内存大小

一旦到了那里,只需将所有相关数据带到共享数组中(您仍应尝试保持合并访问),每个线程带一个或多个(如果与保持合并访问相关)元素。在带完数据后同步线程(仅当您需要停止竞争条件,以确保在完成任何计算之前整个阵列都在共享内存中)并且您可以开始了

另外:应该使用块和线程而不是循环进行细分。我知道这只是一个使用本地数组的示例,但仍然可以通过块/线程进行细分,而不是嵌套循环(这对性能非常有害!)我希望您只使用一个块和一个线程来运行示例代码,否则就没有多大意义了。

1。

正如@aland所说,如果在每个内核调用中只计算一行,可能会遇到更糟糕的性能

你必须考虑处理整个输入,理论上使用大规模并行处理的能力

为什么只为计算一行而启动320个线程的多个内核? 使用尽可能多的块,让每个块的线程处理一行怎么样

(每个区块320个线程不是一个好选择,请查看如何达到更好的占用率)

2.

如果寄存器和共享内存等fast资源不足,则必须使用tile apporach,这是使用GPGPU编程的基础之一

将输入数据分成大小相同的分片,并在线程中循环处理它们

在这里,我发布了一个这种平铺方法的示例:

注意该平铺方法中的范围检查

给您提供想法的示例:

计算任意大小矩阵中列向量中所有元素的总和

每个块处理一列,该块的线程将其元素存储在共享内存数组中的平铺循环中。完成后,它们使用并行缩减计算总和,以开始下一次迭代。

最后,每个块计算其向量之和。

正如我所提到的,这是我的应用程序的一个非常简化的版本。实际代码由各种函数组成,其中一些包含循环。当我剥离所有这些函数时,我只剩下上面看到的循环。关于共享内存使用,似乎我无法分配一个共享足够大的内存以满足我的需要。当我指定一个共享内存大小以满足所有线程所需的存储时,内核激活失败。应用程序一次处理一行映像,并通过创建320个线程(每个线程处理一行)将其调整为执行并行处理。因此,主要的乐趣是Action一次启动320个线程,直到图像的所有行都被处理。@MarkM在GPU上运行320个线程不太可能产生任何加速。请尝试重写您的算法,使每个线程处理较少的数据量,但有更多的线程。现在,由于线程太多,它似乎几乎不适合GPGPU体系结构。当您定义ne
l_srcigral
作为一个本地内存数组,编译器优化将消除整个内核,并最终运行一个空存根。CUDA编译器在删除不利于全局内存写入的死代码方面非常积极。因此,我不会深入了解这两种情况在性能上的差异。@Talonmes,你说的是我需要增强我的示例,以便内存写入不会被优化掉?我会尝试这样做。谢谢。@Talonmes,foget关于local内存阵列。关于如何使上面的代码比现在运行的20多秒快得多,有什么建议吗?你到底想计算什么?