Прогноз ветки префикса Intel x86 0x2E/0x3E действительно используется?

В последнем руководстве разработчика программного обеспечения Intel описываются два префикса кода операции:

Group 2 > Branch Hints

    0x2E: Branch Not Taken
    0x3E: Branch Taken

Они позволяют явное предсказание перехода команд перехода (коды операций, такие какJxx)

Я помню, как читал пару лет назад, что в x86 явное предсказание ветвлений было, по сути, бездействующим в контексте встроенных предсказаний ветвления gccs.

Теперь мне неясно, являются ли эти подсказки веток x86 новой функцией или они практически не используются на практике.

Кто-нибудь может это прояснить?

(То есть: генерируют ли функции прогнозирования ветвлений gccs эти подсказки веток x86? - и современные процессоры Intel не игнорируют их? - и когда это произошло?)

Обновить:

Я создал программу быстрого тестирования:

int main(int argc, char** argv)
{
    if (__builtin_expect(argc,0))
        return 1;

    if (__builtin_expect(argc == 2, 1))
        return 2;

    return 3;
}

Разбирает на следующее:

00000000004004cc <main>:
  4004cc:   55                      push   %rbp
  4004cd:   48 89 e5                mov    %rsp,%rbp
  4004d0:   89 7d fc                mov    %edi,-0x4(%rbp)
  4004d3:   48 89 75 f0             mov    %rsi,-0x10(%rbp)
  4004d7:   8b 45 fc                mov    -0x4(%rbp),%eax
  4004da:   48 98                   cltq   
  4004dc:   48 85 c0                test   %rax,%rax
  4004df:   74 07                   je     4004e8 <main+0x1c>
  4004e1:   b8 01 00 00 00          mov    $0x1,%eax
  4004e6:   eb 1b                   jmp    400503 <main+0x37>
  4004e8:   83 7d fc 02             cmpl   $0x2,-0x4(%rbp)
  4004ec:   0f 94 c0                sete   %al
  4004ef:   0f b6 c0                movzbl %al,%eax
  4004f2:   48 85 c0                test   %rax,%rax
  4004f5:   74 07                   je     4004fe <main+0x32>
  4004f7:   b8 02 00 00 00          mov    $0x2,%eax
  4004fc:   eb 05                   jmp    400503 <main+0x37>
  4004fe:   b8 03 00 00 00          mov    $0x3,%eax
  400503:   5d                      pop    %rbp
  400504:   c3                      retq   
  400505:   66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)
  40050c:   00 00 00 
  40050f:   90                      nop

Я не вижу 2E или 3E? Может быть, GCC исключил их по какой-то причине?

4 ответа

Решение

Эти префиксы команд не влияют на современные процессоры (что-то новее, чем Pentium 4). Они просто стоят один байт пространства кода, и, следовательно, не генерировать их - это правильно.

Подробности см. В руководствах по оптимизации Agner Fog, в частности 3. Микроархитектура: http://www.agner.org/optimize/

"Справочное руководство по оптимизации архитектур Intel® 64 и IA-32" больше не упоминает их в разделе об оптимизации веток (раздел 3.4.1): http://www.intel.de/content/dam/doc/manual/64-ia-32-architectures-optimization-manual.pdf

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

Правильно, что gcc не генерирует префикс, поскольку он не влияет на все процессоры, начиная с Pentium 4.

Но __builtin_expect имеет другие эффекты, такие как перемещение непредвиденного пути кода от горячих мест в кеше кода или встроенные решения, поэтому он все еще полезен.

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

Руководство по оптимизации Intel и руководство Agner Fog (которые уже упоминались здесь) содержат отличное описание этой функции.


Intel говорит об поколениях новее, чем Core 2:

Сделайте сквозной код после условной ветви вероятной целью для ветви с прямой целью

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

Это согласуется с тем, что GCC, кажется, сгенерировал, используя __builtin_expect: "ожидаемый" return 1 / return 2 код помещается в неиспользуемые пути из условных ветвей, которые будут статически предсказываться как неиспользуемые.

Дополнительно:

Ветви, которые не имеют истории в целевом буфере ветвления, прогнозируются с использованием алгоритма статического предсказания:

  • Предсказать безусловные ветви, которые будут приняты.

  • Предсказать непрямые ветви, которые НЕ будут приняты.

Таким образом, в "ожидаемых" не взятых путях, где GCC поместил безусловный jmp До конца функции эти переходы будут статически предсказываться как выполненные (то есть не пропущенные).

Intel также говорит:

сделать аварийный код после условной ветви маловероятной целью для ветви с обратной целью

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

Согласно Agner Fog, большинство Pentiums также следуют этому алгоритму:

На PPro, P2, P3, P4 и P4E команда передачи управления, которая не была замечена ранее или отсутствует в целевом буфере ветвления, предсказывается, что она провалится, если она будет идти вперед, и будет выполнена, если она будет идти назад. (например, петля). Статическое прогнозирование занимает больше времени, чем динамическое прогнозирование на этих процессорах.

Однако семейство Core 2 (и Pentium M) имеет совершенно другую политику:

Эти процессоры не используют статическое прогнозирование. Предсказатель просто делает случайное предсказание при первом просмотре ветви, в зависимости от того, что происходит в записи BTB, назначенной новой ветви. Существует просто 50% -ный шанс сделать правильный прогноз прыжка или не прыгнуть, но предсказанная цель верна.

Как и AMD процессоры, по-видимому:

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

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

Руководство разработчика программного обеспечения для архитектур Intel® 64 и IA-32 -> Том 2: Справочник по набору инструкций, AZ -> Глава 2: Формат инструкций -> 2.1 Формат инструкций для защищенного режима, режима реального адреса и режима виртуального 8086 -> 2.1.1 Префиксы инструкций

Некоторые более ранние микроархитектуры использовали их в качестве подсказок ветвей, но последние поколения не использовали их, и они зарезервированы для использования в будущем.

Другие вопросы по тегам