얼마전에 알게된 매크로 함수이다. 리눅스 커널 코드에서 자주 볼수있는 likeyly(), unlikely() 함수가 있다.
이 두함수의 원형이 바로 __builtin_expect() 함수이고, 두 함수는 이 함수를 랩핑한 것이다.
우선 최적화를 사용하는 이유 부터 소개하고, 그다음으로 likely(), unlikely() 함수에 대한 소개를 하고 마지막으로 __builtin_expect() 함수를 소개 해야될 것 같다. gcc 컴파일러를 이용하는 경우에 사용할 수 있다.


0. Before

본 내용에 들어가기에 앞서, if()문 사용에 있어 최적화 하는 이유는 분기 예측(branch prediction)과 관련 되어있다.
이를 사용하면 명령어 파이프라인이 깨지지 않도록 하여 성능을 향상 시킬수 있다. 하지만 조건문(if문, switch문)을 사용하면 분기 예측이 쉽지 않다. 이를 __builtin_expect() 함수를 통해 미리 컴파일러에게 알려주면, 컴파일러는 이를 토대로 최적화를 통해 프로그램의 성능을 향상 시킬수 있다.

  • 분기 예측(branch prediction)은 cpu 에서 다음에 실행될 명령어를 미리 예측하는 것을 의미한다.
  • 명령어 파이프라인은 한번에 하나의 명령어만 수행하는 것이 아니라 명령어 수행도중 다른 명령어를 수행하는 기법이다.

1. likely(), unlikely() 함수

likely(), likely() 함수는 컴파일러가 프로그래머가 작성한 코드를 최적화 하여 성능을 향상 시키는 함수이다.
결과적으로 사용한다고, 성능을 제외한 직접적으로 프로그램의 동작에 영향을 주는 함수는 아니다.
함수는 컴파일러에게 if문 내부의 결과가 참, 거짓 중 어느것이 더 많은 쪽에 속할지 미리 알려주는 기능을 한다.
컴파일러는 이를 토대로 더 빠르게 실행되도록 최적화를 할 수 있다. 이름에서 부터 눈치를 챌 수 있겠지만, likely() 는 참, unlikely()는 거짓일것 임을 컴파일러에게 미리 알려준다.

1.1 Include

likely(), unlikely() 함수는 <include/linux/compiler.h>에 선언되어있다.
다만, __builtin_expect() 함수는 gcc 내장함수이다.

#include <include/linux/compiler.h>

1.2 Function

함수의 원형은 다음과 같다.

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

1.3 Parameters

likely(), likely() 함수는 1개의 파라미터를 갖습니다.
두함 수 모두 동일한 파라미터를 사용하되,
likely()는 참의 값이 주로 오는 경우, unlikely()는 반대의 경우임을 명심 하고 사용합니다.

  • x
    • if 문의 대괄호 내부에 사용되는 함수이므로 결과 값이 참, 거짓으로 구분될 수 있는 조건식
      • if(x>0){ … } 에서 x>0 과 같은 조건식

1.4 Example

if (unlikely(fd < 0)){
    error();
}

1.4 Comment

편리한데로 사용하면 되지만, likely(), unlikely() 함수 매크로 두 줄을 그대로 복사해서 사용하는 경우도 있는 것 같다.
반면에 원형 그대로 __builtin_expect() 함수를 사용하는 경우도 있는 것 같다.
아니면 linkely(), unlikely()를 매크로 함수로 한번 더 랩핑 해서 사용하는 경우도 보았다.
아마 이름이 애매모호하다고 생각해서 그렇게 사용한게 아닐까 싶은데, 사용자가 편한데로 사용하면 될 것 같다.


2. __builtin_expect() 함수

__builtin_expect() 함수는 gcc의 내장 함수이다. 따로 헤더를 선언하지 않고도 사용이 가능하다.

2.1 Example

if (__builtin_expect(ptr != NULL, 1)){
    error ();
}

2.2 Parameters

__builtin_expect() 함수는 likely(), likely()에서 추가된 1개의 파라미터를 갖습니다.
첫번째 파리미터는 likely(), likely()와 동일합니다.
그러나 두번째 파라미터는 true, false를 나타내기 위해 사용합니다.

  • x
    • if 문의 대괄호 내부에 사용되는 함수이므로 결과 값이 참, 거짓으로 구분될 수 있는 조건식
      • if(x>0){ … } 에서 x>0 과 같은 조건식
  • 1 또는 0
    • 조건식의 예상되는 결과 값 (1 - 참, 0 - 거짓)

2.3 Comment

함수의 원형 그대로 사용하려면, likely(), unlikely()를 사용할때 보다 파라미터 하나를 더 추가해서 사용해야 하기 때문에, 복사해서 사용하던가, likely(), unlikely()의 이름이 맘에 안들면 다른 이름으로 랩핑해서 사용해도 될 것 같다.
주로 사용되는 곳은 사용자마다 따라 다르겠지만, 난 메모리를 동적으로 할당해서 사용하는 경우에 사용한다.
할당 후 할당 되어있는지 확인할때 사용하는데, 메모리 할당에 실패하는 경우보다는 성공하는 경우가 많기 때문이다.
반면에 결과 값 예측이 어려운 경우에는 사용하지 않고 컴파일러에게 맡기는 편이 좋겠다.