Что делает #pragma unroll? Это влияет на количество потоков?

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

__global__ void kernel(float *b, int size)
{
    int tid = blockDim.x * blockIdx.x + threadIdx.x;
 #pragma unroll
    for(int i=0;i<size;i++)
        b[i]=i;
}

Выше моя функция ядра. В main я называю это ниже

int main()
{
    float * a; //host array
    float * b; //device array
    int size=100;

    a=(float*)malloc(size*sizeof(float));
    cudaMalloc((float**)&b,size);
    cudaMemcpy(b, a, size, cudaMemcpyHostToDevice);

    kernel<<<1,size>>>(b,size); //size=100

    cudaMemcpy(a, b, size, cudaMemcpyDeviceToHost);

    for(int i=0;i<size;i++)
        cout<<a[i]<<"\t";

    _getch();

    return 0;
}

Означает ли это, что у меня есть size * size= 10000 потоков, выполняющихся для выполнения программы? 100 из них созданы, когда цикл развернут?

Ответ 1

Нет. Это означает, что вы вызвали ядро ​​CUDA с одним блоком, и один блок имеет 100 активных потоков. Вы передаете размер в качестве второго параметра функции в ядро. В вашем ядре каждый из этих 100 потоков выполняет цикл for 100 раз.

#pragma unroll - это оптимизация компилятора, которая может, например, заменить фрагмент кода, например

for ( int i = 0; i < 5; i++ )
    b[i] = i;

с

b[0] = 0;
b[1] = 1;
b[2] = 2;
b[3] = 3;
b[4] = 4;

поместив директиву #pragma unroll прямо перед циклом. Хорошая вещь в развернутой версии заключается в том, что она требует меньших вычислительных нагрузок для процессора. В случае версии цикла for обработка, помимо назначения каждого i до b[i], включает инициализацию i, оценивая i<5 в 6 раз и увеличивая i в 5 раз. В то время как во втором случае он включает только заполнение содержимого массива b (возможно, плюс int i=5;, если i используется позже). Еще одним преимуществом разворачивания цикла является повышение уровня инструкций Parallelism (ILP). В развернутой версии, возможно, будет больше операций для того, чтобы процессор входил в конвейер обработки, не беспокоясь о состоянии цикла for на каждой итерации.

Сообщения, подобные этим, объясняют, что разворот цикла выполнения не может произойти для CUDA. В вашем случае компилятор CUDA не имеет никаких подсказок, что size будет равным 100, поэтому разворачивание цикла цикла компиляции не произойдет, и, если вы принудительно разворачиваете, вы можете повредить производительность.

Если вы уверены, что size равно 100 для всех исполнений, вы можете развернуть свой цикл, как показано ниже:

#pragma unroll
for(int i=0;i<SIZE;i++)  //or simply for(int i=0;i<100;i++)
    b[i]=i;

в котором size известно во время компиляции с #define SIZE 100.

Я также предлагаю вам иметь правильную проверку ошибок CUDA в вашем коде (объяснил здесь).