做什么不在CUDA内核中工作

好吧,我对CUDA很新,我有点迷茫,真的迷路了。

我正在尝试使用蒙特卡罗方法计算pi,最后我得到一个加法而不是50加法。

我不想“做同时”来调用内核,因为它太慢了。 我的问题是,我的代码不循环,它只在内核中执行一次。

而且,我希望所有线程访问相同的niter和pi,所以当一些线程击中计数器时,所有其他线程将停止。

#define SEED 35791246 __shared__ int niter; __shared__ double pi; __global__ void calcularPi(){ double x; double y; int count; double z; count = 0; niter = 0; //keep looping do{ niter = niter + 1; //Generate random number curandState state; curand_init(SEED,(int)niter, 0, &state); x = curand(&state); y = curand(&state); z = x*x+y*y; if (z<=1) count++; pi =(double)count/niter*4; }while(niter < 50); } int main(void){ float tempoTotal; //Start timer clock_t t; t = clock(); //call kernel calcularPi<<>>(); //wait while kernel finish cudaDeviceSynchronize(); typeof(pi) piFinal; cudaMemcpyFromSymbol(&piFinal, "pi", sizeof(piFinal),0, cudaMemcpyDeviceToHost); typeof(niter) niterFinal; cudaMemcpyFromSymbol(&niterFinal, "niter", sizeof(niterFinal),0, cudaMemcpyDeviceToHost); //Ends timer t = clock() - t; tempoTotal = ((double)t)/CLOCKS_PER_SEC; printf("Pi: %g \n", piFinal); printf("Adds: %d \n", niterFinal); printf("Total time: %f \n", tempoTotal); } 

您的代码存在各种问题。

  1. 我建议使用正确的cuda错误检查并使用cuda-memcheck运行代码以发现任何运行时错误。 为了简化演示,我在下面的代码中省略了正确的错误检查,但是我用cuda-memcheck运行它来表示没有运行时错误。

  2. 你对curand()使用可能不正确(它会在很大范围内返回整数)。 为了使此代码正常工作,您需要一个介于0和1之间的浮点数。 正确的调用是curand_uniform()

  3. 由于您希望所有线程都使用相同的值,因此必须防止这些线程相互踩踏。 一种方法是使用有问题的变量的primefaces更新。

  4. 没有必要在每次迭代时重新运行curand_init 。 每个线程一次就足够了。

  5. 我们不对__shared__变量使用cudaMemcpy..Symbol操作。 为方便起见,为了保留类似于原始代码的东西,我选择将它们转换为__device__变量。

这是修改后的代码版本,修复了上述大部分问题:

 $ cat t978.cu #include  #include  #include  #define ITER_MAX 5000 #define SEED 35791246 __device__ int niter; __device__ int count; __global__ void calcularPi(){ double x; double y; double z; int lcount; curandState state; curand_init(SEED,threadIdx.x, 0, &state); //keep looping do{ lcount = atomicAdd(&niter, 1); //Generate random number x = curand_uniform(&state); y = curand_uniform(&state); z = x*x+y*y; if (z<=1) atomicAdd(&count, 1); }while(lcount < ITER_MAX); } int main(void){ float tempoTotal; //Start timer clock_t t; t = clock(); int count_final = 0; int niter_final = 0; cudaMemcpyToSymbol(niter, &niter_final, sizeof(int)); cudaMemcpyToSymbol(count, &count_final, sizeof(int)); //call kernel calcularPi<<<1,32>>>(); //wait while kernel finish cudaDeviceSynchronize(); cudaMemcpyFromSymbol(&count_final, count, sizeof(int)); cudaMemcpyFromSymbol(&niter_final, niter, sizeof(int)); //Ends timer double pi = count_final/(double)niter_final*4; t = clock() - t; tempoTotal = ((double)t)/CLOCKS_PER_SEC; printf("Pi: %g \n", pi); printf("Adds: %d \n", niter_final); printf("Total time: %f \n", tempoTotal); } $ nvcc -o t978 t978.cu -lcurand $ cuda-memcheck ./t978 ========= CUDA-MEMCHECK Pi: 3.12083 Adds: 5032 Total time: 0.558463 ========= ERROR SUMMARY: 0 errors $ 

我已经将迭代修改为更大的数字,但是如果你想要ITER_MAX ,你可以使用50。

请注意,可以针对此代码提出许多批评。 我的目标,因为它显然是一个学习练习,是指出使用你概述的算法获得function代码的最小变化次数。 仅举一个例子,您可能希望将内核启动配置( <<<1,32>>> )更改为其他更大的数字,以便更充分地利用GPU。