Является ли загрузка и хранение единственными инструкциями, которые переупорядочиваются? - PullRequest
0 голосов
/ 23 мая 2018

Я прочитал много статей об упорядочении памяти, и все они только говорят, что переупорядочение ЦП загружает и сохраняет.

ЦП (меня особенно интересует процессор x86) только переупорядочивает загрузки исохраняет и не переупорядочивает остальные инструкции, которые у него есть?

Ответы [ 2 ]

0 голосов
/ 23 мая 2018

Внеочередное выполнение сохраняет иллюзию запуска в программном порядке для одного потока / ядра .Это похоже на правило оптимизации «как если бы» в C / C ++: делайте все, что хотите, внутренне, пока видимые эффекты одинаковы.

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

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


Простой пример: две цепочки зависимостей ALU могут перекрываться

(связанный: http://blog.stuffedcow.net/2013/05/measuring-rob-capacity/ для получения дополнительной информации о том, насколько велико окно для нахождения параллелизма на уровне инструкций, например, если вы увеличите это значение до times 200, вы увидите только ограниченное перекрытие. Также связано: ответ от начинающего до промежуточного уровняЯ написал о том, как ООП-процессор, такой как Haswell или Skylake, находит и использует ILP.

Более глубокий анализ влияния lfence здесь, см. Понимание влияния lfence нацикл с двумя длинными цепочками зависимостей, для увеличения длины

global _start
_start:
    mov  ecx, 10000000
.loop:
    times 25 imul eax,eax   ; expands to imul eax,eax  / imul eax,eax / ...
 ;   lfence
    times 25 imul edx,edx
 ;   lfence
    dec  ecx
    jnz  .loop

    xor  edi,edi
    mov  eax,231
    syscall          ; sys_exit_group(0)

, встроенный (с nasm + ld) в статический исполняемый файл на Linux x86-64, запускается (on Skylake) в ожидаемых 750M тактовых циклах для каждой цепочки 25 * 10M imul инструкций, умноженных на 3 такта.

Комментирование одной из imul цепочек не меняет время, необходимое для выполнения: все еще750M циклов.

Это определенное доказательство неупорядоченного выполнения, чередуя две цепочки зависимостей, в противном случае.(imul пропускная способность равна 1 за такт, задержка 3 такта. http://agner.org/optimize/. Таким образом, третья цепочка зависимостей могла бы быть смешана без особого замедления).

Фактические числа из taskset -c 3 ocperf.py stat --no-big-num -etask-clock,context-switches,cpu-migrations,page-faults,cycles:u,branches:u,instructions:u,uops_issued.any:u,uops_executed.thread:u,uops_retired.retire_slots:u -r3 ./imul:

  • с обеими цепями imul: 750566384 +- 0.1%
  • только с цепочкой EAX: 750704275 +- 0.0%
  • с одной цепью times 50 imul eax,eax: 1501010762 +- 0.0% (почти в два раза больше, чеммедленно, как и ожидалось).
  • с lfence, предотвращая перекрытие между каждым блоком 25 imul: 1688869394 +- 0.0%, хуже, чем в два раза медленнее.uops_issued_any и uops_retired_retire_slots - 63M, вместо 51M, в то время как uops_executed_thread по-прежнему 51M (lfence не использует никаких портов выполнения, но, очевидно, две lfence инструкции стоят 6 мопов в слитых доменах. AgnerТуман измеряется только 2.)

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

lfence на Intel всегда так, но на AMD, он только частично сериализован с включенным смягчением спектра .


Сноска 1 : Существуют также побочные каналы синхронизации, когда два логических потока совместно используют один физическийнить (гиперпоточность или другое SMT).например, выполнение последовательности независимых imul инструкций будет выполняться по 1 разу в такт на недавнем процессоре Intel, если другой гиперпотоке не нужен порт 1 для чего-либо.Таким образом, вы можете измерить, насколько сильно давление порта 0, синхронизируя цикл ALU на одном логическом ядре.

Другие микроархитектурные побочные каналы, такие как доступ к кэшу, более надежны.Например, Spectre / Meltdown проще всего использовать с побочным каналом чтения кэша, а не ALU.

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


MFENCE на Skylake - это барьер OoO exec, такой как LFENCE

mfence на неожиданных блоках Skylakeвыполнение не по порядку imul, например, lfence, хотя это не задокументировано.(См. Обсуждение в чате).

xchg [rdi], ebx (неявный префикс lock) вообще не блокирует неупорядоченное выполнение инструкций ALU.Общее время по-прежнему составляет 750 миллионов циклов при замене lfence на xchg или инструкции lock ed в вышеприведенном тесте.

Но при mfence стоимость возрастает до 1500 миллионов циклов + времяза 2 mfence инструкции.Чтобы провести контролируемый эксперимент, я оставил счетчик команд таким же, но переместил инструкции mfence рядом друг с другом, чтобы цепочки imul могли переупорядочиваться друг с другом, и время уменьшилось до 750M + время для 2mfence инструкции.

Такое поведение Skylake, скорее всего, является результатом исправления обновления микрокода ошибка SKL079 , MOVNTDQA из памяти WC может пройти раньше Инструкции MFENCE .Наличие опечатки показывает, что раньше было возможно выполнить более поздние инструкции до завершения mfence, поэтому, вероятно, они сделали грубое исправление, добавив lfence моп в микрокод для mfence.

Это еще один фактор в пользу использования xchg для хранилищ seq-cst или даже lock add для некоторой стековой памяти в качестве автономного барьера. Linux уже выполняет обе эти функции, но компиляторывсе еще используйте mfence для барьеров.См. Почему хранилище std :: atomic с последовательной последовательностью использует XCHG?

(См. Также обсуждение выбора барьеров для Linux в этой ветке групп Google со ссылками на3 отдельные рекомендации по использованию lock addl $0, -4(%esp/rsp) вместо mfence в качестве автономного барьера.

0 голосов
/ 23 мая 2018

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


Как правило, исключения FPU также можно наблюдать при переупорядочении.По этой причине большинство неработающих процессоров имеют неточные исключения , но не x86.На платформе x86 процессор обеспечивает выдачу исключений, как если бы операции с плавающей запятой не переупорядочивались.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...