21.4.1.1.1. 가상 함수 테이블(vtable) 룩업 오버헤드를 제거하고 인라인(Inline) 확장을 유도하는 템플릿 메타프로그래밍
PX4의 ModuleBase 아키텍처가 CRTP 패턴을 채택함으로써 얻은 가장 기적적인 성과는 단연코 **성능(Performance)**이다.
우리는 앞서 21.4.1 단원에서 가상 함수(Virtual Function)가 V-Table을 뒤지느라 CPU 사이클을 낭비한다는 것을 배웠다. 하지만 C++ 템플릿 메타프로그래밍(Template Metaprogramming)은 단순히 이 룩업(Lookup) 지연 시간을 없애는 데 그치지 않고, 컴파일러 최고의 최적화 기술인 **인라인 확장(Inline Expansion)**까지 강제로 유도해 낸다.
이 단원에서는 펌웨어 바이너리 레벨에서 이 마법이 어떻게 일어나는지, 링커(Linker)의 시각에서 디스어셈블리(Disassembly) 하듯 파헤쳐보겠다.
1. V-Table의 포인터 널뛰기 제압
일반적인 다형성 상속에서 ModuleBase 포인터를 통해 module->Run()을 호출하면, 기계어는 다음과 같이 동작한다.
module포인터가 가리키는 메모리 덩어리의 헤더를 읽어 V-Table 주소를 얻는다.- V-Table 배열에서
Run()함수가 매핑된 오프셋(Offset)을 찾아 함수 포인터를 꺼낸다. - 그 함수 포인터 주소로 분기(Branch/Jump)한다.
하지만 CRTP를 쓴 PX4의 run_wrapper()는 기계어 레벨에서 위 과정을 완전히 소멸시킨다.
template<class T>
void ModuleBase<T>::run_wrapper() {
static_cast<T*>(this)->Run();
}
컴파일 타임에 T가 CustomApp이라는 것이 이미 결정되어 있으므로, C++ 컴파일러(GCC)는 위 함수를 어셈블리어로 번역할 때 지도를 뒤지는 코드를 싹 다 빼버린다. 대신, 아무런 조건 없이 무조건 CustomApp::Run()의 절대 주소(Absolute Address)로 점프(JMP)하라는 하드코딩된 기계어 한 줄만 남긴다.
2. 구원의 최적화 기법: 인라인(Inline) 확장
여기서 한발 더 나아가, 똑똑한 최신 GCC 컴파일러라면 점프 명령(JMP)마저 쓸데없는 짓이라고 여길 것이다.
CustomApp::Run()이라는 함수가 100% 명확하다면, 컴파일러는 아예 해당 함수의 껍데기를 벗겨내고 그 안에 들어있는 본문(Body) 코드 덩어리를 통째로 복사해서 run_wrapper()를 호출한 부모의 코드 위치에 직결(Paste)시켜 버린다.
이러한 기법을 **인라인 확장(Inline Expansion)**이라고 부른다.
함수 호출을 위해 CPU가 레지스터(Register)를 백업하고 스택(Stack) 포인터를 내리는 등의 숭고한 콜 스택 오버헤드(Call Stack Overhead)가 0(Zero)으로 증발해버리는 것이다.
2.1 템플릿과 인라인의 극적인 시너지
일반적인 C++ 코드에서 인라인 확장을 유도하려면 함수 앞에 inline 키워드를 덕지덕지 붙여야 하고, 그마저도 컴파일러가 무시하기 일쑤다. (특히 가상 함수 virtual에는 인라인 확장이 거의 100% 먹히지 않는다. 런타임에 무슨 객체가 올지 모르기 때문이다.)
하지만 PX4의 ModuleBase는 템플릿(Template) 클래스이다.
C++ 표준에 의해 템플릿 클래스의 멤버 함수들은 본질적으로 헤더 파일에 구현되어야 하며, 컴파일러는 이런 템플릿 함수들을 번역할 때 기본적으로(암묵적으로) 인라인 후보로 강력하게 취급한다.
결론적으로 PX4 시스템은 이 템플릿 메타프로그래밍의 특징을 극악무도하게 쥐어짜 내어, 겉보기엔 부모와 자식 간의 복잡하고 우아한 다형성 계층 구조를 띠고 있지만, 실제 플래시 메모리에 구워지는 기계어는 “그냥 하나의 긴 main 함수 코드“처럼 완벽하게 납작하고(Flat) 연속적인 0 오버헤드 코드로 컴파일되는 마법을 성취해 냈다.
인터페이스의 규격과 속도를 완벽하게 확보했다면, 이제 이 모듈이 우아하게 태어나고 죽을 수 있도록 통제하는 ’생명주기 제어 통제권’이 어떻게 관리되는지 다음 장(21.4.2)에서 탐구해 보도록 하자.