2013-02-19 4 views
1

Мне нужно переместить каждый из первых k элементов 1-D массива на смещение , где смещения монотонно возрастают, т. Е. Если смещение для элемента i смещено 1 , тогда элемент i + 1 имеет смещение, offset2, которое удовлетворяет: offset2> = offset1.CUDA: как перемещать элементы массива

Я написал ядро, которое выполняется на каждом из первых к элементов:

if (thread_id < k) { 

    // compute offset 

    if (offset) { 
    int temp = a[thread_id]; 

    __synchthreads(); 

    a[thread_id + offset] = temp; 
    } 
} 

Однако при испытании при к = 3, смещение действительно монотонно возрастает, а именно 0, 1, 1. Элемент 0 остается в своем положении так, как ожидалось. Однако элемент 1 копируется не только на элемент 2 (в соответствии со смещением для элемента 1), но также на элемент 3.

То есть, кажется, что поток 2 считывает элемент 2 и сохраняет его в своей копии temp только после того, как поток 1 завершил копию элемента 1 на элемент 2.

Что я делаю неправильно и как его исправить?

Спасибо!

+1

Обратите внимание, что '__syncthreads()' только обеспечивает барьер для потоков внутри блока. Таким образом, этот метод будет разорваться, как только вы перейдете к более чем одному блоку в своей сетке. Кроме того, если вы делаете что-то глупое, например, запускаете сетку потоков, каждый из которых имеет только один поток, тогда код будет разрываться повсюду. Возможно, вам следует показать полное представление вашего ядра вместе с вызовом ядра и вычислением параметров запуска. Вы можете просто отредактировать свой вопрос с помощью этой информации, не пробуйте и не добавляйте ее в комментарии. –

+0

Да, я неправильно выполнял 3 блока по 1 нити каждый. Он отлично работает с 1 блоком из 3 потоков. Однако это ограничение ограничено 1024 потоками на блок на Tesla K20. Как перемещается более 1024 элементов? Перемещая один блок по 1024 за один раз, завершив работу, прежде чем сделать еще один блок из 1024 и т. Д.? – user1760748

+0

также, '__syncthreads()' внутри условного блока вроде этого не гарантируется. Прочитайте [здесь] (http://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#synchronization-functions) о syncthreads в условном коде. Что касается того, как заставить его работать с несколькими блоками потоков, вам понадобится другой алгоритм, который будет распараллеливаться.Я не думал об этом широко, но мне кажется, что если ваш выходной вектор отличается от вашего входного вектора, вы бы полностью избегали этой опасности. –

ответ

3

Что вы делаете обобщается на операцию рассеяния:

thread 0 1 2 3 4 
in = { 1, 4, 3, 2, 5} 
idx = { 1, 2, 3, 4, 0} 

out[idx] = in[i] 

В целом разброс не может быть сделано на месте параллельно, поскольку потоки чтения из мест, что другие темы писать. В нашем примере, если поток 2 считывает свое входное местоположение после поток 1 записывает свое местоположение вывода, мы получаем неверные результаты. Это условие гонки и требует либо синхронизации, либо хранения на месте.

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

Другими словами, вы не можете сделать это:

temp = in[thread_idx] 
global-sync 
in[thread_idx + offset] = temp 

Вы должны сделать это:

out[i + offset] = in[thread_idx] 

Где out не указывает на ту же память in.

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