#c #multithreading #memory #kernel #opencl
#c #многопоточность #память #ядро #opencl
Вопрос:
Я столкнулся с этой очень странной проблемой при работе с OpenCL C . Проблема в том, что у меня есть 100 потоков, которые обращаются к одному элементу каждого из массива размером 100. От 0 до 63 проблем нет, и каждый поток правильно вычисляет и обновляет значение элемента массива. Но когда он попадает в поток 64, он запутывается и обновляет значения некоторыми другими значениями…
Вот как я вызываю ядро:
kernelGA(cl::EnqueueArgs(queue[iter],
cl::NDRange(200 / numberOfDevices)),
d_value,
d_doubleParameters,
buf_half_population, and so on...)
На стороне ядра я обращаюсь к каждому потоку с помощью:
__kernel void kernelGA (__global double * value,
__global double * doubleParameters,
__global double * population,
__global double * scores, and so on...)
int idx = get_global_id(0); // This gives me 100 threads for each device. (I have two devices)
int size_a = 50;
double tempValue[size_a];
// Copying the global "value" into local array so each thread has its own copy.
for (int i = 0; i < size_a; i ) {
tempValue[i] = value[i];
}
На данный момент каждый поток теперь имеет свой собственный массив tempValue[] с теми же значениями. Затем я применяю некоторые вычисления и формулы к значениям массива tempValue[] для каждого потока…
// Applying some computations on tempValue and changing the values for each copy of tempValue for each thread.
tempValue[i] = some calculations for each thread...
После этого я получаю доступ к каждому элементу массива tempValue[] для каждого потока и непрерывно помещаю их обратно в массив большего размера (количество потоков * size_a). Имея в виду, что индексация для массива выглядит следующим образом: 0,1, 2, 3, … и так далее…
for (int i = 0; i < size_a; i ) {
totalArray[(idx * size_a) i] = tempvalue[i];
}
Поэтому, когда я получаю ответы totalArray вне ядра и печатаю их, первые 64 (из 0-63) потоков правильно поместили свои значения в totalArray[] . Но начиная с 64 года индексация нарушена. Я имею в виду не совсем индексацию, потому что я распечатал только индексы, и к индексам правильно обращаются для всех потоков. Но значения, похоже, перепутаны…
Например: значение 3-го, 4-го, 5-го и 6-го элементов потока 0-63 равно 50, 60, 70 и 80 соответственно. Но для потока 64 и далее значения 3-го, 4-го, 5-го и 6-го элементов равны 80, 90, 100, 110. Как будто значения были сдвинуты на несколько элементов в обратном направлении. Почему? Что здесь происходит?
Ответ №1:
Существует проблема, если несколько устройств работают с одним и тем же массивом,
Вы помещаете
cl::NDRange(200 / numberOfDevices)
как диапазон
но вы не помещаете
cl::NDRange((200 / numberOfDevices)*deviceIndex)
как смещение для каждого устройства.
Все устройства пытаются выполнить запись в одну и ту же позицию вместо соседних групп.
Также вы не проверяете, если общее количество потоков меньше длины массива в ядре, поэтому некоторые потоки могут попытаться записать за пределы.
Комментарии:
1. Как проверить, меньше ли общее количество потоков, чем длина массива?
Ответ №2:
Итак, я нашел решение своей проблемы:
Проблема заключалась в том, что, хотя у каждого потока была своя собственная копия value[]
массива, хранящаяся в tempValue[]
array:
// Copying the global "value" into local array so each thread has its own copy.
for (int i = 0; i < size_a; i ) {
tempValue[i] = value[i];
}
Значения в массиве были перепутаны после потока 64. Итак, что я сделал, я создал больший массив значений снаружи в коде хоста ( sizeOf(value) * 100
), а затем скопировал первую часть массива в остальные 99 частей и отправил его на устройство. А затем я заставил каждый поток обращаться к своей части массива value [] с помощью индексации.
Это решило проблему!