21.10.2.1.1. `top` 출력 시 특정 모듈의 스택 가용량(Stack Margin)이 임계치(예: 100 bytes) 이하로 떨어질 때 스택 오버플로우를 예방하기 위한 CMake `STACK_MAIN` 재설정 기준

21.10.2.1.1. top 출력 시 특정 모듈의 스택 가용량(Stack Margin)이 임계치(예: 100 bytes) 이하로 떨어질 때 스택 오버플로우를 예방하기 위한 CMake STACK_MAIN 재설정 기준

기체를 띄워놓고 터미널 창에 top을 연타할 때, 다른 건 다 제치고 모듈의 스택 마진(Stack Margin, 할당량 - 사용량) 수치만 집요하게 추적해야 한다.
만약 내 payload_autodrop 모듈의 마진이 100 bytes 이하로 떨어지는 아슬아슬한 기록이 단 한 번이라도 관측되었다면, 그 코드는 곧 터질 시한폭탄과 같다.

언제 갑자기 예기치 못한 인터럽트나 복잡한 C++ 예외 처리 로직이 터지면서 남은 100바이트를 뚫고 램의 다른 구역(다른 프로세스의 메모리)을 침범해 버릴지 모르기 때문이다. (스택 오버플로우)

1. 스택 처방전: CMakeLists.txt 파헤치기

스택 마진이 부족하다면 두 가지 해결책이 있다. 첫째는 코드 내의 거대한 지역 변수(배열 등)를 줄이는 최적화이고, 둘째는 아예 처음부터 내 모듈이 OS로부터 배급받는 밥그릇(Stack)의 크기를 키워버리는 것이다.

우리가 21.3장에서 모듈을 처음 구상할 때 만들었던 src/modules/payload_autodrop/CMakeLists.txt 파일 안에는, 이 밥그릇의 크기를 결정하는 치명적인 매크로 변수가 하나 숨어있다. 바로 STACK_MAIN 이다.

# [src/modules/payload_autodrop/CMakeLists.txt]
px4_add_module(
    MODULE modules__payload_autodrop
    MAIN payload_autodrop
    STACK_MAIN 1200 # <-- [핵심] 이 모듈이 부팅될 때 커널로부터 할당받는 스택 바이트 수!
    COMPILE_FLAGS
        -Wno-sign-compare
    SRCS
        PayloadAutoDrop.cpp
    DEPENDS
        px4_work_queue
)

대부분의 PX4 예제 코드들을 복사해오면 저 STACK_MAIN 값이 1024 거나 1200 정도로 잡혀있다.
우리의 FSM 로직이나 1차 IIR 필터 공식 등은 지역 변수를 거의 쓰지 않으므로 1200바이트면 떡을 칠 용량이다.

하지만 만약 당신이 이 모듈 안에 **1) 무거운 매트릭스 계산(Eigen 라이브러리)**을 넣었거나, 2) printf 계열의 문자열 포매팅을 과도하게 쓰거나, 3) 객체를 깊숙이 복사하는 재귀 함수를 넣었다면 1200바이트의 스택은 순식간에 동이 난다.

2. 올바른 스택 증량법(Step-up Tuning)

top 로그에서 내 스택 마진이 50바이트, 10바이트 등 아슬아슬하게 찍힌다면, 이 STACK_MAIN 값을 200~300 바이트 단위로 찔끔찔끔 올려가며(Step-up) 최적의 한계선을 찾아야 한다.

# [수정 후: 매트릭스 연산 때문에 스택을 늘린 경우]
    STACK_MAIN 1500 

2.1 왜 무식하게 4000바이트씩 퍼주지 않는가?

단순히 “에이 귀찮아, 터지지 않게 넉넉하게 STACK_MAIN 4096 줘버리자!” 라고 생각할 수 있다.
이것이 최악의 하드웨어 리소스 낭비(Waste)다. 내가 쓰지도 않을 여백(Margin)을 3000바이트나 미리 틀어쥐고 있으면, 나침반이나 GPS 같은 필수 센서 데몬들이 부팅될 때 “램이 모자라서 못 켜겠는데요?” 하고 커널이 파업을 선언해 버린다.

따라서 진정한 PX4 아키텍트라면, 기체를 격렬하게 가동시킨 상태에서 top의 스택 마진이 안전 한계선인 200~300 bytes 정도가 아슬아슬하게 남도록 저 STACK_MAIN 숫자를 정밀하게 타이트닝(Tightening)해야 한다.

자, 메모리 단속까지 끝났다. 그러나 메모리는 넉넉한데 다른 뚱뚱한 데몬들 때문에 자꾸 내 FSM 로직의 대기 시간이 엿가락처럼 늘어진다면(Waiting Queue Time 병목), 이를 찢어버릴 최후의 리팩토링 무기가 필요하다. 21.10.2.1.2장, ‘공용 큐(Work Queue) 탈출 및 독립 스레드 분리(Offloading)’ 전략으로 시스템 아키텍처를 뒤엎어보자.