-1

我正在学习CUDA。今天,我尝试了书中的一些代码:CUDA Application Design And Development,这让我感到惊讶。为什么 CUDA Thrust 这么慢?这是代码和输出。

#include <iostream>
using namespace std;

#include<thrust/reduce.h>
#include<thrust/sequence.h>
#include<thrust/host_vector.h>
#include<thrust/device_vector.h>
#include <device_launch_parameters.h>

#include "GpuTimer.h"

__global__ void fillKernel(int *a, int n)
{
    int tid = blockDim.x * blockIdx.x + threadIdx.x;
    if(tid <n) a[tid] = tid;
}

void fill(int *d_a, int n)
{
    int nThreadsPerBlock = 512;
    int nBlock = n/nThreadsPerBlock + ((n/nThreadsPerBlock)?1:0);
    fillKernel<<<nBlock, nThreadsPerBlock>>>(d_a, n);
}

int main()
{
    const int N = 500000;
    GpuTimer timer1, timer2;

    thrust::device_vector<int> a(N);

    fill(thrust::raw_pointer_cast(&a[0]), N);

    timer1.Start();
    int sumA = thrust::reduce(a.begin(), a.end(), 0);
    timer1.Stop();

    cout << "Thrust reduce costs " << timer1.Elapsed() << "ms." << endl;

    int sumCheck = 0;
    timer2.Start();
    for(int i = 0; i < N; i++)
        sumCheck += i;
    timer2.Stop();

    cout << "Traditional reduce costs " << timer2.Elapsed() << "ms." << endl;
    if (sumA == sumCheck)
        cout << "Correct!" << endl;
    return 0;
}

在此处输入图像描述

4

1 回答 1

5

您没有有效的比较。您的 GPU 代码正在执行此操作:

int sumA = thrust::reduce(a.begin(), a.end(), 0);

您的 CPU 代码正在执行此操作:

for(int i = 0; i < N; i++)
    sumCheck += i;

这种方法有很多问题,我不知道从哪里开始。首先,GPU 操作是一个有效的归约,它将为向量中的任何数字序列提供有效的结果a。碰巧你有从 1 到 N in 的序列a,但不一定非要这样,它仍然会给出正确的结果。CPU 代码只给出 1 到 N 的特定序列的正确答案。其次,智能编译器可能能够优化 CPU 代码的性能,基本上将整个循环减少为常量赋值语句。(从 1 到 N 的总和只是 (N+1)(N/2) 不是吗?)我不知道 CPU 端的引擎盖下可能会进行哪些优化。

更有效的比较是在这两种情况下进行实际的任意减少。一个示例可能是对在设备向量上操作与在主机向量上操作的推力::reduce 进行基准测试。或者编写自己的串行 CPU 缩减代码,该代码实际上对向量进行操作,而不是将 1 到 N 的整数相加。

正如评论中所指出的,如果您真的想要帮助,请记录您正在运行的硬件和软件平台等内容,并提供所有代码。我不知道 GPUtimer 是做什么的。我投票决定将其关闭为“过于本地化”,因为我认为没有人会发现使用这样的方法进行比较有用。

于 2013-03-07T15:52:58.243 回答