Skip to content

Tracing and Instrumentation

The instrumentation system provides debugging, profiling, and monitoring capabilities for the kernel.

Overview

The Tracer collects: - Events: Timestamped records of kernel operations - Performance Counters: Timing and count statistics per operation - Kernel Statistics: Process, signal, timer, and I/O metrics

┌────────────────────────────────────────────────────────┐
│                      Tracer                            │
│  ┌──────────────────────────────────────────────┐      │
│  │              Event Ring Buffer               │      │
│  │  [Event 1] [Event 2] [Event 3] ... [Event N] │      │
│  │  (max 1000 events, oldest evicted first)     │      │
│  └──────────────────────────────────────────────┘      │
│                                                        │
│  ┌──────────────┐  ┌────────────────┐  ┌────────────┐  │
│  │ SyscallStats │  │ SchedulerStats │  │KernelStats │  │
│  │ open: 42     │  │ ticks: 1000    │  │ spawned: 5 │  │
│  │ read: 156    │  │ avg: 0.5ms     │  │ signals: 3 │  │
│  │ write: 89    │  │ max: 2.1ms     │  │ timers: 12 │  │
│  └──────────────┘  └────────────────┘  └────────────┘  │
└────────────────────────────────────────────────────────┘

Quick Start

use axeberg::kernel::syscall::{trace_enable, trace_summary, trace_event};
use axeberg::kernel::TraceCategory;

// Enable tracing
trace_enable();

// Record custom events
trace_event(TraceCategory::Custom, "startup", Some("initializing"));

// Get summary
let summary = trace_summary();
println!("{}", summary);  // Pretty-printed stats

Event Categories

pub enum TraceCategory {
    Syscall,     // Syscall entry/exit
    Process,     // Process lifecycle (spawn, exit, signal)
    Memory,      // Memory operations (alloc, free, shm)
    Timer,       // Timer events (set, fire, cancel)
    Signal,      // Signal delivery
    Scheduler,   // Task scheduling
    File,        // File operations
    Ipc,         // IPC operations
    Compositor,  // Compositor/window events
    Custom,      // User-defined events
}

API Reference

Control Functions

Function Description
trace_enable() Enable tracing
trace_disable() Disable tracing
trace_enabled() Check if tracing is on
trace_reset() Clear all events and stats

Event Recording

// Record a simple event
trace_event(TraceCategory::File, "open", None);

// Record with detail
trace_event(TraceCategory::File, "open", Some("/etc/passwd"));

Getting Statistics

let summary = trace_summary();

println!("Uptime: {:.2}s", summary.uptime / 1000.0);
println!("Syscalls: {}", summary.syscall_count);
println!("Errors: {}", summary.syscall_errors);
println!("Avg tick: {:.3}ms", summary.avg_tick_time);

TraceSummary Fields

Field Type Description
uptime f64 Time since trace_enable (ms)
enabled bool Whether tracing is on
event_count usize Events in buffer
syscall_count u64 Total syscalls
syscall_errors u64 Failed syscalls
tick_count u64 Scheduler ticks
avg_tick_time f64 Average tick duration (ms)
max_tick_time f64 Maximum tick duration (ms)
processes_spawned u64 Processes created
processes_exited u64 Processes exited
signals_delivered u64 Signals sent
timers_fired u64 Timers that fired
bytes_read u64 Total bytes read
bytes_written u64 Total bytes written

Performance Counters

Each syscall category has performance counters:

pub struct PerfCounters {
    pub count: u64,       // Total calls
    pub total_time: f64,  // Total time (ms)
    pub min_time: f64,    // Minimum call time
    pub max_time: f64,    // Maximum call time
    pub errors: u64,      // Error count
}

impl PerfCounters {
    pub fn avg_time(&self) -> f64;      // Average time per call
    pub fn success_rate(&self) -> f64;  // Success ratio (0.0-1.0)
}

Event Filtering

Filter events by category:

KERNEL.with(|k| {
    let tracer = k.borrow().tracer();

    // Get only syscall events
    let syscalls = tracer.events_by_category(TraceCategory::Syscall);

    // Get events for a specific process
    let pid1_events = tracer.events_by_pid(1);
});

Category Filtering

Only trace specific categories:

KERNEL.with(|k| {
    let tracer = k.borrow_mut().tracer_mut();

    // Only trace syscalls and memory operations
    tracer.set_filter(Some(vec![
        TraceCategory::Syscall,
        TraceCategory::Memory,
    ]));
});

Ring Buffer

The event buffer holds up to 1000 events. When full, oldest events are evicted:

const TRACE_BUFFER_SIZE: usize = 1000;

// Events are stored in a VecDeque
// New events push to the back
// When full, pop from the front

Pretty-Printed Output

TraceSummary implements Display:

=== Kernel Statistics ===
Uptime: 1.50s
Tracing: ON
Events buffered: 42

--- Syscalls ---
Total: 156
Errors: 2

--- Scheduler ---
Ticks: 1000
Avg tick: 0.500ms
Max tick: 2.100ms

--- Processes ---
Spawned: 5
Exited: 2

--- Events ---
Signals: 3
Timers: 12

--- I/O ---
Read: 4096 bytes
Written: 1024 bytes

Use Cases

Debugging

trace_enable();
// ... run problematic code ...
let events = KERNEL.with(|k| k.borrow().tracer().events().clone());
for event in events {
    println!("[{:.2}] {} {}: {}",
        event.timestamp,
        event.category,
        event.name,
        event.detail.unwrap_or_default());
}

Performance Analysis

trace_enable();
// ... run workload ...
let summary = trace_summary();

if summary.max_tick_time > 16.0 {
    println!("Warning: Tick exceeded frame budget!");
}

println!("Syscall rate: {:.1}/tick",
    summary.syscall_count as f64 / summary.tick_count as f64);

Monitoring

// Periodic health check
fn health_check() {
    let summary = trace_summary();

    if summary.syscall_errors > 100 {
        warn!("High error rate detected");
    }

    if summary.avg_tick_time > 10.0 {
        warn!("Scheduler is slow");
    }
}

Implementation Notes

  • Tracing is disabled by default (zero overhead when off)
  • Events are only recorded when tracing is enabled
  • Statistics are always collected (minimal overhead)
  • The ring buffer prevents unbounded memory growth
  • All timestamps are in milliseconds from kernel time