본문 바로가기
Program Language/C

[C] likely/unlikely macros

by Leo 리오 2012. 12. 14.
반응형

http://kerneltrap.org/node/4705


아래처럼 define 되는 likely라는 매크로가 있다.

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



이것은 어떤 기능을 할까?

 if (__builtin_expect (x, 0))
                foo ();

위와같은 코드가 있다고 할 때, 컴파일러는 x가 0이 될 확률이 높다는걸 '알게'된다.

그럼 foo 함수를 실행할 가능성이 적어지고, 컴파일러가 최적화를 할 가능성이 커진다.



구체적인 예를 보자.

int
testfun(int x)
{
        if(x) {
                x = 5;
                x = x * x;
        } else {
                x = 6;
        }
        return x;
}

함수 testfun은 인자 x로 어떤값이 들어올지 모른다. 

레귤러하게 분포된다면, 

x = 6이 될 확률은 1/2^32 이 될 것이다.



그러나, __builtin_expect()을 씀으로써, x는 '거의' 0임을 알려준다.

[kedar@ashwamedha ~]$ cat abc.c
int
testfun(int x)
{
        if(__builtin_expect(x, 0)) {
                              ^^^--- We instruct the compiler, "else" block is more probable
                x = 5;
                x = x * x;
        } else {
                x = 6;
        }
        return x;
}
 
[kedar@ashwamedha ~]$ gcc -O2 -c abc.c
[kedar@ashwamedha ~]$ objdump  -d abc.o
 
abc.o:     file format elf32-i386
 
Disassembly of section .text:
 
00000000 :
   0:   55                      push   %ebp
   1:   89 e5                   mov    %esp,%ebp
   3:   8b 45 08                mov    0x8(%ebp),%eax
   6:   85 c0                   test   %eax,%eax
   8:   75 07                   jne    11 < testfun+0x11 >
                                ^^^ --- The compiler branches the "if" block and keeps "else" sequential
   a:   b8 06 00 00 00          mov    $0x6,%eax
   f:   c9                      leave
  10:   c3                      ret
  11:   b8 19 00 00 00          mov    $0x19,%eax
  16:   eb f7                   jmp    f < testfun+0xf >

생성된 어셈블러를 보면 x가 0이 아닐 때 점프(jne)를 한다.



[kedar@ashwamedha ~]$ cat abc.c
int
testfun(int x)
{
        if(__builtin_expect(x, 1)) {
                              ^^^ --- We instruct the compiler, "if" block is more probable
                x = 5;
                x = x * x;
        } else {
                x = 6;
        }
        return x;
}
                                                                                                    
[kedar@ashwamedha ~]$ gcc -O2 -c abc.c
[kedar@ashwamedha ~]$ objdump  -d abc.o
                                                                                                    
abc.o:     file format elf32-i386
                                                                                                    
Disassembly of section .text:
                                                                                                    
00000000 :
   0:   55                      push   %ebp
   1:   89 e5                   mov    %esp,%ebp
   3:   8b 45 08                mov    0x8(%ebp),%eax
   6:   85 c0                   test   %eax,%eax
   8:   74 07                   je     11 < testfun+0x11 >
                                ^^^ --- The compiler branches the "else" block and keeps "if" sequential 
   a:   b8 19 00 00 00          mov    $0x19,%eax
   f:   c9                      leave
  10:   c3                      ret
  11:   b8 06 00 00 00          mov    $0x6,%eax
  16:   eb f7                   jmp    f < testfun+0xf >

반대로, 위와 같은 경우엔 x가 0일 때 점프하게 된다.



Basic Block(코드의 순서)을 어떻게 배치하느냐에 따라서 성능은 달라 질 수있다.

(branch predictor가 없다면,) CPU는 PIPELINE으로 되있기 때문에 우선 branch는 무시하고, 있는 코드를 순서대로 실행하다 branch가 되야되면 파이프라인을 FLUSH시킨다. 그럼 성능이 떨어질 수 밖에 없다.


조그마한 성능도 중요한 임베디드나 커널 코드에 많이 쓰이는듯 하다.















반응형

'Program Language > C' 카테고리의 다른 글

LNK2005 already defined in LNK1169: one or more multiply defined symbols found  (0) 2012.11.27
다차원 배열  (0) 2012.10.03
#ifdef #else #endif #elifdef  (0) 2012.08.09
printf debugging  (0) 2012.06.19
sizeof  (0) 2012.06.04

댓글