Зависит ли ускорение от предсказания ветвления от сложности предиката?

Предположим, у меня есть какая-то функция IsTrue() который возвращает bool, Если программист решит, что IsTrue() будет обычно возвращаться trueона может использовать GCC __builtin_expect или аналогичные для ускорения инструкций в этих типичных случаях.

Взяв следующие 2 примера:

// example 1
const bool result = IsTrue();
if (__builtin_expect(result, true))
// do something
;

// example 2
if (__builtin_expect(IsTrue(), true))
// do something
;

При условии, что IsTrue нетривиально, есть ли разница между ними? Делает размещение IsTrue() внутри __builtin_expect список параметров вызывает оценку кэша команд до результат IsTrue известен или применяется только ветвление после результат IsTrue рассчитывается?

3

Решение

Все современные процессоры используют суперскалярный конвейер, который предварительно вычисляет инструкции, следующие за тем, который фактически выполняется. Используя __builtin_expectкомпилятор переупорядочивает инструкции так, чтобы ожидаемый (вероятный) путь не использовал переходы, которые приводят к пропуску суперскалярного конвейера и, следовательно, делают все предварительно вычисленные результаты бесполезными.

РЕДАКТИРОВАТЬ: это, конечно, упрощено. Современные процессоры также имеют предсказание ветвления, поэтому они пытаются предсказать, по какому пути будет следовать код, но путь без переходов все еще предпочтителен (это также лучше для кэша, потому что путь к исполняемому коду компактен). Также обратите внимание, что эти изменения в скорости, как правило, довольно незначительны, и вам не нужно беспокоиться, если ваш код выполняется не слишком часто или действительно требует как можно большей скорости.

3

Другие решения

Как говорится в документации GCC, предпочитайте строить с оптимизацией по профилю (PGO, -fprofile-generate с последующим запуском тестовых сценариев и восстановлением с -fprofile-use) чтобы писать с __builtin_expect,

Встроенный в CPU прогноз ветвлений будет кэшировать большинство веток в «типичных» путях выполнения программы. Статическое предсказание ветвлений имеет значение, главным образом, когда оно предоставляет надежные данные о все ветви, поэтому, когда у компилятора есть выбор между выполнением одного из нескольких тестов в первую очередь, он может организовать наиболее эффективную последовательность. При этом учитывается не только то, к чему относятся значения, но какие else if заявление выбирается чаще всего.

__builtin_expect редко будет иметь значение. Для ветвящихся программ, -fprofile-use обычно обеспечивает мгновенный прирост на 10-30% без каких-либо усилий при программировании.

Делает размещение IsTrue() внутри __builtin_expect список параметров приводит к тому, что кэш инструкций должен оцениваться до результата IsTrue известен, или предсказание ветвления применяется только после результата IsTrue рассчитывается?

__builtin_expect происходит во время компиляции. Кеш инструкций еще даже не существует. Компилятор догадается, что IsTrue является trueи затем во время выполнения процессор сделает еще одно, более обоснованное предположение.

1