Переносные подсказки для прогнозирования отрасли

Есть ли какой-либо переносной способ подсказки предсказания ветвления? Рассмотрим следующий пример:

  if (unlikely_condition) {
    /* ..A.. */
  } else {
    /* ..B.. */
  }

Разве это не так:

  if (!unlikely_condition) {
    /* ..B.. */
  } else {
    /* ..A.. */
  }

Или это единственный способ использовать конкретные подсказки компилятора? (например, __builtin_expect на GCC)

Будут ли компиляторы рассматривать условия if по-разному на основе упорядочения условий?

Ответ 1

Канонический способ предсказать статическую ветвь заключается в том, что if предсказан не-разветвленным (т.е. выполняется каждое предложение if, а не else), а петли и обратное - goto. Поэтому не ставьте общий случай в else, если вы ожидаете, что статическое предсказание будет значительным. Обход незанятой петли не так прост; Я никогда не пробовал, но я полагаю, что предложение else должно работать довольно портативно.

Многие компиляторы поддерживают некоторую форму #pragma unroll, но по-прежнему необходимо охранять ее каким-то #if для защиты других компиляторов.

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

Как рекомендует GNU в документации для __builtin_expect, оптимизация на основе профиля превосходит намеки и с меньшими усилиями.

Ответ 2

В большинстве случаев следующий код

if (a)
{
   ...
}
else
{
    ...
}

на самом деле

evaluate(A)

if (!A)
{
   jmp p1
}

... code A

   jmp p2

p1:

... code !A

p2:

Обратите внимание, что если A истинно, "код A" уже находится в стадии разработки. Процессор увидит команду "jmp p2" вперед и загрузит код p2 в конвейер.

Если A является ложным, "код! A" может не находиться в pipleline, поэтому он может быть медленнее.

Выводы:

  • do Если (X), если X более вероятно, чем! X
  • попытайтесь оценить A как можно раньше, чтобы CPU мог динамически оптимизировать конвейер.

:

evaluate(A)

do more stuff

if (A)
   ...

Ответ 3

Оптимизация по сути является компилятором, поэтому вам нужно использовать функциональность компилятора, чтобы помочь ей. Сам язык не заботится о (или мандате) оптимизации.

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

Ответ 4

Просто соглашайтесь с тем, что вы делаете. Мне нравится использовать

if (!(someExpression))

Но компилятор должен относиться к этому в равной степени.

Ответ 5

Что не так с проверкой конкретного компилятора с помощью #ifdef и спрятать эти вещи за пользовательским макросом? Вы можете #define его развернуть до простого выражения в случаях, когда у вас нет компилятора, который поддерживает эти подсказки оптимизации. Недавно я сделал что-то подобное с явным кэшем, который GCC поддерживает через встроенную функцию.