首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >CUDA并行化嵌套的for循环

CUDA并行化嵌套的for循环
EN

Stack Overflow用户
提问于 2012-11-04 10:53:06
回答 1查看 7.1K关注 0票数 6

我是CUDA新手。我正在尝试并行化以下代码。现在它位于内核上,但根本没有使用线程,因此速度很慢。我试着用这个answer但到目前为止都无济于事。

内核应该生成前n个素数,并将它们放入设备中。_primes数组,然后从主机访问此数组。代码是正确的,并且在串行版本中运行良好,但我需要加快速度,可能需要使用共享内存。

代码语言:javascript
运行
复制
//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++;
    }
}
}

我目前,初步的,绝对错误的并行化尝试如下所示:

代码语言:javascript
运行
复制
//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++;
}

但是这段代码用没有意义的数据填充数组。此外,许多值都是零。提前感谢您的帮助,非常感谢。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-11-05 03:35:50

您的代码中存在一些问题,例如:

代码语言:javascript
运行
复制
int num = i + 2;

此表达式将赋值给thread 0交互2,到thread 1迭代3,以此类推。问题是线程将计算的下一次迭代是基于表达式num++;。因此,thread 0下一步将计算迭代3,该迭代已经由thread 1。因此,导致冗余计算。此外,我认为对于这个问题,只使用一个维度会比使用两个维度更容易(x,y)。因此,考虑到这一点,你必须改变num++至:

代码语言:javascript
运行
复制
num += blockDim.x * gridDim.x;

另一个问题是您没有考虑到变量counter必须在线程之间共享。否则,每个线程将尝试查找'n‘个素数,所有这些素数都将填充整个数组。所以你必须改变int counter = 0;设置为共享或全局变量。让我们使用一个全局变量,这样它就可以在来自所有块的所有线程中可见。我们可以使用数组的位置零device_primes保存变量counter

您还必须初始化此值。让我们只将这个任务分配给一个线程,即` `id = 0的线程,因此:

代码语言:javascript
运行
复制
if (thread_id == 0) device_primes[0] = 1;

但是,这个变量是全局的,它将由所有线程写入。因此,我们必须保证所有线程在写入该全局变量之前,都会看到该变量counter是1(第一个位置device_primes对于素数,0表示counter),所以你必须在最后添加一个屏障,所以:

代码语言:javascript
运行
复制
if (thread_id == 0) 
    device_primes[0] = 1;
__syncthreads()

因此,一个可能的解决方案(尽管效率很低):

代码语言:javascript
运行
复制
__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

优化:在代码方面,最好使用同步较少/没有同步的方法。此外,还可以通过考虑素数的一些属性来减少计算量,如

http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes.

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13215614

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档