Vector Cuda的128位矢量加法,性能问题

Vector Cuda的128位矢量加法,性能问题,vector,cuda,Vector,Cuda,我想把128位向量和进位相加。我的128位版本(addKernel128在下面的代码中)比基本32位版本(addKernel32在下面)慢两倍。 我有记忆整合问题吗?如何才能获得更好的性能 #include "cuda_runtime.h" #include "device_launch_parameters.h" #include <iostream> #define UADDO(c, a, b) asm volatile("add.cc.u32 %0, %1, %2;" : "

我想把128位向量和进位相加。我的128位版本(
addKernel128
在下面的代码中)比基本32位版本(
addKernel32
在下面)慢两倍。 我有记忆整合问题吗?如何才能获得更好的性能

#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <iostream>

#define UADDO(c, a, b) asm volatile("add.cc.u32 %0, %1, %2;" : "=r"(c) : "r"(a) , "r"(b));
#define UADDC(c, a, b) asm volatile("addc.cc.u32 %0, %1, %2;" : "=r"(c) : "r"(a) , "r"(b));

__global__ void addKernel32(unsigned int *c, const unsigned int *a, const unsigned int *b, const int size)
{
  int tid = blockIdx.x * blockDim.x + threadIdx.x;

  while (tid < size)
  {
    c[tid] = a[tid] + b[tid];
    tid += blockDim.x * gridDim.x;
  }
}

__global__ void addKernel128(unsigned *c, const unsigned *a, const unsigned *b, const int size)
{
  int tid = blockIdx.x * blockDim.x + threadIdx.x;

  while (tid < size / 4)
  {
    uint4 a4 = ((const uint4 *)a)[tid],
          b4 = ((const uint4 *)b)[tid],
          c4;

    UADDO(c4.x, a4.x, b4.x)
    UADDC(c4.y, a4.y, b4.y) // add with carry
    UADDC(c4.z, a4.z, b4.z) // add with carry
    UADDC(c4.w, a4.w, b4.w) // add with carry (no overflow checking for clarity)

    ((uint4 *)c)[tid] = c4;

    tid += blockDim.x * gridDim.x;
  }
}

int main()
{
  const int size = 10000000; // 10 million

  unsigned int *d_a, *d_b, *d_c;

  cudaMalloc((void**)&d_a, size * sizeof(int));
  cudaMalloc((void**)&d_b, size * sizeof(int));
  cudaMalloc((void**)&d_c, size * sizeof(int));

  cudaMemset(d_a, 1, size * sizeof(int)); // dummy init just for the example
  cudaMemset(d_b, 2, size * sizeof(int)); // dummy init just for the example
  cudaMemset(d_c, 0, size * sizeof(int));

  int nbThreads = 512;
  int nbBlocks = 1024; // for example

  cudaEvent_t start, stop;
  cudaEventCreate(&start);
  cudaEventCreate(&stop);
  cudaEventRecord(start);

  addKernel128<<<nbBlocks, nbThreads>>>(d_c, d_a, d_b, size);

  cudaEventRecord(stop);
  cudaEventSynchronize(stop);
  float m = 0;
  cudaEventElapsedTime(&m, start, stop);

  cudaFree(d_c);
  cudaFree(d_b);
  cudaFree(d_a);
  cudaDeviceReset();
  printf("Elapsed = %g\n", m);
  return 0;
}
#包括“cuda_runtime.h”
#包括“设备启动参数.h”
#包括
#定义UADDO(c,a,b)asm volatile(“add.cc.u32%0,%1,%2;”:“=r”(c):“r”(a),“r”(b));
#定义UADDC(c,a,b)asm volatile(“addc.cc.u32%0,%1,%2;”:“=r”(c):“r”(a),“r”(b));
__全局\uuuvoid addKernel32(无符号整数*c、常量无符号整数*a、常量无符号整数*b、常量整数大小)
{
int tid=blockIdx.x*blockDim.x+threadIdx.x;
而(tid<尺寸)
{
c[tid]=a[tid]+b[tid];
tid+=blockDim.x*gridDim.x;
}
}
__全局\uuuvoid addKernel128(无符号*c、常数无符号*a、常数无符号*b、常数整数大小)
{
int tid=blockIdx.x*blockDim.x+threadIdx.x;
而(tid
由于各种原因,在WDDM GPU上对CUDA代码进行计时可能非常困难。其中大部分都围绕着这样一个事实,即GPU是由Windows作为显示设备进行管理的,这可能会在计时中引入各种工件。一个例子是Windows驱动程序和WDM将为GPU批量工作,并且可以在CUDA GPU工作的中间交错显示工作。
  • 如果可能,在linux或windows GPU上计时cuda代码 在变矩器离合器模式下
  • 为了提高性能,始终在不使用
    -G
    开关的情况下构建。在VisualStudio中,这通常对应于生成版本,而不是项目的调试版本
  • 为了获得良好的性能比较,通常建议在实际测量计时结果之前进行一些“预热运行”。这些将消除“启动”和其他一次性测量问题,使您更有可能获得合理的结果。您可能还希望多次运行代码并平均结果
  • 通常建议使用与GPU对应的arch标志进行编译,例如,对于cc2.0 GPU,使用
    -arch=sm_20

    • 由于各种原因,在WDDM GPU上对CUDA代码进行计时可能非常困难。其中大部分都围绕着这样一个事实,即GPU是由Windows作为显示设备进行管理的,这可能会在计时中引入各种工件。一个例子是Windows驱动程序和WDM将为GPU批量工作,并且可以在CUDA GPU工作的中间交错显示工作。
      • 如果可能,在linux或windows GPU上计时cuda代码 在变矩器离合器模式下
      • 为了提高性能,始终在不使用
        -G
        开关的情况下构建。在VisualStudio中,这通常对应于生成版本,而不是项目的调试版本
      • 为了获得良好的性能比较,通常建议在实际测量计时结果之前进行一些“预热运行”。这些将消除“启动”和其他一次性测量问题,使您更有可能获得合理的结果。您可能还希望多次运行代码并平均结果
      • 通常建议使用与GPU对应的arch标志进行编译,例如,对于cc2.0 GPU,使用
        -arch=sm_20

      128位add需要更多的工作,不是吗?你不认为它会比32位版本慢吗?从全球范围来看,工作量是一样的:的确,每一次添加都需要4倍的工作量,但必要添加的数量减少了4倍。你没有提到你在哪个平台上(windows或linux,哪个GPU,CUDA版本,是WDDM,等等)这对于时间分析非常重要。对于计时,在计时测量之前进行“预热运行”也是很常见的。当我运行一个修改过的代码版本(cuda 5.0、rhel 5.5、Quadro5000 GPU)时,我得到的结果是经过的时间大致相同(事实上128版本要快一点)。我猜你是在windows上,如果使用WDDM GPU,精确计时可能会非常困难。如果你是在windows下,正如我猜的那样,还请确定你是否正在构建调试版本或发布版本的项目。正如我所怀疑的,我在windows 7下使用WDDM驱动程序。VS2010、Cuda 5.5、驱动程序版本320.57和Quadro 600 GPU。在调试版本中观察到性能不佳。发布版本要好得多,但仍然慢了20%。也许我们可以得出结论,在这种环境下测量时间是不可预测的。谢谢你测试我的代码。128位加法需要更多的工作,不是吗?你不认为它会比32位版本慢吗