2015-01-19 3 views
-1

Я довольно новичок в CUDA и просто смущен о том, как это работает.Как работают параллельные вычисления CUDA?

Я создал простую пустоту для выполнения на графическом процессоре.

__global__ void Test (int *ch) { 


long i = blockIdx.x; 
ch[2] = i; 
long u = threadIdx.x; 
ch[3] = u; 

if (i < 640) 
{ 
    ch[0]++; 

    if (u < 480) 
    { 

    ch[1]++; 
    } 

} 

} 

Я назвал пустоту < < < 640480 >>>. Во всех учебниках я видел, что If заменяет «CPU» for-loop. Оригинальный "CPU-Пустота" выглядел следующим образом:

void Test (int *ch) { 

h_ch[2] = 640; 
h_ch[3] = 480; 

for(int a = 0;a < 640;a++) 
{ 
    ch[0]++; 

    for(int b = 0;b < 480;b++) 
    { 

    ch[1]++; 
    } 

} 

} 

Если я печатаю массив сп порожденную CPU я вижу что-то вроде этого: Ch [0] = 640 ч [1] = 307200 ч [2 ] = 640 ch [3] = 480, но что делает GPU?

Я получил следующие результаты: ch [0] = 1038 (значение менялось при каждом запуске!) Ch [1] = 1038 (похоже, ch [0]) ch [2] = 639 ch [3 ] = 31

Что происходит? Я предполагал получить те же результаты, что и на CPU.

Спасибо за ответы

Ниже приведен полный код: (Я просто хочу те же результаты) Вы можете выбрать CPU или GPU

#include "cuda_runtime.h" 
#include "device_launch_parameters.h" 

#include <stdio.h> 
#include <iostream> 

int *h_ch , *ch; 

__global__ void Test (int *ch) 
{ 

long i = blockIdx.x; 
ch[2] = i; 
long u = threadIdx.x; 
ch[3] = u; 

if (i < 640) 
{ 
    ch[0]++; 
    if (u < 480) 
    { 

    ch[1]++; 


    } 

} 

} 
void test (int *h_ch) 
{ 

h_ch[2] = 640; 
h_ch[3] = 480; 

for(int a = 0;a < 640;a++) 
{ 
h_ch[0]++; 

for(int b = 0;b < 480;b++) 
{ 

h_ch[1]++; 
} 

} 

} 
int main() 
{ 
h_ch = (int *)malloc(4*sizeof(int)); 
cudaMalloc((void **)&ch,4*sizeof(int)); 

h_ch[0] = 0; 
h_ch[1] = 0; 
h_ch[2] = 0; 
h_ch[3] = 0; 

cudaMemcpy(ch,h_ch,4*sizeof(int),cudaMemcpyHostToDevice); 

//Test<<<640,480>>>(ch); 
test(h_ch); 

//cudaMemcpy(h_ch,ch,4*sizeof(int),cudaMemcpyDeviceToHost); 

for(int i = 0;i < 4;i++) printf("%d ",h_ch[i]); 

int a; 
std::cin >> a; 

return 0; 
} 
+0

Просьба представить полный пример которые будут компилировать и включать информацию о вашем желаемом результате. –

+2

У вас есть несколько потоков, наступающих друг на друга, когда они пытаются обновить два местоположения 'ch [0]' и 'ch [1]'. В GPU несколько потоков выполняются параллельно. Когда все эти потоки пытаются обновить одно и то же место одновременно, возникает хаос. Если вы хотите, чтобы этот код работал правильно, замените обычные обновления (например, 'ch [1] ++;') на атомные обновления (например, 'atomicAdd (ch + 1, 1);' –

ответ

2

Есть несколько вопросов.

  1. У вас есть несколько потоков шаговых друг на друг, как они пытаются обновить два места ch[0] и ch[1]. В GPU несколько потоков выполняются параллельно. Когда все эти потоки пытаются обновить одно и то же место одновременно, возникает хаос. Если вы хотите увидеть этот код работает правильно, заменить обычные обновления (например ch[1]++;) с атомными обновлениями (например atomicAdd(ch+1, 1);

  2. Вашего код GPU и коды процессора не то же самое, логически. Ваш код GPU имеет каждый поток обновляет ch[0] и ch[1] один раз, поэтому конечные номера в этих местах должны быть соответственно 640 и 480, если проблема с номером в № 1. была исправлена. Но ваш код процессора имеет обновление ch[1], выполняемое в цикле, 480 раз для каждого обновления ch[0]. Мы могли бы исправить это, изменив код GPU как код процессора или наоборот, изменив код процессора как логический код графического процессора.

Следующий код имеет вышеуказанные 2 проблемы решены, изменяя код процессора, чтобы быть похожим на GPU, с ожидаемыми результатами 307200 в обоих ch[0] и ch[1] как для CPU и GPU:

$ cat t609.cu 
#include <stdio.h> 
#include <iostream> 

int *h_ch , *ch; 

__global__ void Test (int *ch) 
{ 

    long i = blockIdx.x; 
    long u = threadIdx.x; 

    if (i < 640) 
    atomicAdd(ch,1); 
    if (u < 480) 
    atomicAdd(ch+1,1); 
} 

void test (int *h_ch) 
{ 

    for(int a = 0;a < 640;a++) 
    for(int b = 0;b < 480;b++){ 
     h_ch[0]++; 
     h_ch[1]++;} 

} 
int main() 
{ 
    h_ch = (int *)malloc(4*sizeof(int)); 
    cudaMalloc((void **)&ch,4*sizeof(int)); 

    h_ch[0] = 0; 
    h_ch[1] = 0; 
    h_ch[2] = 0; 
    h_ch[3] = 0; 

    cudaMemcpy(ch,h_ch,4*sizeof(int),cudaMemcpyHostToDevice); 

    Test<<<640,480>>>(ch+2); 
    test(h_ch); 

    cudaMemcpy(h_ch+2,ch+2,2*sizeof(int),cudaMemcpyDeviceToHost); 

    for(int i = 0;i < 4;i++) printf("%d \n",h_ch[i]); 

    return 0; 
} 
$ nvcc -arch=sm_20 -o t609 t609.cu 
$ ./t609 
307200 
307200 
307200 
307200 
$ 
Смежные вопросы