compiler-level if문 최적화
MariaDB 프로젝트에서는 likely
, unlikely
api를 사용하여 분기를 최적화한다.
__builtin_expect
long __builtin_expect (long expression, long value);
- 컴파일러에게 표현식이 어떤 값일 확률이 높다는 정보를 주는 방법이다. 컴파일러는 이 힌트를 이용해 최적화를 진행한다
- cpu는 instruction 실행의 병렬성(parallelism)을 높이기 위해 branch prediction을 진행한다
- instruction의 병렬성은 instruction pipelining을 통해 구현된다
value
에는 constant literal이 전달되어야 한다expression
의 결과가value
일 경우 성능이 향상되지만 그렇지 못할 경우에 대가를 치르기 때문에 신중하게 사용해야 한다- switch문에 대해서도 최적화가 가능하다
likely unlikely
/* Add checking if we are using likely/unlikely wrong */
#ifdef CHECK_UNLIKELY
C_MODE_START
extern void init_my_likely(), end_my_likely(FILE *);
extern int my_likely_ok(const char *file_name, uint line);
extern int my_likely_fail(const char *file_name, uint line);
C_MODE_END
#define likely(A) ((A) ? (my_likely_ok(__FILE__, __LINE__),1) : (my_likely_fail(__FILE__, __LINE__), 0))
#define unlikely(A) ((A) ? (my_likely_fail(__FILE__, __LINE__),1) : (my_likely_ok(__FILE__, __LINE__), 0))
/*
These macros should be used when the check fails often when running benchmarks but
we know for sure that the check is correct in a production environment
*/
#define checked_likely(A) (A)
#define checked_unlikely(A) (A)
#else
/**
The semantics of builtin_expect() are that
1) its two arguments are long
2) it's likely that they are ==
Those of our likely(x) are that x can be bool/int/longlong/pointer.
*/
#define likely(x) __builtin_expect(((x) != 0),1)
#define unlikely(x) __builtin_expect(((x) != 0),0)
#define checked_likely(x) likely(x)
#define checked_unlikely(x) unlikely(x)
#endif /* CHECK_UNLIKELY */
- MariaDB 프로젝트에서 최적화를 위해 사용하는 __builtin_expect 를 감싼 api
CHECK_UNLIKELY
매크로를 켜서 분기 예측의 hit, miss 여부에 관한 통계를 수집해서 unlikely, likely 사용 여부를 결정하는 방식이다
references
- [IBM Documentation] __builtin_expect
- Make __builtin_expect effective in switch statements (PR middle-end/PR59521).
- [WIKIPEDIA] Instruction Pipelining