Что именно делает #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 из них при развертывании цикла?


person Magzhan Abdibayev    schedule 09.03.2014    source источник
comment
Нет. Это означает, что вы вызвали ядро ​​CUDA с одним блоком, и этот блок имеет 100 активных потоков. Вы передаете size в качестве второго параметра функции вашему ядру. В вашем ядре каждый из этих 100 потоков выполняет цикл for 100 раз. Я советую вам начать изучение CUDA с основ и двигаться постепенно, а не переходить к более сложным или менее важным материалам, таким как развертывание циклов.   -  person Farzad    schedule 09.03.2014
comment
@Farsad, спасибо, не могли бы вы объяснить, что делает #pragma unroll? я думаю, что я мог бы выполнить цикл без использования прагмы?   -  person Magzhan Abdibayev    schedule 09.03.2014


Ответы (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 используется позже). Еще одним преимуществом развертывания цикла является улучшение параллелизма на уровне инструкций (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 в вашем коде (объяснено здесь).

person Farzad    schedule 09.03.2014
comment
И в основном потому, что это убивает производительность параллельных вычислений. потому что перекосы потоков не параллельны, когда это условие ветвления, которое предлагает любому потоку в блоке отклониться от другого пути инструкций и аннулирует архитектуру SIMT, которая представляет собой 1 инструкцию (регистр?), Выполняемую только всеми потоками в warp @ в то же время и в том же месте, он же параллельный - person yan bellavance; 17.07.2017
comment
@RobertCrovella Зачем нам нужно явно добавлять эту прагму? Разве компилятор не может сам распознать такие циклы? - person z0lupka; 26.05.2021
comment
Я нигде не говорил, что вы должны были явно добавить эту прагму. Я просто дал ссылку на соответствующий раздел в документации, чтобы у других была ссылка на документацию. Если вы нажмете на эту ссылку и прочитаете самое первое предложение, у вас будет ответ на ваш вопрос. - person Robert Crovella; 26.05.2021