19.4.2.3. 신규 데이터가 있을 때만 orb_copy()를 수행하여 CPU 점유율 최적화
앞선 19.4.2.2 단원 계단에서 우리는 orb_check()라는 초경량 매크로를 통해 매우 가볍고 우아하게 VFS 링 버퍼망의 갱신 플래그(Updated Flag)만을 단독으로 훔쳐보는 데 성공했다. 이제 커널이 들어 올려준 이 깃발(Flag)이 true로 펄럭일 때(updated == true), 비로소 그동안 아끼고 아껴왔던 무거운 무기인 orb_copy()의 족쇄를 풀고, 진짜 거대한 물리적 실시간 데이터 구조체 딥 카피(Deep Copy)를 감행하여 CPU의 극한 최적화를 피도 눈물도 없이 달성하는 최종 완성형 폴링(Polling) 코드를 마주할 차례이다.
1. 조건부 물리적 타격: 업데이트 확정 시에만 전개되는 orb_copy()
단순히 업데이트가 없으면 스레드를 재워버리고, 오직 스케줄러가 업데이트를 확정 지었을 때만 무거운 메모리 복사 블록 연산을 수행하게 만드는 이 조건부 구조는, 픽스호크 리눅스 시스템 코어 아키텍트를 평가하는 가장 잔혹하면서도 직관적인 실력 척도가 된다. 아래의 파괴적으로 최적화된 완성형 로직을 해부해 보자.
int sensor_sub_fd = orb_subscribe(ORB_ID(sensor_test_data));
// 이전에 읽어온 데이터의 타임스탬프를 혹시 모를 이중 검증용으로 복사해 둘 캐시 메모리 앵커
uint64_t last_processed_time = 0;
while (!thread_should_exit) {
bool updated = false;
orb_check(sensor_sub_fd, &updated);
if (updated) {
// ---- [오직 CPU 연산과 힙 메모리 할당이 허락된 유일한 통제 공간] ----
// 1. [핵심 최적화] 여기서만 비로소 무겁고 거대한 C++ 구조체를 힙/스택에 강제 할당한다.
// 데이터가 없을 때조차 스레드 상단에 구조체를 껍데기 선언해 버리는
// 그 하급생들의 미친 메모리 스택 점유 낭비조차 아끼기 위함이다.
sensor_test_data_s sensor_data_raw{};
// 2. 확정 보장된 새 데이터를 내 로컬 구조체 방 안으로 강제 딥 카피
orb_copy(ORB_ID(sensor_test_data), sensor_sub_fd, &sensor_data_raw);
// 3. (선택적 방어) orb_check()가 커널 버그나 레이스 컨디션으로 인해
// 가짜 기상 알람(False Alarm)을 울렸을 아주 희박한 경우를 대비비한, 타임스탬프 2중 빙벽 검증
if (sensor_data_raw.timestamp != last_processed_time) {
// 4. 이중 방어선을 통과했다면, 비로소 이 최신 데이터를 기반으로
// 무거운 코어 비행 제어 연산, 모터 PWM 믹싱 행렬 등의 치명적 알고리즘을 맘 놓고 박아버린다.
PX4_INFO("Perfectly Extracted Temp without CPU waste: %.2f", (double)sensor_data_raw.temperature);
// 5. 다음번 갱신 확인용으로 현재 생존 시간을 덮어써 방어벽 업데이트
last_processed_time = sensor_data_raw.timestamp;
} // End of Timestamp Double Checking
} // End of Update Check
// 6. 1초에 단 10번(10Hz)만 눈을 떠서 버퍼 껍데기를 가볍게 노크하도록 내 워커 스레드를 다시 깊은 수면 블로킹 시킴
px4_usleep(100000);
} // End of Daemon While Loop
2. CPU 점유율 최하단 대폭락의 마법 (기아 Starvation 완전 해소)
고작 변수 하나와 if 조건문 블록 하나 코드에 추가했을 뿐인데, 이 아키텍처가 거대한 픽스호크 펌웨어 시스템에 선사하는 물리적인 위력은 경이롭기 짝이 없다.
만약 건너편 퍼블리셔 데몬이 버그가 나서 픽스호크 링 버퍼에 데이터를 자그마치 한 시간(1 Hour) 동안 쏘지 않고 죽어 있다고 극한 가정해 보자.
- 단순 직진 읽기(Simple Read) 아키텍처 데몬: 매 루프 쿨타임마다 무식하게 깨어나서
sensor_test_data_s sensor_data_raw{};를 할당 선언하고,orb_copy로 32~60바이트를memcpy복사하고, 타임스탬프를 비교하고서야 “아놔 쓰레기네” 하고 버리는 미친 CPU 연산을 한 시간 동안 약 36,000번(10Hz 기준)이나 반복 수행한다. 픽스호크 보드의 물리적 온도가 치솟고 NSH 터미널에서top코어 관제 명령을 치면, 이 망할 스크립트의 CPU 점유율이 5% 이상을 갉아먹으며 빨간불을 내뿜는 것을 목격할 수 있다. - Update Check 방어벽 기반 데몬: 스레드가 깨어나서 고작 1바이트짜리
bool updated공간과 커널 레지스터 플래그만orb_check로 가볍게 비교해 본 뒤(“아직 안 왔네”), 복사 없이 곧바로 다시 잠들어 버린다. 그 무겁고 거대한sensor_data_raw구조체 컴파일 블록 스코프(Scope)는 메모리 링커에 아예 올려보지도 구경하지도 않는다. 이 경우top명령에서 해당 데몬의 CPU 점유율은 0.001% 미만으로 극한 수렴하며 펌웨어 시스템 상에서 그 존재감조차 완벽히 사라진 유령(Ghost) 상태가 된다.
이처럼 orb_check와 스코프 기반의 조건부 orb_copy의 결합은 단순한 C++ 코딩 스킬을 아득히 넘어선다. 극한으로 한정된 임베디드 코어 자원 환경에서, 내 스레드의 이기심을 버리고 다른 생존 스레드들의 숨통(CPU 캐시 라인)을 철저히 보호하는 아주 이타적이면서도 강력한 PX4 미들웨어의 절대 아키텍처 디자인 패턴(Design Pattern)이다.