리눅스 소스코드를 보다 보면 조건문에서 가끔씩 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
'Linux(Centos or RHEL) > RHEL 기초' 카테고리의 다른 글
인터럽트? (0) | 2020.04.23 |
---|---|
프로세스를 TASK_RUNNING(CPU 실행) 상태로 바꾸는 함수...? (0) | 2020.04.23 |
sleep과 wait의 차이? (0) | 2020.04.22 |
프로세스를 TASK_UNINTERRUPTIBLE 상태로 바꾸는 함수...? (0) | 2020.04.22 |
프로세스를 TASK_RUNNING(실행 대기) 상태로 바꾸는 함수...? (0) | 2020.04.21 |