Перейти к Оптимизации Refactor

У меня есть «MyFunction», над которой я продолжаю зацикливаться, если я должен или не должен использовать goto, и в подобных (надеюсь, редких) обстоятельствах. Поэтому я пытаюсь выработать сложную привычку для этой ситуации. Делать или не делать.

int MyFunction()
{   if (likely_condition)
{
condition_met:
// ...
return result;
}
else /*unlikely failure*/
{   // meet condition
goto condition_met;
}
}

Я намеревался получить выгоду от неудачной инструкции условного перехода для вероятного случая. Однако я не вижу, как компилятор мог бы знать, что оптимизировать для вероятности случая без чего-либо подобного.

  1. это работает правильно?
  2. преимущества стоят путаницы?
  3. Есть ли лучшие (менее многословные, более структурированные, более выразительные) способы, позволяющие провести эту оптимизацию?

4

Решение

Современный ЦП будет использовать эту ветку в любом случае с одинаковой производительностью, если он сделает правильный прогноз ветвления. Так что, если это находится во внутреннем цикле, производительность if (unlikely) { meet condition } common code; будет соответствовать тому, что вы написали.

Кроме того, если вы укажете общий код в обеих ветках, компилятор генерировать код, идентичный тому, что вы написали: общий случай будет передан для if пункт и else пункт будет jmp к общему коду. Вы видите это все время с более простыми терминалами, такими как *out = whatever; return result;, При отладке бывает сложно сказать, какие return вы смотрите, потому что они все были объединены.

4

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

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

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

int MyFunction() {
if (!likely_condition) {
meet_condition();
}
// ...
return result;
}
5

  1. Похоже, код должен работать так, как вы ожидаете, пока condition_met: не пропускает инициализации переменных.

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

3.

int MyFunction()
{
if (!likely_condition)
{
// meet condition
}

condition_met:
// ...
return result;
}

или, если это поможет вашему компилятору (проверьте сборку)

int MyFunction()
{
if (likely_condition); else
{
// meet condition
}

condition_met:
// ...
return result;
}
4

Я очень рекомендую использовать __builtin_expect() макрос (GCC) или аналогичный для вашего конкретного компилятора C ++ (см. Подсказки по прогнозированию переносимых веток) Вместо того, чтобы использовать goto:

int MyFunction()
{   if (__builtin_expect(likely_condition))
{
// ...
return result;
}
else /*unlikely failure*/
{   // meet condition
}
}

Как и другие упоминали goto подвержен ошибкам и злу от костей.

1
По вопросам рекламы [email protected]