Вероятный/маловероятный эквивалент для MSVC

Компилятор GCC поддерживает оператор __builtin_expect, который используется для определения вероятных и маловероятных макросов.

например.

#define likely(expr)    (__builtin_expect(!!(expr), 1))
#define unlikely(expr)  (__builtin_expect(!!(expr), 0))

Есть ли эквивалентное утверждение для компилятора Microsoft Visual C или что-то подобное?

Ответ 1

Я говорю просто пунт

Там нет ничего подобного. Существует __assume(), но не используйте ее, это директива оптимизатора другого рода.

Действительно, встроенная в макрос встроенная в gnu причина заключается в том, что вы можете просто избавиться от него автоматически, если __GNUC__ не определен. В этих макросах нет ничего необходимого, и я уверен, что вы не заметите разницу во времени выполнения.

Резюме

Просто избавьтесь от (null out) *likely в не-GNU. Вы не пропустите это.

Ответ 2

В соответствии с http://www.akkadia.org/drepper/cpumemory.pdf (стр. 57), все же имеет смысл использовать предсказание статической ветки, даже если процессор прогнозирует корректно динамически. Причина этого в том, что кеш L1i будет использоваться еще эффективнее, если статическое предсказание будет выполнено правильно.

Ответ 3

Стандарт С++ 20 будет включать в себя атрибуты прогнозирования ветвлений [[likely]] и [[unlikely]].

Самую последнюю версию предложения по атрибутам можно найти в http://wg21.link/p0479

Исходное предложение атрибута можно найти в http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0479r0.html

Программисты должны предпочесть PGO. Атрибуты могут легко снизить производительность, если они применяются неправильно или позже становятся неправильными при изменении программы.

Ответ 4

__ предположить должен быть схожим.

Однако, если вы хотите сделать это очень хорошо, вы должны использовать Profile Guided Optimization, а не статические подсказки.

Ответ 5

В соответствии с Документ Intel:

Чтобы эффективно писать свой код, чтобы воспользоваться этими правила, при написании инструкций if-else или switch, проверьте наиболее общие случаи сначала и работать постепенно вниз до наименее общего.

К сожалению, вы не можете написать что-то вроде

#define if_unlikely(cond) if (!(cond)); else 

поскольку оптимизатор MSVC по сравнению с VS10 игнорирует такой "намек".

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

Ответ 6

Я знаю, что этот вопрос касается Visual Studio, но я постараюсь ответить на максимально возможное количество компиляторов (включая Visual Studio)…

Десять лет спустя налицо прогресс! Начиная с Visual Studio 2019 MSVC до сих пор не поддерживает ничего подобного (хотя это самый популярный встроенный/встроенный), но, как упоминалось выше у Паули Ниеминена C++ 20, есть likely/unlikely атрибуты, которые можно использовать для создания вероятных/маловероятных макросов, а MSVC обычно довольно быстро добавляет поддержку новых стандартов C++ (в отличие от C), поэтому я ожидаю, что Visual Studio 2021 их поддержит.

В настоящее время (2019-10-14) только GCC поддерживает эти атрибуты и даже тогда применяется только к меткам, но этого достаточно, чтобы хотя бы выполнить некоторое базовое тестирование. Вот быстрая реализация, которую вы можете протестировать в Compiler Explorer:

#define LIKELY(expr) \
  ( \
    ([](bool value){ \
      switch (value) { \
        [[likely]] case true: \
          return true; \
        [[unlikely]] case false: \
          return false; \
      } \
    }) \
  (expr))
#define UNLIKELY(expr) \
  ( \
    ([](bool value){ \
      switch (value) { \
        [[unlikely]] case true: \
          return true; \
        [[likely]] case false: \
          return false; \
      } \
    }) \
  (expr))

Вы, вероятно, захотите использовать #ifdef для поддержки компиляторов, которые не могут его обработать, но, к счастью, большинство компиляторов поддерживают __builtin_expect:

  • GCC 3.0
  • лязг
  • ICC, так как по крайней мере 13, вероятно, гораздо дольше.
  • Oracle Development Studio 12. 6+, но только в режиме C++.
  • ARM 4.1
  • IBM XL C/C++, поскольку, по крайней мере, 10,1, вероятно, дольше.
  • TI с 6.1
  • TinyCC с 0.9.27

GCC 9+ также поддерживает __builtin_expect_with_probability. Он недоступен где-то еще, но, надеюсь, однажды... Потребуется немало догадок, пытаясь выяснить, использовать ли подобное/маловероятно или нет - вы просто устанавливаете вероятность, и компилятор (теоретически) делает правильные вещи.

Кроме того, clang поддерживает __builtin_unpredictable (начиная с версии 3.8, но проверьте его с помощью __has_builtin(__builtin_unpredictable)). Поскольку в наши дни многие компиляторы основаны на clang, они, вероятно, работают и в них.

Если вы хотите, чтобы все было закончено и готово к работе, вас может заинтересовать один из моих проектов, Хедли. Это единственный общедоступный заголовок C/C++, который работает практически на всех компиляторах и содержит множество полезных макросов, включая HEDLEY_LIKELY, HEDLEY_UNLIKELY, HEDLEY_UNPREDICTABLE, HEDLEY_PREDICT, HEDLEY_PREDICT_TRUE и HEDLEY_PREDICT_FALSE. У него еще нет версии C++ 20, но она скоро должна появиться

Даже если вы не хотите использовать Хедли в своем проекте, вы можете проверить реализации там, а не полагаться на списки выше; Я, вероятно, забуду обновить этот ответ новой информацией, но Хедли всегда должен быть в курсе событий.