打破开销与控制标志

时间:2012-11-05 16:38:34

标签: performance cuda

我正在使用一个天真的素数生成函数。这段代码需要大约5.25秒来生成10k素数(device_primes [0]保存已经找到的数字素数,其余位置是素数找到的。)

_global__ void getPrimes(int *device_primes,int n)
{ 
    int c = 0;
    int thread_id = blockIdx.x * blockDim.x + threadIdx.x;
    int num = thread_id+2;

    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       
    }
}

我刚刚开始优化代码,我做了以下修改,而不是:

for (c = 2; c <= num - 1; c++)
{ 
    if (num % c == 0) //not prime
         break;
}
 if (c == num) {...}
我现在有:

   int prime = 1;

   ...
   for (c = 2; c <= num - 1 && prime; c++)
    { 
        if (num % c == 0) prime = 0; // not prime
    }
     if (prime) {...} // if prime

现在我可以在0.707s中产生10k。我只是想知道为什么这么简单的修改加速,是打破那么糟糕?

1 个答案:

答案 0 :(得分:2)

正如Tony所说,不同的代码执行会导致gpu代码大幅减速,迫使某些代码以串行而非并行的方式运行。在上面代码的慢速版本中,中断的线程与继续的代码不同。

cuda c programming guide是gpu编程技术的优秀资源。 Here is what it says about control flow

  

任何流控制指令(if,switch,do,for,while)都可以通过使相同warp的线程发散(即遵循不同的执行路径)来显着影响有效指令吞吐量。如果发生这种情况,则必须序列化不同的执行路径,从而增加为此warp执行的指令总数。当所有不同的执行路径都完成后,线程会聚回到相同的执行路径。

较新的nvidia硬件和cuda版本可以比旧版本更好地处理一些分支,但是最好尽可能避免分支。