Nik*_*a K 6 c++ for-loop cuda gpu nested
我是CUDA的新手.我试图并行化以下代码.现在它坐在内核上但根本没有使用线程,因此很慢.我尝试使用这个答案但到目前为止无济于事.
内核应该生成前n个素数,将它们放入device_primes数组中,稍后从主机访问该数组.代码是正确的,在串行版本中工作正常,但我需要加快速度,也许使用共享内存.
//CUDA kernel code
__global__ void generatePrimes(int* device_primes, int n)
{
//int i = blockIdx.x * blockDim.x + threadIdx.x;
//int j = blockIdx.y * blockDim.y + threadIdx.y;
int counter = 0;
int c = 0;
for (int num = 2; counter < n; num++)
{
for (c = 2; c <= num - 1; c++)
{
if (num % c == 0) //not prime
{
break;
}
}
if (c == num) //prime
{
device_primes[counter] = num;
counter++;
}
}
}
Run Code Online (Sandbox Code Playgroud)
我目前的,初步的,并且肯定是错误的尝试并行化这个看起来如下:
//CUDA kernel code
__global__ void generatePrimes(int* device_primes, int n)
{
int i = blockIdx.x * blockDim.x + threadIdx.x;
int j = blockIdx.y * blockDim.y + threadIdx.y;
int num = i + 2;
int c = j + 2;
int counter = 0;
if ((counter >= n) || (c > num - 1))
{
return;
}
if (num % c == 0) //not prime
{
}
if (c == num) //prime
{
device_primes[counter] = num;
counter++;
}
num++;
c++;
}
Run Code Online (Sandbox Code Playgroud)
但是这段代码使用没有意义的数据填充数组.此外,许多值都是零.在此先感谢您的任何帮助,我们对此表示赞赏.
您的代码中存在一些问题,例如:
int num = i + 2;
Run Code Online (Sandbox Code Playgroud)
该表达式分配给thread 0
交互 2、thread 1
迭代 3,依此类推。问题在于线程将计算的下一次迭代基于表达式num++;
。因此,thread 0
接下来将计算迭代 3,该迭代已经由 计算thread 1
。因此,导致冗余计算。此外,我认为对于这个问题,仅使用一维而不是二维会更容易(x,y)
。因此,考虑到这一点,您必须更改num++
为:
num += blockDim.x * gridDim.x;
Run Code Online (Sandbox Code Playgroud)
另一个问题是您没有考虑到变量counter
必须在线程之间共享。否则,每个线程将尝试查找“n”个素数,并且所有这些素数都将填充整个数组。所以你必须更改int counter = 0;
为共享或全局变量。让我们使用一个全局变量,以便它可以在所有块的所有线程中可见。我们可以使用数组的零位置device_primes
来保存变量counter
。
您还必须初始化该值。让我们将这项工作仅分配给一个线程,即 id = 0 的线程,因此:
if (thread_id == 0) device_primes[0] = 1;
Run Code Online (Sandbox Code Playgroud)
然而,这个变量是全局的,它会被所有线程写入。因此,我们必须保证所有线程在写入该全局变量之前都会看到该变量counter
为 1(device_primes
带质数的第一个位置,零代表counter
),因此您还必须在最后添加一个屏障,因此:
if (thread_id == 0)
device_primes[0] = 1;
__syncthreads()
Run Code Online (Sandbox Code Playgroud)
因此,一种可能的解决方案(尽管效率低下):
__global__ void getPrimes(int *device_primes,int n)
{
int c = 0;
int thread_id = blockIdx.x * blockDim.x + threadIdx.x;
int num = thread_id;
if (thread_id == 0) device_primes[0] = 1;
__syncthreads();
while(device_primes[0] < n)
{
for (c = 2; c <= num - 1; c++)
{
if (num % c == 0) //not prime
{
break;
}
}
if (c == num) //prime
{
int pos = atomicAdd(&device_primes[0],1);
device_primes[pos] = num;
}
num += blockDim.x * gridDim.x; // Next number for this thread
}
}
Run Code Online (Sandbox Code Playgroud)
下面这行atomicAdd(&device_primes[0], 1);
基本上会执行device_primes[0]++;
。我们使用原子操作是因为变量counter
是全局的并且我们需要保证互斥。请注意,您可能必须使用flag -arch sm_20
.
优化:就代码而言,最好使用较少/不同步的方法。此外,通过考虑素数的一些属性也可以减少计算量,如http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes中所示。