본문 바로가기

Linux(Centos or RHEL)/RHEL 기초

linux에서 likely와 unlikely란?

리눅스 소스코드를 보다 보면 조건문에서 가끔씩 likey()unlikely()를 볼 수 있습니다. 프로그램에서의 조건문은 굉장히 중요한 것인데, 어떻게 동작하는 것인지는 알아야겠다는 생각이 들어서 한번 찾아 봤습니다.

 

likely()unlikely()“include/linux/compiler.h“에 정의되어있습니다.

얼핏 보면 반대의 동작을 하는 것 같은 느낌이 듭니다.

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

 

[https://elixir.bootlin.com/linux/v2.6.39.4/source/include/linux/compiler.h#L115]

 

 

자 그럼 실제로 어떤 동작을 하는가에 대해서 확인해 보겠습니다. 아래와 같이 테스트용 코드를 작성해 봅니다. 테스트는 CentOS 7.7에서 해 보았습니다.

a라는 int형 변수가 2일때에는 1을 더하고, 그 외에는 1을 빼는 조건문을 likely()unlikey()를 통해서 검사하는 코드입니다.

#include <stdio.h>

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

int main()
{
   int a;

   a = 2;
   printf ("likely test\n");
   printf ("a = %d\n",a);
   if (likely (a == 2))
      a++;
   else
      a--;
   printf ("after if a = %d\n", a);

   a = 1;
   printf ("a = %d\n",a);
   if (likely (a == 2))
      a++;
   else
      a--;
   printf ("after if a = %d\n", a);

   a = 2;
   printf ("\n");
   printf ("unlikely test\n");
   printf ("a = %d\n",a);
   if (unlikely (a == 2))
      a++;
   else
      a--;
   printf ("after if a = %d\n", a);

   a = 1;
   printf ("a = %d\n",a);
   if (unlikely (a == 2))
      a++;
   else
      a--;
   printf ("after if a = %d\n", a);
   return 0;
}

 

 

코드를 빌드 하고 실행시켜봅니다.

[root@centos77 likely]# cc likeyUnlikelyTest.c -o test

[root@centos77 likely]# ./test

likely test

a = 2

after if a = 3

a = 1

after if a = 0

 

unlikely test

a = 2

after if a = 3

a = 1

after if a = 0

[root@centos77 likely]#

 

likely나 unlikely나 같은 결과가 나왔습니다.

 

 

 

위의 코드에서 likey()unlikey()를 정의할 때 사용되는 __builtin_expect() 함수의 동작은 gcc의 문서에 정의되어 있습니다.

[https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html]

 

-- Built-in Function: long __builtin_expect (long EXP, long C)

You may use `__builtin_expect' to provide the compiler with branch

prediction information. In general, you should prefer to use

actual profile feedback for this (`-fprofile-arcs'), as

programmers are notoriously bad at predicting how their programs

actually perform. However, there are applications in which this

data is hard to collect.

 

The return value is the value of EXP, which should be an integral

expression. The value of C must be a compile-time constant. The

semantics of the built-in are that it is expected that EXP == C.

For example:

 

if (__builtin_expect (x, 0))

foo ();

 

would indicate that we do not expect to call `foo', since we

expect `x' to be zero. Since you are limited to integral

expressions for EXP, you should use constructions such as

 

if (__builtin_expect (ptr != NULL, 1))

error ();

 

when testing pointer or floating-point values.

 

 

간단하게 말하면 gcc 컴파일러가 코드를 컴파일할 때, 코드를 최적화하여 컴파일한다는 뜻입니다...

 

 

어떤 식으로 최적화를 한다는 것인지는 아래의 링크를 참고해 보시면 좋을 것 같습니다.

https://kernelnewbies.org/FAQ/LikelyUnlikely

 

FAQ/LikelyUnlikely - Linux Kernel Newbies

KernelNewbies: FAQ/LikelyUnlikely (2017-12-30 01:29:58에 localhost가(이) 마지막으로 수정)

kernelnewbies.org