Насколько часто используются «вероятные» и «маловероятные» макросы?

12

Часто известные как likelyи unlikelyмакросы помогают компилятору узнать, будет ли ifон вводиться или пропускается. Его использование приводит к некоторым (довольно незначительным) улучшениям производительности.

Я начал использовать их недавно, и я не уверен, как часто следует использовать такие подсказки. В настоящее время я использую его с проверкой ошибок ifs, которые обычно помечаются как unlikely. Например:

mem = malloc(size);
if (unlikely(mem == NULL))
  goto exit_no_mem;

Вроде бы все нормально, но проверка ошибок ifпроисходит довольно часто и, следовательно, использование упомянутых макросов.

У меня вопрос, слишком ли много likelyи unlikelyмакросов при каждой проверке ошибок if?

В то время как мы в этом, какие другие места они часто используют?


В моем текущем использовании это библиотека, которая абстрагируется от подсистемы реального времени, поэтому программы становятся переносимыми между RTAI, QNX и другими. Тем не менее, большинство функций довольно маленькие и напрямую вызывают одну или две другие функции. Многие даже static inlineфункции.

Итак, во-первых, это не приложение, которое я мог бы профилировать. Не имеет смысла «определять узкие места», поскольку это библиотека, а не отдельное приложение.

Во-вторых, это что-то вроде: «Я знаю, что это маловероятно, я мог бы также рассказать об этом компилятору». Я не пытаюсь активно оптимизировать if.

Shahbaz
источник
7
пахнет микро оптимизации для меня ...
трещотка урод
2
Для кода приложения я бы добавил их только в том случае, если профилирование показало, что этот код используется в горячем пути.
CodesInChaos
akkadia.org/drepper/cpumemory.pdf Страница 57
Джеймс
@james, это просто говорит likelyи unlikelyсуществует и что они делают. Я не нашел ничего, что могло бы предложить, когда и где лучше всего их использовать.
Шахбаз
@Shahbaz "Если условие часто ложно, выполнение не является линейным. В середине находится большой кусок неиспользуемого кода, который не только загрязняет L1i из-за предварительной выборки, но также может вызвать проблемы с предсказанием перехода. Если предсказание ветвления неверно, условное выражение может быть очень неэффективным ". Итак, узкие циклы, в которых вы хотите убедиться, что необходимые инструкции находятся в кеше L1i
Джеймс

Ответы:

12

Вам нужна производительность настолько сильно, что вы готовы загрязнить свой код этим? Это небольшая оптимизация.

  • Код работает в узком цикле?
  • Есть ли у вашего приложения проблемы с производительностью?
  • Вы профилировали свое приложение и определили, что этот конкретный цикл стоит много процессорного времени?

Если вы не можете ответить yesна все вышеизложенное, не беспокойтесь о подобных вещах.

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

Java парень
источник
1
Просто чтобы прояснить, я не голосовал против тебя. Тем не менее, ваш ответ на самом деле не отвечает на мой вопрос. Вы пытаетесь сказать, что (un)likelyмакрос используется редко и только в чрезвычайно критичном для производительности коде? Является ли «плохой практикой» его частое использование или просто «ненужное»?
Шахбаз
@Shahbaz Это делает код менее читабельным, и оптимизация производительности может варьироваться от тривиального выигрыша до тривиальной потери. Последнее, когда предположение о вероятности было либо неверным, либо изменилось на неправильное из-за более позднего изменения других частей кода. Если никогда не должен использоваться, если это необходимо.
Питер
3
@Peter: Хотя это слишком плохо, синтаксис не так хорош, записи о том, что является вероятным или маловероятным, могут предоставить полезную информацию людям , которые читают код. Например, кто-то, кто видел if (likely(x==2 || x==3)) doOneThing(); else switch(x) { ... }, может судить, что использование программистом ifзначений 2 и 3 было не просто следствием того, что программист не знал, что C может связывать две caseметки с одним обработчиком.
суперкат
Никто не упомянул, что я считаю критической точкой. Дело не только в том, что «маловероятный» путь случается реже, это может быть связано с тем, что на этом пути вас не заботит скорость. Например, периферийное устройство перестает отвечать на запросы, поэтому вы все равно должны сбросить его и спать.
Бенджамин Линдквист
2

Если вы пишете для x86 / x64 (и не используете 20-летние процессоры), выигрыш в производительности от использования __builtin_expect () будет незначительным, если таковой имеется. Причина этого в том, что современные процессоры x86 / x64 (хотя на 100% не уверены в Atom) имеют динамическое предсказание ветвления, поэтому, по сути, ЦП «узнает» о ветвлении, которое используется чаще. Конечно, эта информация может храниться только для ограниченного числа филиалов, однако возможны только два случая. Если (а) это «часто используемая» ветвь, то ваша программа получит выгоду от этого динамического предсказания ветвления, а если (б) это «редкая» ветвь, вы не увидите реального снижения производительности из-за неправильных предсказаний в такие редкие ветки (20 циклов ошибочного предсказания ветвления процессора не слишком плохи, если это происходит однажды в синей луне).

NB: это НЕ означает, что на современных x86 / x64 важность ошибочного прогнозирования ветвлений стала ниже: любая ветвь с вероятностью скачка-сдвига 50-50 все равно будет подвергаться штрафу (циклы ЦПИ II-20), поэтому во внутренних ветвях цикла могут все еще нужно избегать. Это только важность __builtin_expect () на x86 / x64, которая уменьшилась (IIRC, около 10-15 лет назад или около того) - в основном из-за динамического предсказания ветвлений.

NB2: для других платформ, кроме x86 / x64, YMMV.

Заяц без ошибок
источник
Что ж, компилятор знает, какая ветвь будет ожидать от процессора меньше вероятности. И это может устроить так, чтобы это было действительно маловероятным. Но компилятор, вероятно, уже знает этот шаблон без unlikely-notation.
Дедупликатор
@Deduplicator: с динамическим предсказанием ветвлений, компилятор не знает, какая ветвь более вероятна, так как CPU вычисляет его во время выполнения на основе предыдущих проходов по этой самой точке кода.
No-Bugs Hare