2016-11-19 7 views
0

У меня есть простое ядро, как это:Запись на индекс массива работает только для последней задачи в очереди

__kernel void cycle(__global int * grid, int idx) { 
    grid[idx] = idx; 
} 

и я бегу clEnqueueTask() внутри цикла следующим образом:

for (int i = 0; i < size; i++) { 
    int arg = i; 
    clSetKernelArg(kernel_id, 1, &arg); 
    clEnqueueTask(command_queue, kernel_id, 0, NULL, NULL); 
} 

Ожидаемый результат массив [0 ...size - 1], но он устанавливает только последний индекс с соответствующим значением. Остальные остаются по умолчанию (в моем случае 0).

Я попытался накапливая значение параметра idx в первой ячейке массива (grid[0] += idx), и он дал мне ожидаемую сумму целых чисел от 1 до size - 1, поэтому параметр получает правильно принят и задачи выполнены правильно.

Любая помощь приветствуется!

+0

Я закончил использование 'clEnqueueNDRangeKernel', который хорошо работает. Все еще не уверен, почему параллелизм задач не работает в этом случае. 'clEnqueueTask' отмечен как устаревший на OpenCL, реализованный Intel, но я не уверен, что имеет какое-либо отношение к проблеме – Lev

ответ

1

Возможное предложение о причине вашего вопроса:

arg целое имеет тот же адрес в памяти во время полного цикла; при передаче его в ядро ​​CL вы передаете адрес (вместо копии значения), и, таким образом, значение изменяется каждый раз для всех экземпляров.

Это предполагает, однако, что все значения массива сетки равны одному, последнему, значению, а не нолю, кроме последнего.

Почему это работает при расчете суммы? Мое предположение заключается в том, что вы не храните отдельные значения внутри массива grid (который необходимо сохранить после завершения ядра и чтения данных); вместо этого значение добавляется и присваивается grid[0], а значение в grid[0] не зависит от idx.

Правда, это несколько расплывчатое и включает в себя некоторые догадки, но вот что-то вы можете попробовать:

for (int i = 0; i < size; i++) { 
    int *arg = malloc(sizeof(*arg)); 
    *arg = i; 
    clSetKernelArg(kernel_id, 1, arg, sizeof(*arg)); 
    clEnqueueTask(command_queue, kernel_id, 0, NULL, NULL); 
} 

(По какой-то причине, ваш пример не имеет size аргумент clSetKernelArg, не знает, почему.) Очевидно, что вы обычно выделяли arg в виде массива размером size, вместо того, чтобы раскладывать его на каждую итерацию, но давайте сохраним этот пример.

Если это работает, вы можете поиграть, чтобы узнать, в какой момент вы можете freearg, потому что вышеизложенное является утечкой памяти. И я сомневаюсь, что вы можете освободить arg внутри цикла.