__init 매크로의 __section(.init.text) __cold notrace 의 의미

init/main.c 의 start_kernel 함수를 보면 다음과 같이 선언되어 있습니다.

asmlinkage void __init start_kernel(void)

위에서 __init 매크로는 한꺼번에 3 개의 속성을 함수에 부여하고 있는데요.
각각 무엇을 의미하는지 살펴보겠습니다.

가. __section(.init.text)

__section 매크로는 속성 지정자인 __attribute__ 를 통해 section 을 지정하는 역할을 합니다.

# define __section(S) __attribute__ ((__section__(#S)))

위와 같이 인자로 받은 S 라는 section 으로 지정해주는 매크로네요.
따라서, __section(.init.text)는 이 함수의 코드가 사용하는 section 을 .text 가 아니라 .init.text 로 하겠다는 의미입니다.
왜 이렇게 하는지에 대해서는 여기저기 설명들이 잘 나와있더군요.

한마디로 커널 초기화 때만 임시로 .init.text 라는 영역을 할당하여 이 함수를 사용하고, 다음부터는 다시 사용하지 않을 코드라서 사용된 메모리를 해제하려는 용도입니다.
__init 뿐 아니라 data 영역도 .init.data 섹션을 임시로 사용할 수 있도록 __initdata 라는 매크로도 정의되어 있습니다.

나. __cold 는 왜 사용하지 ?

attribute 의 속성 중에서 cold 를 보면 대강 왜 사용하는지를 짐작할 수 있습니다.

gnu gcc 매뉴얼

cold
The cold attribute is used to inform the compiler that a function is unlikely executed. 
The function is optimized for size rather than speed and on many targets it is placed into special subsection of the text section so all cold functions appears close together improving code locality of non-cold parts of program. 
The paths leading to call of cold functions within code are marked as unlikely by the branch prediction mechanism. It is thus useful to mark functions used to handle unlikely conditions, such as perror, as cold to improve optimization of hot functions that do call marked functions in rare occasions.

간단히 요약하면 다음과 같겠네요.

  • 잘 호출되지 않는 함수에 대해 cold 속성을 지정한다.
  • cold 로 지정된 것들은 text section 의 특별한 subsection 이라는 곳에 모아두어서,
  • non-cold 코드 부분들의 지역성(locality)를 높여준다.
  • cold 속성이 지정된 함수는 속도보다는 메모리 절약의 차원에서 최적화된다.
  • 해당 함수가 불리는 곳은 분기 예측을 위해 unlikely 로 처리한다.

다. notrace 는 무엇일까 ?

no_instrument_function 속성을 지정해주는 매크로입니다.
복습을 하다보니 스터디 시간에 디버깅을 막는다는 얘기를 했었는데 그게 정확한 얘기는 아닌 것 같네요.
궁금해서 좀 공부를 해보았습니다.

#define notrace __attribute__((no_instrument_function))

no_instrument_function
If -finstrument-functions is given, profiling function calls will be generated at entry and exit of most user-compiled functions. Functions with this attribute will not be so instrumented.

한마디로, 컴파일할 때 -finstrument-functions 옵션을 주면 대부분의 user-compiled 함수들로 들어갔다 나올 때마다 profiling 함수들이 호출되는데, 이 속성을 주면 그게 적용이 안된다는 겁니다.

여기서 profiling 함수가 무엇인지를 좀 이해할 필요가 있습니다.

특정 프로그램을 수행할 때 해당 프로그램에서 사용하는 함수들의 성능 정보들을 프로파일링할 수 있는데, 이 때 사용하는 툴 중의 하나가 gprof 입니다.
주로 성능 튜닝할 때 사용합니다.
어떤 함수가 몇번 호출되었고 얼마나 시간이 소요되었는지 등에 대한 자료를 뽑기 위해 통계 데이터를 쌓아줍니다.
우리는 이러한 툴의 성틍 통계 결과를 보고 어떤 함수를 튜닝해야하는지 짐작할 수 있습니다.
gprof 툴이 내부적으로 이러한 성능 프로파일링을 수행하기 위해 사용하는 함수가 바로 profiling 함수입니다.
GNU 매뉴얼을 보면 다음과 같이 -finstrument-functions 옵션을 설명하고 있습니다.

https://gcc.gnu.org/onlinedocs/gcc-4.5.1/gcc/Code-Gen-Options.html#index-finstrument_002dfunctions-2114

-finstrument-functions
Generate instrumentation calls for entry and exit to functions. Just after function entry and just before function exit, the following profiling functions will be called with the address of the current function and its call site. [...]
          void __cyg_profile_func_enter (void *this_fn,
                                         void *call_site);
          void __cyg_profile_func_exit  (void *this_fn,
                                         void *call_site);

함수를 들락날락할 때 __cyg_profile_func_enter 와 __cyg_profile_func_exit 라는 함수가 자동으로 호출된다는 것인데요.
함수에 들어갈 때 자동으로 __cyg_profile_func_enter 가 호출되고, 나갈 때 __cyg_profile_func_exit 함수가 호출되니,  해당 함수를 우리가 구현하면 그 곳에서 원하는 정보들을 어딘가에 마음대로쌓아둘 수 있겠군요.
gprof 같은 성능툴도 결국 이러한 profiling 함수 내에서 각종 데이터들을 쌓아두고 이것들을 최종적으로 우리에게 보여주는 겁니다.

아래 url 을 보면 해당 profiling 함수를 이용한 좋은 sample code 가 있습니다.  설명도 아주 잘 나와 있네요.
꼭 읽어보시고 sample code 도 돌려보세요. 제가 하는 설명들이 좀더 와닿을 것입니다.

http://balau82.wordpress.com/2010/10/06/trace-and-profile-function-calls-with-gcc/

결국 결론은 notrace 는 디버그를 못하게 막는 것과는 상관없이, -finstrument-functions 옵션을 주고 컴파일 하더라도 이 함수는 프로파일링 대상에서 제외하겠다는 의미입니다.

참고로 기본적으로 커널은 컴파일할 때 -finstrument-functions 옵션은 주지 않습니다.

You may also like...