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

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

например.

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

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

8 ответов

Решение

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

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

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

Резюме

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

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

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

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

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

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

Я знаю, что этот вопрос касается 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, он, вероятно, и в них работает.

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

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

В соответствии с документом Intel по реорганизации филиалов и циклов для предотвращения ошибочных прогнозов:

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

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

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

потому что оптимизатор MSVC от VS10 игнорирует такую ​​"подсказку".

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

__assume должен быть похожим.

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

Теперь MS сказал, что они реализовали вероятные / маловероятные атрибуты

Но на самом деле нет никакой разницы между использованием «вероятно» или «неиспользованием».

Я скомпилировал эти коды и получил тот же результат .

          int main()
    {
        int i = rand() % 2;
        if (i) [[likely]]
        {
           printf("Hello World!\n");
        }
        else
        {
            printf("Hello World2%d!\n",i);
        }
    }
          int main()
    {
        int i = rand() % 2;
        if (i)
        {
           printf("Hello World!\n");
        }
        else [[likely]]
        {
            printf("Hello World2%d!\n",i);
        }
    }
      int pdb._main (int argc, char **argv, char **envp);
0x00401040      push    ebp
0x00401041      mov     ebp, esp
0x00401043      push    ecx
0x00401044      call    dword [rand] ; pdb.__imp__rand
                                   ; 0x4020c4
0x0040104a      and     eax, 0x80000001
0x0040104f      jns     0x401058
0x00401051      dec     eax
0x00401052      or      eax, 0xfffffffe ; 4294967294
0x00401055      add     eax, 1
0x00401058      je      0x40106d
0x0040105a      push    str.Hello_World ; pdb.___C__0O_NFOCKKMG_Hello_5World__CB_6
                                   ; 0x402108 ; const char *format
0x0040105f      call    pdb._printf ; int printf(const char *format)
0x00401064      add     esp, 4
0x00401067      xor     eax, eax
0x00401069      mov     esp, ebp
0x0040106b      pop     ebp
0x0040106c      ret
0x0040106d      push    0
0x0040106f      push    str.Hello_World2_d ; pdb.___C__0BB_DODJFBPJ_Hello_5World2__CFd__CB_6
                                   ; 0x402118 ; const char *format
0x00401074      call    pdb._printf ; int printf(const char *format)
0x00401079      add     esp, 8
0x0040107c      xor     eax, eax
0x0040107e      mov     esp, ebp
0x00401080      pop     ebp
0x00401081      ret

Поскольку вопрос старый, ответы о том, что в MSVC нет / или что нет никакого воздействия, устарели.

Последняя версия MSVC поддерживает [[likely]] / [[unlikely]] в /std:c++20 а также /std:c++latest режимы.

См. Демонстрацию в обозревателе компилятора Godbolt, которая показывает разницу.

Как видно из приведенной выше ссылки, один видимый эффект на x86 / x64 для if-elseУтверждение состоит в том, что условный переход вперед будет для маловероятной ветви. До C++20 и поддерживающей версии VS этого же можно было добиться, поместив вероятную ветвь в if часть, и маловероятное разветвление в else часть, отрицая условие по мере необходимости.

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

Другие вопросы по тегам