36940db938a8f4a1e919496793ed439850a221c2의 공식 문서·소스를 기준으로 새로 썼다. 그림의 이벤트 열과 시간 간격은 구조를 설명하는 가상 예시이며 실제 보드 측정치가 아니다. 주 경로는 기본 로깅과 다른 CTF 트레이싱이다.1. 어떤 질문을 풀려고 기록하는가
기존 Thread / Scheduler 글은 스레드가 실행 후보가 되는 조건과 선점 판단을 설명한다. Logging 글은 LOG_INF() 같은 메시지의 필터·처리·백엔드 경로를 다룬다. 트레이싱은 커널의 지정된 훅에서 사건을 기록해 실행의 순서와 상대적 시점을 재구성하는 도구다. 이벤트를 봤다고 해서 스케줄러의 모든 원인이나 코드의 모든 상태가 기록됐다고 말할 수는 없다.
| 층 | 주 입력 | 답하기 좋은 질문 | 여기서 알 수 없는 것 |
|---|---|---|---|
| 스케줄러 구현 | ready 상태·우선순위·선점 조건 | 다음 실행 후보를 어떻게 고르는가 | 특정 기기에서 실제로 언제 일어났는가 |
| Logging | 애플리케이션·모듈의 LOG_* 호출 | 어떤 메시지가 어떤 수준으로 출력됐는가 | 모든 스위치·ISR 경계가 자동으로 찍혔는가 |
| Tracing | 선택한 커널 훅·포맷 구현 | 관측된 이벤트의 순서·시각 차이는 무엇인가 | 미계측 코드와 유실된 이벤트의 원인 |
근거: 3.7.0 Tracing overview, Logging 문서, tracing_macros.h 비활성 훅.
2. 훅은 관측점이고, 포맷과 수송은 그다음 선택이다
CONFIG_TRACING=n이면 SYS_PORT_TRACING_FUNC 계열은 빈 매크로다. 켠 뒤에도 Kconfig의 기본 포맷은 TRACING_NONE이므로 실제 기록을 위해 CTF·SystemView·user-defined 등 포맷을 선택해야 한다. CONFIG_TRACING_THREAD·CONFIG_TRACING_ISR 같은 범주 옵션도 어떤 훅을 보낼지 결정한다. Zephyr v3.7.0의 CONFIG_TRACING=y는 thread-switch 계측 옵션을 선택하지만, 이것만으로 특정 파일이나 호스트 시각화가 자동 생성되는 것은 아니다.
↔ 좁은 화면에서 커널 훅부터 호스트 뷰어까지 오른쪽으로 이동해 읽으세요.
z_thread_mark_switched_in() 같은 경로가 trace 훅을 호출한다. 비활성 범주는 여기서 빈 동작.tracing_ctf.h가 훅을 ctf_top.c 이벤트로 연결한다. 모든 훅이 CTF 이벤트가 되는 것은 아니다.TRACING_CTF_TIMESTAMP=y일 때만 앞에 붙는다.metadata가 필요하다. 제공된 파일은 timestamp 필드를 전제한다.화살표는 데이터 경계이며 물리적인 실시간 전송 완료 보증이 아니다. async는 백엔드 출력보다 앞서 이벤트를 기록한다.
근거: Tracing Kconfig 8–105행, thread.c switch 훅, CTF 훅 연결과 빈 구현, CTF_EVENT 직렬화.
3. 이벤트는 시간축의 점이지 원인 설명문이 아니다
CTF에는 thread_switched_in/out, isr_enter, isr_exit, isr_exit_to_scheduler 같은 이벤트 ID가 있다. 다음 그림은 이 종류를 엮어 만든 가상 단일 CPU 기록 예시다. 실제 장비나 샘플 실행 결과가 아니며, 모든 ISR이 스레드를 바꾸는 것도 아니다.
↔ 좁은 화면에서 t0부터 t4까지 좌우로 이동해 보세요. 시간 간격은 축척이 아닙니다.
switched_in(A)isr_enterisr_exit_to_schedulerswitched_out(A)switched_in(B)t1→t2는 이 예시에서 ISR 경계를 찾는 쌍이고, t3→t4는 전환 관측점이다. 둘 다 실제 수행 시간의 정확한 측정치로 읽으려면 훅 비용·시계 해상도·이벤트 유실을 별도로 평가해야 한다.
| 이벤트 | 말할 수 있는 것 | 그 점만으로 단정할 수 없는 것 |
|---|---|---|
thread_switched_in(B) | B가 실행으로 선택된 관측점 | B가 왜 ready였는지, 언제부터 대기했는지 |
isr_enter / isr_exit | 관측된 인터럽트 경계 | ISR 내부의 모든 함수·하드웨어 처리 |
isr_exit_to_scheduler | ISR에서 스케줄러로 향하는 출구 | 반드시 다른 스레드가 실행됐다는 결론 |
| 이벤트가 없음 | 그 파일에 해당 기록이 없음 | 사건 자체가 발생하지 않았다는 증명 |
CTF timestamp는 CONFIG_TRACING_CTF_TIMESTAMP=y(기본값)일 때 이벤트 직렬화에서 32비트 cycle counter를 nanosecond로 변환한 값을 32비트 필드에 넣는다. 이것은 벽시계가 아니며 긴 기록에서는 폭과 wrap 가능성을 확인해야 한다. async 방식이라도 timestamp는 나중에 백엔드가 쓰는 시각이 아니라 이벤트 생성 경로에서 붙는다.
CONFIG_TRACING_CTF_TIMESTAMP=n 이면 고정 CTF_EVENT 구현은 timestamp 필드 자체를 쓰지 않는다. 반면 제공된 tsdl/metadata의 event_header는 항상 32비트 timestamp 다음에 ID가 온다고 선언한다. 따라서 기본 metadata를 그대로 복사해 이 캡처를 해석하면 header 배치가 맞지 않는다. timestamp가 없는 header에 맞는 metadata를 준비하거나 기본 y 설정으로 다시 빌드해야 한다.근거: CTF 이벤트·timestamp 정의, CTF metadata event header, 3.7.0 시각화 도구.
4. 포맷, 전송 방식, 백엔드를 한 옵션으로 뭉치지 않는다
Kconfig는 트레이싱 포맷을 하나 고르고, CTF core에는 sync/async 전송 방식과 generic backend 선택이 더해진다. SystemView는 Zephyr의 별도 구현과 RTT를 사용한다. user-defined는 스레드 스위치·ISR·idle 등에 대응하는 함수를 앱이 구현하는 선택이다. 각 포맷이 모든 훅과 백엔드를 동일하게 지원한다고 가정하지 않는다.
| 선택 | 역할 | 3.7.0 조건·주의 |
|---|---|---|
TRACING=y + TRACING_CTF=y | 훅과 CTF 포맷·core | 포맷 기본값은 NONE. CTF를 명시하고 최종 .config 확인 |
TRACING_CTF_TIMESTAMP | CTF 이벤트 header 앞의 시각 필드 | 기본 y. n이면 제공된 metadata의 timestamp 있는 header와 불일치 |
TRACING_THREAD / TRACING_ISR | 스레드·ISR 범주 훅 | 둘 다 기본 y지만 포맷 구현이 실제 이벤트를 매핑했는지도 확인 |
TRACING_SYNC / TRACING_ASYNC | 현재 문맥 출력 / 링 적재 뒤 tracing thread 출력 | async가 기본. sync는 backend 지연을 현재 문맥에서 감당해야 함 |
TRACING_BACKEND_POSIX | native_sim 계열 파일 출력 | ARCH_POSIX 및 TRACING_SYNC에 의존 |
TRACING_BACKEND_USB | USB 출력 | USB_DEVICE_STACK 및 TRACING_ASYNC에 의존 |
TRACING_BACKEND_RAM | 디버거로 읽을 RAM 출력 | 링과 별도인 고정 용량의 최종 저장 공간 |
SEGGER_SYSTEMVIEW / TRACING_USER | RTT 기반 SystemView / 사용자 함수 | CTF generic backend 경로와 포맷을 구분 |
근거: 포맷·방식 Kconfig, 백엔드 Kconfig, SystemView 및 user-defined 문서.
5. 비동기 링과 RAM 백엔드 저장 공간은 같은 버퍼가 아니다
CTF core의 sync 경로는 이벤트를 만든 문맥에서 backend 호출까지 진행한다. async 경로는 형식화한 패킷을 TRACING_BUFFER_SIZE 링에 먼저 넣고, 별도 tracing_thread가 꺼내 backend로 보낸다. 링에 패킷을 모두 넣을 공간이 없으면 해당 적재는 실패하고 내부 drop 카운터가 증가한다. 따라서 async는 호출자 출력 지연을 줄이는 선택이지 무손실 기록 보장이 아니다.
↔ 좁은 화면에서 sync·async 두 경로와 공통 최종 저장소를 비교하세요.
TRACING_BUFFER_SIZE 링에 적재; 부족하면 이 패킷 드롭↓tracing_thread가 나중에 backend output 호출ram_tracing[RAM_TRACING_BUFFER_SIZE]에 다시 쓴다. 용량을 넘는 출력 묶음부터 출력이 중단되고 기존 내용을 덮어 순환 저장하지 않는다. async의 앞단 링과 다른 손실 지점이다. async thread가 링에서 꺼낸 묶음은 CTF 이벤트 한 개의 경계와 같지 않을 수 있다.동기·비동기 경로는 CTF core 구현에 관한 설명이다. RAM 백엔드는 두 경로 중 하나와 조합될 수 있다. POSIX 파일 backend는 Kconfig상 sync만 허용한다.
| 위치 | 설정·소스 | 용량을 넘으면 | 의미 |
|---|---|---|---|
| async 앞단 링 | TRACING_BUFFER_SIZE · tracing_buffer.c | 그 패킷 적재 실패, 내부 drop 카운터 증가 | 전송 thread가 늦으면 생산 이벤트를 잃음 |
| RAM backend 종단 | RAM_TRACING_BUFFER_SIZE · ram_tracing[] | 새 출력 거절; 이미 저장한 바이트 유지 | 링을 키워도 종단이 가득 차면 캡처가 늘지 않음 |
| POSIX 파일 backend | native_sim 실행 파일의 출력 파일 | 쓰기 실패 경고 경로를 확인 | RAM 용량 설정과 별개 |
6. 고정 3.7.0 문서의 native_sim 경로로 CTF를 읽기
하드웨어 없이 파일 경로를 익힐 때 공식 3.7.0 예시는 native_sim과 prj_native_ctf.conf를 쓴다. 이 설정은 TRACING=y, TRACING_CTF=y, TRACING_SYNC=y, TRACING_BACKEND_POSIX=y를 명시한다. timestamp는 끄지 않으므로 Kconfig 기본 y가 적용되고, 제공된 metadata의 timestamp 있는 header와 맞는다. 아래는 문서의 명령을 재구성한 절차이며 이 글에서 빌드를 실행했다는 뜻은 아니다.
west build -b native_sim samples/subsys/tracing -- -DCONF_FILE=prj_native_ctf.conf
mkdir data
cp $ZEPHYR_BASE/subsys/tracing/ctf/tsdl/metadata data/
./build/zephyr/zephyr.exe -trace-file=data/channel0_0
이후 data/metadata와 data/channel0_0를 같은 디렉터리로 TraceCompass 또는 babeltrace에 제공한다. 이 명령의 metadata 복사는 timestamp=y인 예시에 한한다. timestamp=n 캡처에는 timestamp 필드가 없는 event header와 일치하도록 metadata를 바꿔야 한다. -trace-file 인수는 POSIX backend의 파일 이름 옵션이다. 다른 보드·백엔드에는 이 파일 생성 방식이 그대로 적용되지 않는다.
| 조각 | 역할 | 빠지면 |
|---|---|---|
channel0_0 | POSIX backend가 쓴 이 실행의 바이너리 이벤트 스트림 | 사건의 실제 순서·데이터가 없음 |
metadata | 이 버전 CTF 이벤트 ID·필드·header 정의; 제공 파일은 timestamp 필드 가정 | 없거나 실제 header와 다르면 필드를 올바르게 해석하기 어려움 |
최종 .config | 포맷·timestamp·범주·방식·backend 확인 | header 불일치나 특정 이벤트 누락을 판별하기 어려움 |
근거: 3.7.0 Using Tracing, native CTF 샘플 설정, POSIX -trace-file 옵션.
7. “이벤트가 없다”를 해석하기 전의 점검 순서
- 빌드의 Zephyr commit, 보드, 최종
.config를 기록한다.TRACING뿐 아니라 포맷,TRACING_THREAD·TRACING_ISR, 방식과 backend를 따로 확인한다. - CTF 포맷에서 해당 훅이 실제 이벤트로 매핑되는지 확인한다. v3.7.0의 일부
sys_port_trace_*는 CTF 헤더에서 빈 매크로다. - async 링이 이벤트 생산 속도를 따라가는지, RAM backend를 골랐다면 최종 저장 공간이 찼는지 분리해 본다. 백엔드 파일·전송 오류도 별도로 확인한다.
- CTF 데이터의 timestamp y/n에 맞춰 metadata의 event header도 확인한다. timestamp를 쓴 경우 해상도·wrap과 계측 비용을 고려한다. 단일 이벤트의 부재를 코드 경로 부재의 증거로 쓰지 않는다.
8. 고정 버전 근거와 검증 범위
이 글은 Zephyr 3.7.0의 CTF 경로와 native_sim 파일 예시를 중심으로 소스와 문서를 대조했다. 특정 보드의 ISR 지속 시간, 손실률, 전송 대역폭을 측정하지 않았다. SystemView·Percepio·user-defined의 상세 프로토콜이나 모든 아키텍처 훅 구현을 전수 설명하지 않는다.