Implement event tracing core - #80
Open
Synte-Peng wants to merge 5 commits into
Open
Conversation
Add CONFIG_DEBUG_TRACE (default off), DEBUG_EVENT_BUFFER_SIZE (256), and DEBUG_EVENT_STRUCT_SIZE (16) to config.h. Wire debug_trace.o into KERNEL_OBJS in Makefile.
X-macro ring-buffer tracer for lightweight kernel instrumentation. Architecture: - trace_events.h: single-source-of-truth event definitions, included 5 times with varying preprocessor state to generate enums, structs, inline writers, print functions, and a dispatch table. - debug_trace.h: the 5-pass X-macro engine, per-event typed always_inline write functions, and public API with compile-out stubs for CONFIG_DEBUG_TRACE=0. - debug_trace.c: fixed-stride ring buffer with dump/clear/count/ overwrites/get operations. Two interrupt-protection protocols: - SAFE: gates the buffer write with csrrci/csrsi to disable/restore interrupts. For call sites that do not already hold interrupt protection (e.g. NOSCHED sections). - RAW: skips gating. For call sites already executing inside interrupt-disabled sections (e.g. dispatch, CRITICAL_ENTER, or ISR context). Write cost is minimized: class structs use a union projection so only populated fields are stored; unused fields carry stale data from prior slots without per-event zeroing. When CONFIG_DEBUG_TRACE=0, all tracepoints compile to nothing.
Add 7 tracepoints to task.c: TASK_CREATE, TASK_DESTROY, TASK_SWITCH, TASK_DELAY, TASK_SUSPEND, TASK_RESUME, TASK_YIELD. Refactor mo_task_delay() and mo_task_suspend() to call _yield() directly instead of mo_task_yield(). mo_task_yield() now emits TASK_YIELD, so calling it from within mo_task_delay/suspend would double-trace (TASK_DELAY + TASK_YIELD, or TASK_SUSPEND + TASK_YIELD). The internal _yield() path is trace-free so each operation records exactly one event. Guard the previous_state capture in mo_task_cancel() with #if CONFIG_DEBUG_TRACE so the variable is compiled out when tracing is disabled.
There was a problem hiding this comment.
All reported issues were addressed across 6 files
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
debug_dump_events() held global interrupt-disable across up to 256 printf() calls. On a slow UART this delays timer dispatch and other interrupts for an unbounded amount of time. Fix by snapshotting the entire ring buffer into a static _tr_snap[] inside the critical section, then performing all printf output with interrupts re-enabled. All _tr_print_EVENT_* functions now take a buffer pointer instead of hard-coding debug_trace_buffer, and _tr_print_event() dispatches through it.
There was a problem hiding this comment.
All reported issues were addressed across 1 file (changes from recent commits).
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
Concurrent debug_dump_events() calls share the static _tr_snap[] buffer. Once interrupts are re-enabled for the printf loop the scheduler can switch to another task which, if it also calls dump, overwrites the snapshot and corrupts the first task's output. Add a volatile _tr_dumping flaginside the critical section. Re-entrant callers skip the dump entirely instead of blocking.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implement a compile-time type-checked kernel event tracing subsystem
backed by an X-macro ring buffer. Event writes are always-inlined with
zero overhead when CONFIG_DEBUG_TRACE=0.
generate enums, structs, inline writers, print functions, and dispatch
table. Adding an event is one line.
compile-time type checking on every trace call, zero function-call
overhead at runtime
TASK_SWITCH : 17 instructions.
TASK_CREATE : 26 instructions.
DEBUG_EVENT_STRUCT_SIZE (configurable, default 16 bytes), with a
union projection so only populated fields are stored
(1 instruction per direction, vs 3 for hal_interrupt_set)
CRITICAL_ENTER sections like TASK_CREATE), RAW events skip
gating (used where interrupts are already disabled, like
dispatch/TASK_SWITCH)
config.h, new fields added via __field in trace_events.h —
STATIC_ASSERT catches sizing errors at compile time
the entire tracing subsystem compiles to nothing
preserved
Supersedes #79.
Summary by cubic
Add a lightweight, type-checked kernel event tracing system with a fixed-size ring buffer and instrumented task lifecycle/switch events. Tracing is off by default, compiles out when CONFIG_DEBUG_TRACE=0, snapshots the buffer to shorten interrupt-off time in debug_dump_events, and now skips re-entrant dumps to avoid snapshot corruption.
New Features
include/sys/trace_events.h.Migration
Written for commit 04756f0. Summary will update on new commits.