2013-11-01 3 views
0

Я собираюсь написать ядро ​​гистограммы для устройств CUDA. Он основан на NVIDIA's paper.Константа для цикла дает неверный результат

Идея состоит в том, что каждая нить вычисляет частичную гистограмму определенной части (в моем случае тома) и записывает ее в блок разделяемой памяти. Тем не менее, я столкнулся странные проблемы с алгоритмом и урезанная ядра до значительных частей:

__global__ void calcHist64() 
{ 
    extern __shared__ unsigned char partialHistograms[]; 

    //a unique sequential thread id within this block, used to determine the memory in which to write the partial histogram 
    unsigned int seqTid = threadIdx.x + threadIdx.y * blockDim.x;  
#pragma unroll 
    for(int i = 0; i < 255; ++i) 
    { 
     //increment the thread's partial histogram value 
     partialHistograms[seqTid]++; 
    } 
    //each partial histogram should now be 255 
    //Output the value for every thread in a certain block 
    if(blockIdx.x == 0 && blockIdx.y == 31) 
     printf("Partial[%i][%i]: %i\n", threadIdx.x, threadIdx.y, partialHistograms[partialHistRoot]); 
} 

Ядро вызывается через:

int sharedMemory = 4096; 
dim blocks(32, 32, 1); 
dim3 threadsPerBlock(8,8,1); 
calcHist64<<<blocks, threadsPerBlock, sharedMemory>>>(); 

Я ожидаю, что каждый частичный гистограмму иметь значение 255. Однако это справедливо только для первых блоков (низкий blockIdx.x/blockIdx.y). Значения для других блоков сильно различаются. Последние блоки (blockIdx.y == 31) имеют значения 239 или 240.

Я не могу объяснить это поведение. Это константа для цикла, которая выполняется ровно 255 раз. Каждый поток обращается к различным частям разделяемой памяти, поэтому не должно быть никаких условий гонки.

Может ли кто-нибудь объяснить это поведение?

+0

Я не знаю, так ли это, но, возможно, это проблема с различными процессорными ядрами, хранящими старые значения в кеше. Последний, чтобы очистить кеш в памяти, может иметь старые значения для некоторых из блоков в 'partialHistograms' - и это объясняет, почему затронуты последние блоки (первые блоки были с 255 так долго, что они уже были распространены в каждый кеш) , Вы пытались использовать мьютексы или что-то подобное внутри цикла 'for'? Я не могу думать о какой-либо другой проблеме с этим кодом. –

ответ

3

Вы не инициализируете общую память. Он автоматически не инициализируется нулем для вас.

После этой строки кода:

unsigned int seqTid = threadIdx.x + threadIdx.y * blockDim.x; 

Добавить это:

partialHistograms[seqTid] = 0; 

Также в вашем коде вы не определяете partialHistRoot. Я предполагаю, что partialHistRoot == seqTid. Если это не так, у вас есть условие гонки и ваше заявление

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

Неправильная версия.

+0

Ах, конечно. Глупая ошибка. Он просто работал без инициализации. Вот почему я забыл об этом. 'partialHistRoot' больше не должно быть в вопросе. Он равен 'seqTid'. –

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