为什么cuda版本比cpu代码慢2倍?

时间:2015-08-09 02:18:36

标签: c++ cuda

这对我来说有点令人困惑,为什么cuda代码的运行速度大约是cpu版本的两倍。 cpu代码在main上面注释掉了。我只是计算从0到(512 * 512 * 512)的所有素数。 cpu版本在大约97秒内执行,而gpu版本需要182秒。我有一台运行速度为4 Ghz的intel i7和一款nvidia GTX 960.有什么想法吗?

#include <cuda.h>
#include <iostream>
#include <cstdint>
#include <stdio.h>
#include <ctime>
#include <vector>
#include <cstdlib>
#include <climits>

using namespace std;



__host__ __device__  bool is_prime(uint32_t n)
{
    if(n == 2)
        return true;
    if(n % 2 == 0)
        return false;
    uint32_t sr = sqrtf(n);

    for(uint32_t i = 3; i <= sr; i += 2)
        if(n % i == 0)
            return false;
    return true;
}

__global__ void prime_sum(unsigned int* count)
{
    uint32_t n = (blockIdx.y * gridDim.y + blockIdx.x) * blockDim.x + threadIdx.x;
    if(is_prime(n))
        atomicAdd(count, 1);
}

int main()
{
    /* CPU VERSION
    time_t start = time(0);
    int pcount = 0;
    for(uint32_t i = 0; i < (512 * 512 * 512); i++)
    {
        if(is_prime(i)) pcount++;
    }
    start = time(0) - start;
    std::cout << pcount << "\t" << start << std::endl;
    */

    //CUDA VERSION
    time_t start = time(0);
    unsigned int* sum_d;
    cudaMalloc(&sum_d, sizeof(unsigned int));
    cudaMemset(sum_d, 0, sizeof(unsigned int));

    prime_sum<<< dim3(512, 512), 512 >>>(sum_d);

    unsigned int sum = 0;
    cudaMemcpy(&sum, sum_d, sizeof(unsigned int), cudaMemcpyDeviceToHost);
    start = time(0) - start;
    std::cout << sum << "\t" << start << std::endl;
    cudaFree(sum_d);

    return 0;
}

这是一个想法。 is_prime函数的效率来自于能够在大多数时间快速退出,因为大多数数字可以被2或更低的数字整除,所以当大多数时候串行执行时循环快速退出。但是由于warp每组32个线程必须等待最坏的结束。另外,我包括evens,所以一半的线程将被第一个if消除。

1 个答案:

答案 0 :(得分:0)

首先,GPU通常具有良好的浮点计算能力,但不具有整数计算能力,模块化(和除法)操作非常慢。

其次,在Kelper架构之前,全球的atmoic操作很慢,但你有一台GTX 960,所以我认为这不是问题所在。

第三,对于CPU版本,每个整数可以在它不是素数之后立即退出循环。但是对于GPU,整数必须等到其所有32个相邻线程都退出。在你的代码中,偶数线程在进入内核后立即退出,但它们必须等到奇数线程完成它们的循环。

BTW,为什么要使用&lt;&lt;&lt; dim3(512,512),512&gt;&gt;&gt;?我认为1D工作维度&lt;&lt;&lt;&lt; 512 * 512,512&gt;&gt;&gt;已经足够了。