CUDA: синхронизация потоков

Проверьте свойства вашего проекта. На вкладке «Приложение» выберите свой класс Program как объект «Запуск»:

alt text http://i42.tinypic.com/2vvsxhe.jpg

13
задан talonmies 20 February 2016 в 08:24
поделиться

3 ответа

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

Но разные деформации таким образом не синхронизируются. Поэтому, если ваш алгоритм требует, чтобы определенные операции выполнялись во многих деформациях, вам необходимо использовать явные вызовы синхронизации (см. Руководство по программированию CUDA, раздел 5.4).


РЕДАКТИРОВАТЬ: реорганизовал следующие несколько абзацев, чтобы прояснить некоторые

Здесь действительно две разные проблемы: Синхронизация инструкций и видимость памяти.

  • __ syncthreads () обеспечивает синхронизацию инструкций и обеспечивает видимость памяти, но только внутри блока, а не между блоками (Руководство по программированию CUDA, Приложение B.6). Это полезно для записи и чтения в разделяемой памяти, но не подходит для синхронизации доступа к глобальной памяти.

  • __ threadfence () обеспечивает видимость глобальной памяти, но не выполняет синхронизацию инструкций, поэтому, по моему опыту, он имеет ограниченное использование (но см. Пример кода в Приложении B.5).

  • Глобальная синхронизация инструкций - это невозможно в ядре. Если вам нужно выполнить f () во всех потоках перед вызовом g () в любом потоке, разделите f () и g () на два разных ядра и последовательно вызывать их с хоста.

  • Если вам просто нужно увеличить общие или глобальные счетчики, рассмотрите возможность использования функции атомарного увеличения atomicInc () (Приложение B.10). В случае приведенного выше кода, если x1 и x2 не являются глобально уникальными (для всех потоков в вашей сетке), неатомарные приращения приведут к состоянию гонки, аналогичному к последнему абзацу Приложения B.2.4.

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

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

рассмотрите возможность использования функции атомарного приращения atomicInc () (Приложение B.10). В случае приведенного выше кода, если x1 и x2 не являются глобально уникальными (для всех потоков в вашей сетке), неатомарные приращения приведут к состоянию гонки, аналогичному к последнему абзацу Приложения B.2.4.

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

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

рассмотрите возможность использования атомарной функции приращения atomicInc () (Приложение B.10). В случае приведенного выше кода, если x1 и x2 не являются глобально уникальными (для всех потоков в вашей сетке), неатомарные приращения приведут к состоянию гонки, аналогичному к последнему абзацу Приложения B.2.4.

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

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

В случае приведенного выше кода, если x1 и x2 не являются глобально уникальными (для всех потоков в вашей сетке), неатомарные приращения приведут к состоянию гонки, аналогичному к последнему абзацу Приложения B.2.4.

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

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

В случае приведенного выше кода, если x1 и x2 не являются глобально уникальными (для всех потоков в вашей сетке), неатомарные приращения приведут к состоянию гонки, аналогичному к последнему абзацу Приложения B.2.4.

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

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

аналогично последнему абзацу приложения B.2.4.

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

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

аналогично последнему абзацу приложения B.2.4.

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

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

35
ответ дан 1 December 2019 в 18:55
поделиться

Из раздела 6.1 руководства CUDA Best Practices Guide:

Любой поток инструкция управления (if, switch, do, for, while) может существенно повлиять пропускная способность инструкций за счет расхождения потоков одной основы; то есть, следовать различным путям выполнения. Если это произойдет, разные пути выполнения должны быть сериализованы, увеличивая общее количество инструкций, выполняемых для этого деформация. Когда все разные пути выполнения завершены, потоки сходятся вернуться к тому же пути выполнения.

Итак, вам не нужно делать ничего особенного.

2
ответ дан 1 December 2019 в 18:55
поделиться

Ответ на ваш вопрос - нет. Тебе не нужно делать ничего особенного. В любом случае, вы можете исправить это, вместо своего кода вы можете сделать что-то вроде этого:

buffer[x1] += (d1 < 0.5);
buffer[x2] += (d2 < 0.5);

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

1
ответ дан 1 December 2019 в 18:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: