【问题标题】:CUDA vs Intel AVX / SSE vector sum performance questionsCUDA 与英特尔 AVX/SSE 向量和性能问题
【发布时间】:2013-10-21 08:56:52
【问题描述】:

首先,我是 CUDA 的新手,我正在努力学习,所以也许我做错了什么。我想将 CUDA 性能与使用 Intel 内在函数实现的等效函数进行比较,期望 CUDA 会产生更好的结果。

但令我惊讶的是,这不是我所看到的。我的函数非常简单,我只需添加两个向量并将结果存储在第三个向量中。我的 CUDA 代码是最基本的,在我的设置功能中:

void cudaAddVectors(float* vectorA, float* vectorB, float* sum, int numElements)
{
//
// Allocate the memory on the device
//
float* dvA;
float* dvB;
float* dvC;

cudaMalloc((void**)&dvA, numElements * sizeof(float));
cudaMalloc((void**)&dvB, numElements * sizeof(float));
cudaMalloc((void**)&dvC, numElements * sizeof(float));

//
// Copy the host vectors to device vectors
//
cudaMemcpy(dvA, vectorA, numElements * sizeof(float), cudaMemcpyHostToDevice);
cudaMemcpy(dvB, vectorB, numElements * sizeof(float), cudaMemcpyHostToDevice);

//
// Perform the sum on the device and time it
//
deviceSumLink(dvA, dvB, dvC, numElements);

//
// Now get the results back to the host
//
cudaMemcpy(sum, dvC, numElements * sizeof(float), cudaMemcpyDeviceToHost);

// Cleanup and go home
cudaFree(dvA);
cudaFree(dvB);
cudaFree(dvC);

}

然后设备代码使用块或线程运行,如下所示:

void deviceSumLink(float* a, float* b, float* c, int numElements)
{
    //deviceSum<<<numElements, 1>>>(a,b,c);
    deviceSumThreads<<<1, numElements>>>(a,b,c);
}

以及在设备上运行的实际代码:

__global__ void deviceSum(float* a, float* b, float* c)
{
    int index = blockIdx.x;
    c[index] = a[index] + b[index];
}

__global__ void deviceSumThreads(float* a, float* b, float* c)
{
    int index = threadIdx.x;
    c[index] = a[index] + b[index];
}

我对 Intel 版本的这个和 CUDA 进行了计时,对不同大小的向量求和,并验证两者都产生了准确的结果。对于 CUDA 调用,我只计时 deviceSumLink 调用,而不是内存设置和所有内容,但无论调用内核的方法如何,英特尔内在函数版本(使用 8 元素数组)只是将 CUDA 从水。基本上,该功能的英特尔 SIMD 版本快 10 倍!

我没想到会这样,所以我把这归功于我是 CUDA 的新手。那么我做错了什么?我认为 CUDA 在这类事情上应该要快得多,我想我一定没有正确使用它或其他什么。

如果您有一些见解,我会感谢 cmets!

谢谢!

【问题讨论】:

  • 忘了添加我在配备 2.3 GHz Intel Core i7 和 NVidia GeForce GT 650M 的 MacBookPro Retina 上运行此程序
  • 您是说您的基准测试是在具有 8 个浮点数 的数组上完成的吗? (即 numElements = 8)?
  • numElements 可以是 8 的任意倍数,并且向量是浮点数,是的。英特尔希望内存与 32 字节边界对齐,因此它们是对齐的。
  • 这不是我问的。让我再尝试一次。对于引用的“快 10 倍!”,您使用的 numElements 的值是多少。
  • 是的,在这种特殊情况下是的......我尝试了 8 的不同倍数,但我看到了一些奇怪的结果,例如,有 800 个元素产生 0.001028 毫秒的英特尔和 0.013893 的 CUDA。然后 8000 个元素对英特尔有 0.009781,对 CUDA 有 0.008457,然后 80000 个元素对英特尔有 0.105219,对 cuda 有 0.006614(?!)那么,我错过了什么?为什么 80000 比 8000 快?谢谢帮助

标签: cuda simd intrinsics


【解决方案1】:

仅使用 1 个块或每个块 1 个线程来添加向量不会充分利用 GPU。由于the limitation of thread size per block and block size,它们不适用于大型向量。

要正确添加两个大向量并获得最佳性能,您需要这样的内核

__global__ void
vectorAdd(const float *A, const float *B, float *C, int numElements)
{
    int i = blockDim.x * blockIdx.x + threadIdx.x;

    if (i < numElements)
    {
        C[i] = A[i] + B[i];
    }
}

并使用以下线程/块设置调用它

int threadsPerBlock = 256;
int blocksPerGrid =(numElements + threadsPerBlock - 1) / threadsPerBlock;

vectorAdd<<<blocksPerGrid, threadsPerBlock>>>(d_A, d_B, d_C, numElements);

有关详细信息,请参阅此 CUDA 示例。

http://docs.nvidia.com/cuda/cuda-samples/#vector-addition

【讨论】:

    猜你喜欢
    • 2012-11-14
    • 2020-03-21
    • 1970-01-01
    • 1970-01-01
    • 2011-11-04
    • 2013-06-06
    • 2016-10-29
    • 2017-05-08
    • 1970-01-01
    相关资源
    最近更新 更多