Подтвердить что ты не робот

Барьер памяти GCC __sync_synchronize против asm volatile ("": "memory")

asm volatile("":: :"memory") часто используется в качестве барьера памяти (например, как видно из макроса barrier ядра Linux).

Это похоже на то, что делает встроенная в GCC __sync_synchronize.

Эти два похожи?

Если нет, каковы различия, и когда один из них будет использоваться над другим?

4b9b3361

Ответ 1

Там существенная разница - первый вариант (inline asm) фактически ничего не делает во время выполнения, там нет команды, и CPU не знает об этом. он служит только во время компиляции, чтобы сообщить компилятору не перемещать грузы или магазины за эту точку (в любом направлении) в рамках своих оптимизаций. Он назвал барьер SW.

Второй барьер (встроенная синхронизация) просто переводится в барьер HW, возможно, в качестве ограждения (mfence/sfence), если вы находитесь на x86 или его эквивалентах в других архитектурах. ЦП может также выполнять различные оптимизации во время выполнения, самый важный из них фактически выполняет операции не по порядку - эта инструкция говорит ему, чтобы убедиться, что нагрузки или магазины не могут пройти эту точку и должны соблюдаться в правильной части точка синхронизации.

Вот еще одно хорошее объяснение:

Типы барьеров памяти

Как упоминалось выше, как компиляторы, так и процессоры могут оптимизировать выполнение инструкций таким образом, что это требует использования барьер памяти. Барьер памяти, который влияет как на компилятор, так и на процессор - это аппаратный барьер памяти и барьер памяти, который влияет только на компилятор - это программный барьер памяти.

Помимо аппаратных и программных барьеров памяти, барьер памяти могут быть ограничены памятью, записью памяти или обоими. Воспоминание барьер, который влияет как на чтение, так и на запись, является полным барьером памяти.

Существует также класс барьера памяти, который специфичен для многопроцессорных сред. Название этих барьеров памяти с префиксом "smp". В многопроцессорной системе эти барьеры аппаратных барьеров памяти и в однопроцессорных системах, они программные блоки памяти.

Макрос барьера() является единственным барьером программной памяти, и это полный барьер памяти. Все остальные барьеры памяти в ядре Linux аппаратных барьеров. Программный барьер аппаратной памяти - подразумеваемое программное обеспечение барьер.

Пример использования SW-барьера: рассмотрите следующий код -

for (i = 0; i < N; ++i) {
    a[i]++;
}

Этот простой цикл, скомпилированный с оптимизацией, скорее всего, будет развернут и векторизован. Здесь код сборки gcc 4.8.0-O3 генерирует упакованные (векторные) операции:

400420:       66 0f 6f 00             movdqa (%rax),%xmm0
400424:       48 83 c0 10             add    $0x10,%rax
400428:       66 0f fe c1             paddd  %xmm1,%xmm0
40042c:       66 0f 7f 40 f0          movdqa %xmm0,0xfffffffffffffff0(%rax)
400431:       48 39 d0                cmp    %rdx,%rax
400434:       75 ea                   jne    400420 <main+0x30>

Однако при добавлении встроенной сборки на каждой итерации gcc не разрешается изменять порядок операций за барьером, поэтому он не может группировать их, и сборка становится скалярной версией цикла:

400418:       83 00 01                addl   $0x1,(%rax)
40041b:       48 83 c0 04             add    $0x4,%rax
40041f:       48 39 d0                cmp    %rdx,%rax
400422:       75 f4                   jne    400418 <main+0x28>

Однако, когда ЦП выполняет этот код, он разрешает переупорядочивать операции "под капотом", если он не нарушает модель упорядочения памяти. Это означает, что выполнение операций может быть выполнено не по порядку (если ЦП поддерживает это, как это делают большинство в наши дни). Забор HW предотвратил бы это.

Ответ 2

Комментарий о пользе барьеров только для SW:

На некоторых микроконтроллерах и других встроенных платформах у вас может быть многозадачность, но нет кэширования или латентности кэша, и, следовательно, нет инструкций по барьеру HW. Поэтому вам нужно делать что-то вроде SW-замков. SW-бар предотвращает оптимизацию компилятора (объединение и переупорядочение чтения/записи) в этих алгоритмах.