Во-первых, процессоры имеют возможность, называемую прогнозирование ветвления . После нескольких запусков цикла процессор сможет заметить, что ваш оператор if
всегда идет в одну сторону. (Он может даже заметить регулярные паттерны, такие как true false true false
.) Затем он спекулятивно выполнит эту ветвь, и при условии, что сможет правильно предсказать, дополнительные затраты на if
утверждение в значительной степени устранено. Если вы считаете, что пользователь с большей вероятностью выберет true
, а не false
, вы даже можете сообщить об этом компилятору gcc (расширение, специфичное для gcc).
Однако вы упомянули в одном из своих комментариев, что у вас есть «гораздо более сложная последовательность bools». Я думаю, возможно, что у процессора нет памяти для сопоставления с образцом всех этих переходов - к тому времени, когда он возвращается к первому оператору if
, знание того, каким образом этот переход прошел, смещено с его объем памяти. Но мы могли бы помочь здесь ...
Компилятор имеет возможность преобразовывать циклы и операторы if в то, что он считает более оптимальными формами. Например. он может преобразовать ваш код в форму, заданную schnaader. Это известно как отключение контура . Вы можете помочь в этом, выполнив Оптимизация по профилю (PGO) , сообщив компилятору, где находятся горячие точки. (Примечание: в gcc -funswitch-loops
включается только при -O3
.)
Вы должны профиль свой код на уровне инструкций ( VTune будет хорошим инструментом для этого), чтобы увидеть, действительно ли операторы if являются узким местом. Если это действительно так, и, глядя на сгенерированную сборку, вы думаете, что компилятор ошибся, несмотря на PGO, вы можете попробовать самостоятельно вывести оператор if. Возможно, шаблонный код сделает это более удобным:
template<bool B> void innerLoop() {
for (int i=0; i<10000; i++) {
if (B) {
// some stuff..
} else {
// some other stuff..
}
}
}
if (user_set_flag) innerLoop<true>();
else innerLoop<false>();