Подсказка для предсказания ветвлений в утверждениях

У меня есть обычай ASSERT(...) макрос, который я использую в приложении C ++.

#include <stdlib.h>
#include <iostream>

/// ASSERT(expr) checks if expr is true.  If not, error details are logged
/// and the process is exited with a non-zero code.
#ifdef INCLUDE_ASSERTIONS
#define ASSERT(expr)                                                      \
if (!(expr)) {                                                        \
char buf[4096];                                                   \
snprintf (buf, 4096, "Assertion failed in \"%s\", line %d\n%s\n", \
__FILE__, __LINE__, #expr);                              \
std::cerr << buf;                                                 \
::abort();                                                        \
}                                                                     \
else // This 'else' exists to catch the user's following semicolon
#else
#define ASSERT(expr)
#endif

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

Утверждения, по определению, должны быть оценены как истинные (т.е. likely).

Могу ли я предоставить аналогичную подсказку в моем ASSERT макрос? Какой основной механизм здесь?

Очевидно, что я буду измерять разницу в производительности, но теоретически это должно иметь значение?

Я запускаю свой код только в Linux, но было бы интересно узнать, есть ли кросс-платформенный способ сделать это тоже. Я также использую gcc, но хотел бы также поддержать clang.

13

Решение

Увеличение производительности вряд ли будет значительным, но именно так определяются эти макросы ядра Linux:

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

Таким образом, вы можете изменить свое состояние следующим образом (при условии, что expr как ожидается, будет правдой и, следовательно, !(expr) как ожидается, будет ложным):

if (__builtin_expect(!(expr), 0)) {

Или вы можете определить те же макросы, что и ядро, и использовать их для лучшей читаемости.

Это встроенный gcc, поэтому не переносимый, конечно.

это предполагает, что Clang также поддерживает встроенный. В противном случае вы можете использовать вышеупомянутые макросы и условно определять их как #define likely(x) (x) на компиляторах, которые не поддерживают встроенные.

В вашем случае предсказание будет хорошим (либо это, либо вы прерываете работу), поэтому не должно быть риска пессимизации, но если вы все-таки подумаете об использовании встроенной функции более широко, вот несколько советов от gcc документация:

В общем, вы должны предпочесть использовать реальную обратную связь профиля (-fprofile-arcs), так как программисты, как известно, плохо предсказывают, как на самом деле работают их программы.

14

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

Для многих процессоров, likely а также unlikely (или что-нибудь еще в этом отношении) не предоставляют подсказку ветвления для ЦП (только для компилятора, который может использовать его для оптимизации по-разному, аналогично оптимизации по профилю) по той простой причине, что нет способа сделать это ,

Например, подсказки веток определены для x86 начиная с P4. До этого они не имели никакого эффекта, но, что еще хуже, они ни на что не влияли, кроме P4. Так что они бесполезны (но тратят пространство и пропускную способность), и, насколько я знаю, GCC их не излучает.

У ARM нет (еще?) Подсказок о ветвях. У PPC, IA64 и SPARC действительно есть подсказки, я не знаю, использует ли GCC likely а также unlikely хотя для них, но, по крайней мере, это возможно.

10

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

extern void abort (void) __THROW __attribute__ ((__noreturn__));

и в Visual Studio 2013:

_CRTIMP __declspec(noreturn) void __cdecl abort(void);
2
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector