Прогноз ветки префикса 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 Префиксы инструкций
Некоторые более ранние микроархитектуры использовали их в качестве подсказок ветвей, но последние поколения не использовали их, и они зарезервированы для использования в будущем.