В настоящее время я работаю над проектом, подающим в суд на OpenCL на NVIDIA Tesla C1060 (версия драйвера 195.17). Однако у меня странное поведение, которое я не могу объяснить. Вот код, который озадачивает меня (сокращен для ясности и в целях тестирования):
kernel void TestKernel(global const int* groupOffsets, global float* result,
local int* tmpData, const int itemcount)
{
unsigned int groupid = get_group_id(0);
unsigned int globalsize = get_global_size(0);
unsigned int groupcount = get_num_groups(0);
for(unsigned int id = get_global_id(0); id < itemcount; id += globalsize, groupid += groupcount)
{
barrier(CLK_LOCAL_MEM_FENCE);
if(get_local_id(0) == 0)
tmpData[0] = groupOffsets[groupid];
barrier(CLK_LOCAL_MEM_FENCE);
int offset = tmpData[0];
result[id] = (float) offset;
}
}
Этот код должен загрузить смещение для каждой рабочей группы в локальную память, а затем прочитать его обратно и записать в соответствующую запись выходного вектора. Для большинства рабочих элементов это работает, но для каждой рабочей группы рабочие элементы с локальными идентификаторами с 1 по 31 читают неверное значение.
Мой выходной вектор (для рабочей группы = 128) выглядит следующим образом:
index 0: 0
index 1- 31: 470400
index 32-127: 0
index 128: 640
index 129-159: 471040
index 160-255: 640
index 256: 1280
index 257-287: 471680
index 288-511: 1280
...
результат, который я ожидал, будет
index 0-127: 0
index 128-255: 640
index 256-511: 1280
...
Странная вещь: проблема возникает только тогда, когда я использую меньше рабочих элементов itemcount (поэтому он работает, как и ожидалось, когда globalsize> = itemcount, то есть каждый рабочий элемент обрабатывает только одну запись). Я предполагаю, что это как-то связано с циклом.
Кто-нибудь знает, что я делаю не так и как это исправить?
Обновление:
Я обнаружил, что, кажется, работает, если я изменяю
if(get_local_id(0) == 0)
tmpData[0] = groupOffsets[groupid];
до
if(get_local_id(0) < 32)
tmpData[0] = groupOffsets[groupid];
Что удивляет меня еще больше, поэтому, хотя это может решить проблему, я не чувствую себя комфортно, решая ее таким образом (поскольку это может сломать в другой раз).
Кроме того, я бы предпочел не терять производительность при работе на оборудовании класса Geforce 8xxx из-за дополнительных (не связанных с этим оборудованием, насколько я понимаю) обращений к памяти.
Таким образом, вопрос все еще остается.