2011-12-31 5 views
3

У меня есть ядро, которое для каждого потока в данном блоке вычисляет цикл for с другим числом итераций. Я использую буфер размером N_BLOCKS для хранения количества итераций, необходимых для каждого блока. Следовательно, каждый поток в данном блоке должен знать количество итераций, специфичных для его блока.Как распределить общее значение между потоками в заданном блоке?

Однако я не уверен, какой путь является лучшим (говорящий по производительности), чтобы прочитать значение и распространить его на все другие потоки. Я вижу только один хороший способ (скажите, пожалуйста, если что-то лучше): сохраните значение в общей памяти и прочитайте каждый поток. Например:

__global__ void foo(int* nIterBuf) 
{ 
    __shared__ int nIter; 

    if(threadIdx.x == 0) 
     nIter = nIterBuf[blockIdx.x]; 

    __syncthreads(); 

    for(int i=0; i < nIter; i++) 
     ... 
} 

Другие лучшие решения? Мое приложение будет использовать множество данных, поэтому я хочу получить лучшую производительность.

Спасибо!

+0

Выглядит хорошо для меня. –

+0

Что делать, если я скопировал общую переменную в локальную переменную? Тем не менее, я чувствую, что, если я использую его только один раз в цикле for, это не стоит. По-прежнему существует конфликт банков в общей памяти, необходимый для копирования значения в локальную память. –

+0

Да, вы можете сохранить его в реестре. Не уверен, что это будет действительно быстрее, плюс он использует регистр. И нет там никакого банковского конфликта, так как все потоки читаются с одного и того же адреса. –

ответ

5

Значения, доступные только для чтения, для всех потоков в блоке, вероятно, лучше всего хранятся в массивах __constant__. На некоторых архитектурах CUDA, таких как Fermi (SM 2.x), если вы объявляете аргумент массива или указателя, используя ключевое слово C++ const, и вы равномерно распределяете его по блоку (то есть индекс зависит только от blockIdx, а не от threadIdx), то компилятор может автоматически продвигать ссылку на постоянную память.

Преимущество постоянной памяти заключается в том, что она проходит через выделенный кеш, поэтому она не загрязняет L1, и если количество данных, к которым вы обращаетесь на один блок, относительно невелико, после первого доступа в каждом блоке, вы должны всегда попадать в кеш после первоначального обязательного промаха в каждом потоковом блоке.

Вам также не нужно использовать какую-либо общую память или переводить из глобальной в общую память.

+0

Вау, очень проницательный. Благодаря!! –

2

Если моя информация обновлена, разделяемая память является второй самой быстрой памятью, уступающей только регистрам.

Если вы читаете эти данные из разделяемой памяти, каждая итерация замедляет вас, и вы все еще имеете доступные регистры (см. Вычислительные возможности и спецификации вашего GPU), возможно, вы попытаетесь сохранить копию этого значения в каждом регистре потока (используя локальная переменная).

+0

+1 Я думаю, это единственный возможный ответ. –

+0

Итак, лучше всего было бы читать из глобальной памяти, хранить в общей памяти, а затем копировать в регистр. Или я должен пропустить общую память? В конце концов, я не вижу объединенного чтения. –

+0

Либо a) читать из глобального для регистрации, либо b) использовать решение, которое вы опубликовали. * * Коалесцированное чтение, проверьте руководство CUDA. –

Смежные вопросы