Многопоточность для цикла по cuda - PullRequest
0 голосов
/ 13 октября 2018

Я хотел бы создать цикл for, который проверяет значение 2 ^ 41 с помощью cuda.Я написал этот фрагмент кода, но он тестирует один и тот же ключ несколько раз, но я хотел бы протестировать его только один раз, и я не знаю почему.

__global__ void kernel(int fileSize, unsigned char * buffer)
{
   for(mot64 i3 = 0L; i3 < (1L << 41); i3++){
     deCipher(buffer, i3, fileSize);
   }
   return;
}

Спасибо за вашу помощь:)

1 Ответ

0 голосов
/ 13 октября 2018

Вы, похоже, не совсем понимаете основы того, как работают массивно параллельные вычисления на GPU, поэтому я постараюсь дать вам "быстрое" объяснение того, что происходит.Но на самом деле вы захотите прочитать хорошую книгу об этом, потому что это массивная и сложная тема.

Запуская ядро ​​в CUDA, вы запускаете его для работы в определенном количестве потоков, напримерthis:

kernel<<<blocks, threads>>>(fileSize, buffer);

Это означает, что функция будет работать с указанным числом blocks, а каждый блок имеет определенное количество threads, всего blocks*threads потоков.

Чтобы по-настоящему понять, что это значит, вам нужно прочитать какую-нибудь книгу о CUDA и что такое сетки, блоки и потоки.Простое объяснение состоит в том, что функция запускается на «grid».Это "grid" разделено на "blocks".Думайте об этих блоках как о виртуальных «ядрах» в процессоре.Не совсем правильно, но достаточно близко, чтобы иметь смутное представление о том, о чем мы говорим.Каждый «block» сам по себе делится на «threads».Каждая из этих «threads» выполняет вашу функцию независимо.Итак, теперь ваша функция запускает огромное количество экземпляров параллельно.Вы хотите, чтобы каждый экземпляр обращался к разной части вашего буфера.

Внутри вашего ядра вы хотите рассчитать, над каким потоком вы работаете, следующим образом:

int index = blockIdx.x * blockDim.x + threadIdx.x;
int stride = blockDim.x * gridDim.x;

Это изображениеочень важно.

Как видите, сетка двумерная, и эти два измерения удобно называть x и y.Подумайте о строках и столбцах.То, что index говорит вам, это то, где вы находитесь горизонтально на сетке.stride говорит вам, какова длина каждой строки, думайте об этом как о смещении.

Итак, внутри вашего ядра у вас будет такой цикл:

for (int i = index; i < sizeOfYourData; i += stride)
{
    // [...]
}

Это говорит вамименно с какой нитью вы работаете.Остальное тривиально.Переменная i теперь является вашим «идентификатором потока», вы можете использовать его в качестве смещения для вашего буфера, чтобы позволить каждому потоку обращаться к разной его части.

Так что вам нужно что-то вроде этого:

__global__ void kernel(int fileSize, unsigned char * buffer)
{
    int index = blockIdx.x * blockDim.x + threadIdx.x;
    int stride = blockDim.x * gridDim.x;

    for (int i3 = index; i3 < (1L << 41); i3 += stride)
    {
        deCipher(buffer, i3, fileSize);
    }

    return;
}
...