2013-07-08 48 views
0

我想要確定x^2 + 1格式有多少個素數,其中1 < = x < = 10^7。我只是想將它與CUDA並行化並檢查差異,因此我使用了平凡的素數檢查,並且我不關心改進算法。通過更改線程數來更改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; 
} 

回答

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

隨氮素= 100000運行你的代碼,總的執行時間爲1.5秒,我M2050 GPU。 N = 1000000時,執行時間約爲75秒。有N = 10000000這就是你的執行時間是非常多長。

+0

沒錯。謝謝 – saeedn