我是CUDA新手。我正在尝试并行化以下代码。现在它位于内核上,但根本没有使用线程,因此速度很慢。我试着用这个answer但到目前为止都无济于事。
内核应该生成前n个素数,并将它们放入设备中。_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++;
}
}
}
我目前,初步的,绝对错误的并行化尝试如下所示:
//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++;
}
但是这段代码用没有意义的数据填充数组。此外,许多值都是零。提前感谢您的帮助,非常感谢。
发布于 2012-11-05 03:35:50
您的代码中存在一些问题,例如:
int num = i + 2;
此表达式将赋值给thread 0
交互2,到thread 1
迭代3,以此类推。问题是线程将计算的下一次迭代是基于表达式num++;
。因此,thread 0
下一步将计算迭代3,该迭代已经由thread 1
。因此,导致冗余计算。此外,我认为对于这个问题,只使用一个维度会比使用两个维度更容易(x,y)
。因此,考虑到这一点,你必须改变num++
至:
num += blockDim.x * gridDim.x;
另一个问题是您没有考虑到变量counter
必须在线程之间共享。否则,每个线程将尝试查找'n‘个素数,所有这些素数都将填充整个数组。所以你必须改变int counter = 0;
设置为共享或全局变量。让我们使用一个全局变量,这样它就可以在来自所有块的所有线程中可见。我们可以使用数组的位置零device_primes
保存变量counter
。
您还必须初始化此值。让我们只将这个任务分配给一个线程,即` `id = 0的线程,因此:
if (thread_id == 0) device_primes[0] = 1;
但是,这个变量是全局的,它将由所有线程写入。因此,我们必须保证所有线程在写入该全局变量之前,都会看到该变量counter
是1(第一个位置device_primes
对于素数,0表示counter
),所以你必须在最后添加一个屏障,所以:
if (thread_id == 0)
device_primes[0] = 1;
__syncthreads()
因此,一个可能的解决方案(尽管效率很低):
__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
}
}
下面这行atomicAdd(&device_primes[0], 1);
基本上都会执行device_primes[0]++;
。我们使用原子操作是因为变量counter
是全球性的,我们需要保证相互排斥。注意,您可能必须使用flag -arch sm_20
。
优化:在代码方面,最好使用同步较少/没有同步的方法。此外,还可以通过考虑素数的一些属性来减少计算量,如
https://stackoverflow.com/questions/13215614
复制相似问题