这对我来说有点令人困惑,为什么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消除。
答案 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;已经足够了。