Падение производительности в программе CUDA, которая неоднократно вызывает ядро ​​в цикле for - PullRequest
3 голосов
/ 05 января 2012

У меня есть программа CUDA, которая неоднократно вызывает ядро ​​в цикле for.Код вычисляет все строки матрицы, используя значения, вычисленные в предыдущей, до тех пор, пока не будет выполнена вся матрица.Это в основном алгоритм динамического программирования.Код ниже заполняет запись (i, j) многих отдельных матриц параллельно с ядром.

for(i = 1; i <=xdim; i++){

  for(j = 1; j <= ydim; j++){ 

    start3time = clock();
    assign5<<<BLOCKS, THREADS>>>(Z, i, j, x, y, z)
    end3time = clock(); 
    diff = static_cast<double>(end3time-start3time)/(CLOCKS_PER_SEC / 1000); 
    printf("Time for i=%d j=%d is %f\n", i, j, diff); 
  }

}

Назначение ядра 5 простое

__global__ void assign5(float* Z, int i, int j, int x, int y, int z) {

  int id = threadIdx.x + blockIdx.x * blockDim.x;

  char ch = database[j + id];

  Z[i+id] = (Z[x+id] + Z[y+id] + Z[z+id])*dev_matrix[i][index[ch - 'A']];

  }

}

Моя проблема в том, что когда яЗапустите эту программу, время для каждого i и j большую часть времени равно 0, но иногда это 10 миллисекунд.Таким образом, результат выглядит как

Time for i=0 j=0 is 0
Time for i=0 j=1 is 0
.
.
Time for i=15 j=21 is 10
Time for i=15 j=22 is 0
.

Я не понимаю, почему это происходит.Я не вижу условия гонки нити.Если я добавлю

if(i % 20 == 0) cudaThreadSynchronize();

сразу после первого цикла, тогда Время для i и j будет в основном 0. Но тогда время для синхронизации иногда составляет 10 или даже 20. Кажется, что CUDA выполняет много операций внизкая стоимость, а затем взимает много за более поздние.Любая помощь будет оценена.

1 Ответ

6 голосов
/ 07 января 2012

Я думаю, что у вас неправильное представление о том, что на самом деле вызывает ядро ​​в CUDA на хосте.Вызов ядра не блокирует и добавляется только в очередь устройства.Если вы измеряете время до и после вызова ядра, то разница не имеет никакого отношения к тому, сколько времени занимает вызов ядра (он будет измерять время, необходимое для добавления вызова ядра в очередь).

Вы должны добавить cudaThreadSynchronize () после каждого вызова ядра и перед измерением end3time.cudaThreadSynchronize () блокирует и возвращает, если все ядра в очереди завершили свою работу.

Вот почему

if(i % 20 == 0) cudaThreadSynchronize();

сделал пики в ваших измерениях.

...