Реальные варианты использования барьеров (DSB, DMB, ISB) в ARM

Я понимаю, что DSB, DMB и ISB являются препятствиями для предотвращения изменения порядка инструкций. Я также могу найти множество очень хороших объяснений для каждого из них, но довольно сложно представить себе случай, когда мне придется их использовать.

Кроме того, из открытых исходных кодов я время от времени вижу эти препятствия, но довольно сложно понять, почему они используются. Например, в функции tcp_rcv_synsent_state_process в ядре Linux 3.7 tcp_rcv_synsent_state_process есть следующая строка:

    if (unlikely(po->origdev))
            sll->sll_ifindex = orig_dev->ifindex;
    else
            sll->sll_ifindex = dev->ifindex;

    smp_mb();

    if (po->tp_version <= TPACKET_V2)
            __packet_set_status(po, h.raw, status);

где smp_mb () - это в основном DMB. Не могли бы вы привести мне несколько примеров из реальной жизни? Это помогло бы больше узнать о препятствиях.


person jaeyong    schedule 19.03.2013    source источник
comment
Этот вопрос был недавним примером: stackoverflow.com/q/15003405/1163019   -  person auselen    schedule 19.03.2013
comment
В руководстве программиста Cortex также есть раздел о препятствиях (11.2). infocenter.arm.com/help/topic/com. arm.doc.den0013c / index.html   -  person auselen    schedule 19.03.2013
comment
en.wikipedia.org/wiki/Memory_barrier содержит информацию, которая может помочь.   -  person artless noise    schedule 20.03.2013


Ответы (3)


Извините, я не собираюсь приводить вам прямой пример, как вы просите, потому что, поскольку вы уже просматриваете исходный код Linux, у вас их много, и они, похоже, не помогают. В этом нет ничего постыдного - любого здравомыслящего человека хотя бы изначально смущают проблемы с упорядочением доступа к памяти :)

Если вы в основном разработчик приложений, то есть все шансы, что вам не придется особо беспокоиться об этом - какие бы фреймворки параллелизма вы ни использовали, решат эту проблему за вас.

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

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

Пол МакКенни написал отличную статью о необходимости барьеров памяти и их влиянии на процессор: Барьеры памяти: взгляд на оборудование для программных хакеров

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

Но если вам нужны именно списки примеров, особенно для архитектуры ARM, вы можете сделать намного хуже, чем Барьерные тесты и поваренная книга.

Взгляд программиста extra-extra light и не совсем верная с архитектурной точки зрения версия:

  • DMB - всякий раз, когда доступ к памяти требует упорядочивания относительно другого доступа к памяти.
  • DSB - всякий раз, когда доступ к памяти должен быть завершен до выполнения программы.
  • ISB - всякий раз, когда выборка инструкций должна происходить явно после определенного момента в программе, например, после обновления карты памяти или после написания кода, который должен быть выполнен. (На практике это означает «выбросить все предварительно загруженные инструкции на этом этапе».)
person unixsmurf    schedule 19.03.2013
comment
Хорошее объяснение. Я не могу не задаться вопросом о трех инструкциях. По сути, вы пишете: DMB: убедитесь, что приведенный выше код завершен. DSB: убедитесь, что приведенный выше код заполнен. ISB: убедитесь, что приведенный выше код заполнен. (Возможно, мне следует прочитать предоставленные вами ссылки.) Тем не менее, разве volatile не скажет компилятору гарантировать порядок инструкций? (В конце концов, вставив одну из приведенных выше команд и т. Д.) - person Illishar; 15.12.2020
comment
@Illishar: volatile влияет на порядок, в котором инструкции генерируются компилятором, да. Эти инструкции влияют на то, когда результаты этих инструкций гарантированно будут архитектурно согласованными в системе с нарушением порядка и / или с несколькими процессорами. Статья Пола МакКенни - наиболее полный из перечисленных источников, и на него стоит потратить некоторое время. Что касается инструкций, это не то, что говорится в описании. Входя в мир параллелизма, привыкните уделять много внимания семантике. - person unixsmurf; 15.12.2020

Обычно вам нужно использовать барьер памяти в тех случаях, когда вы должны УБЕДИТЬСЯ, что доступ к памяти происходит в определенном порядке. Это может потребоваться по ряду причин, обычно это требуется, когда два или более процессов / потоков или аппаратный компонент обращаются к одной и той же структуре памяти, которая должна быть согласованной.

Очень часто используется в DMA-передачах. Простые управляющие структуры DMA могут выглядеть так:

struct dma_control {
  u32 owner;
  void * data;
  u32 len;
};

Владелец обычно устанавливается на что-то вроде OWNER_CPU или OWNER_HARDWARE, чтобы указать, кому из двух участников разрешено работать со структурой.

Код, который меняет это, обычно выглядит следующим образом

dma->data = data;
dma->len  = length;
smp_mb();
dma->owner = OWNER_HARDWARE;

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

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

person Nico Erfurth    schedule 19.03.2013

Одним из простых примеров барьерного требования является спин-блокировка. Если вы реализуете спин-блокировку с использованием сравнения и замены (или LDREX / STREX на ARM) и без барьера, процессору разрешается спекулятивно загружать значения из памяти и лениво сохранять вычисленные значения в памяти, и ни то, ни другое не требуется. в порядке загрузки / сохранения в потоке инструкций.

DMB, в частности, предотвращает переупорядочивание доступа к памяти в DMB. Без DMB процессор мог бы переупорядочить хранилище в памяти, защищенной спин-блокировкой, после того, как спин-блокировка будет снята. Или процессор мог читать память, защищенную спин-блокировкой, до того, как спин-блокировка была фактически заблокирована, или пока она была заблокирована другим контекстом.

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

person rsaxvc    schedule 31.07.2013