【发布时间】:2020-08-25 03:42:47
【问题描述】:
我想添加带有进位的 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;
}
【问题讨论】:
-
128 位添加需要更多的工作,不是吗?你不希望它比 32 位版本慢吗?
-
在全球范围内,工作量是相同的:确实,每次添加都需要多 4 倍的工作,但必要添加的数量减少了 4 倍。
-
你没有提到你在哪个平台上(windows 或 linux,哪个 GPU,CUDA 版本,是 WDDM 等),这对于时序分析非常重要。对于计时,在计时测量之前进行“热身”也很常见。当我运行代码的修改版本here(cuda 5.0、rhel 5.5、Quadro5000 GPU)时,我得到的结果是经过的时间大致相同(实际上 128 版本要快一些)。我猜你是在 Windows 上,如果使用 WDDM GPU,准确计时可能会非常困难。
-
如果你在windows下,我猜,也请确定你是在构建项目的调试版本还是发布版本。
-
怀疑,我在带有 WDDM 驱动程序的 Windows 7 下。 VS2010、Cuda 5.5、驱动程序版本 320.57 和 Quadro 600 GPU。在调试版本中观察到性能不佳。发布版本要好得多,但仍然慢了 20%。也许我们可以得出结论,在这种环境下测量时间是不可预测的。感谢您测试我的代码。