Как понять, что макрос «вероятно» влияет на предсказание переходов?

Я заметил, что если мы знаем, что есть хороший шанс, что поток управления является истинным или ложным, мы можем сообщить об этом компилятору, например, в ядре Linux есть много likely unlikely, фактически подразумеваемых __builtin_expect, предоставленным gcc, поэтому я хочу узнай как он работает, потом проверил там сборку:

  20:branch_prediction_victim.cpp ****             if (array_aka[j] >= 128)
 184                            .loc 3 20 0 is_stmt 1
 185 00f1 488B85D0              movq    -131120(%rbp), %rax
 185      FFFDFF
 186 00f8 8B8485F0              movl    -131088(%rbp,%rax,4), %eax
 186      FFFDFF
 187 00ff 83F87F                cmpl    $127, %eax
 188 0102 7E17                  jle     .L13

Тогда для __builtin_expect

  20:branch_prediction_victim.cpp ****             if (__builtin_expect((array_aka[j] >= 128), 1))
 184                            .loc 3 20 0 is_stmt 1
 185 00f1 488B85D0              movq    -131120(%rbp), %rax
 185      FFFDFF
 186 00f8 8B8485F0              movl    -131088(%rbp,%rax,4), %eax
 186      FFFDFF
 187 00ff 83F87F                cmpl    $127, %eax
 188 0102 0F9FC0                setg    %al
 189 0105 0FB6C0                movzbl  %al, %eax
 190 0108 4885C0                testq   %rax, %rax
 191 010b 7417                  je      .L13
  • 188 - setg установить, если больше, здесь установить, если больше чего?
  • 189 - movzbl переместить нулевой расширенный байт в длинный, я знаю это переместить %al в %eax
  • 190 - testq побитовое ИЛИ затем установите флаги ZF CF, это правильно?

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


person http8086    schedule 04.04.2020    source источник
comment
Использование setcc с последующей проверкой флага reified таким образом — это глупый шаблон, который предполагает, что код мог быть скомпилирован с низкими настройками оптимизации. Не могли бы вы привести воспроизводимый пример?   -  person harold    schedule 04.04.2020
comment
Было бы полезно увидеть код, который вы на самом деле компилируете. И, как говорит Гарольд, похоже, никакой оптимизации нет, что делает все это бессмысленным. Никто не заботится о скорости кода, скомпилированного без оптимизации.   -  person gnasher729    schedule 04.04.2020


Ответы (1)


setcc читает ФЛАГИ, в данном случае установленные cmp прямо перед этим. Прочтите руководство.

Похоже, вы забыли включить оптимизацию, поэтому __builtin_expect просто создает логическое значение 0 / 1 в регистре и переходит к нему, не равному нулю, вместо перехода к исходному условию FLAGS. Не смотрите на неоптимизированный код, он всегда будет отстойным.

Подсказки таковы: логическая обработка braindead как часть likely и загрузка j из стека с использованием RBP в качестве указателя кадра с movq -131120(%rbp), %rax


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

likely на самом деле может заставить компилятор использовать ветвь вместо cmov для случаев, которые, как вы знаете, предсказуемы, даже если эвристика компилятора (без оптимизации на основе профиля) ошиблась бы. Связано: флаг оптимизации gcc -O3 делает код медленнее, чем -O2< /а>

person Peter Cordes    schedule 04.04.2020