Вы, похоже, не совсем понимаете основы того, как работают массивно параллельные вычисления на 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;
}