通过更改线程数来更改CUDA代码输出的说明

时间:2013-07-08 23:51:28

标签: cuda nvidia

我想确定形式x ^ 2 + 1是多少个素数,1 <= x <= 10 ^ 7。我只想将它与CUDA并行化并检查差异,所以我使用了普通的素数检查,而我并不关心改进它的算法。

我安排了一个网格,并将其放在我的间隔上,将结果记录在每个块的共享内存中,对每个块上的gpu执行减少,最后执行cpu减少以获得最终结果。

我的问题是当我更改每个块中的块数和线程数时,输出结果会发生变化。我无法解释的另一件事是,对于每个块8个块和2048个线程的配置,代码运行在100ms以下,但是当我将线程数减少到1024并且块数增加一倍时,代码将导致超时在memcpy从设备到主机!!我怎样才能解释这种行为以及正确性在哪里出现问题?

我正在使用GTX 480 nvidia gpu。

我的代码是:

#include <stdio.h>
static void HandleError( cudaError_t err, const char *file, int line )
{
    if (err != cudaSuccess) {
        printf( "%s in %s at line %d\n", cudaGetErrorString( err ), file, line );
        exit( EXIT_FAILURE );
    }
}

#define HANDLE_ERROR( err ) (HandleError( err, __FILE__, __LINE__ ))
#define N 10000000
#define BLOCKS 8
#define THREADS 2048

__device__ int isprime(int x)
{
    long long n = (long long)x*x + 1;
    for( int p=3; p<=x+1; p+=2 )
        if ( n % p == 0 ) return 0;
    return 1;
}

__global__ void solve(int n, int* result)
{
    __shared__ int ipc[THREADS];

    int tid = threadIdx.x;
    int x = blockIdx.x*blockDim.x + threadIdx.x + 2;

    // sliding grid window over interval of to-be-computed data
    int acc = 0;
    while( x <= n )
    {
        if ( isprime(x) ) acc++;
        x += blockDim.x*gridDim.x;
    }
    ipc[tid] = acc;
    __syncthreads();


    // reduction over each block in parallel
    for( int s=blockDim.x/2; s>0; s>>=1 )
    {
        if ( tid < s )
        {
            ipc[tid] += ipc[tid+s];
        }
        __syncthreads();
    }

    if ( tid == 0 ) result[blockIdx.x] = ipc[0];
}

int main()
{
    int *dev;
    int res[BLOCKS];

    int ans = 0;

    HANDLE_ERROR( cudaMalloc((void**)&dev, BLOCKS * sizeof(int)) );

    solve<<<BLOCKS, THREADS>>>(N, dev);

    HANDLE_ERROR( cudaMemcpy(res, dev, BLOCKS*sizeof(int), cudaMemcpyDeviceToHost) );

    // final reduction over results for each block
    for( int j=0; j<BLOCKS; j++ )
        ans += res[j];

    printf("ans = %d\n", ans);

    HANDLE_ERROR( cudaFree( dev ) );
    return 0;
}

1 个答案:

答案 0 :(得分:5)

在任何当前的GPU上,您无法在每个块上运行2048个线程:

#define THREADS 2048
...
solve<<<BLOCKS, THREADS>>>(N, dev);
                  ^
                  |
                2048 is illegal here

你没有在内核调用上做正确的cuda error checking,所以你的代码不会告诉你这个错误正在发生。

因此,在每个块2048个线程的情况下,你的内核甚至没有执行(你的结果应该是假的。)

如果将线程切成两半,则超时可能是由于内核执行时间太长而导致windows TDR mechanism启动。

我尝试使用BLOCKS = 16和THREADS = 1024

运行代码

当N = 100000时,我的M2050 GPU上的总执行时间约为1.5秒。 N = 1000000时,执行时间约为75秒。当你拥有N = 10000000时,执行时间非常长。