# Teleprof A lightweight, debug-only telemetry profiler for Rust applications. Shows thread activity and call stack hierarchy in real-time. Inspired by RAD Telemetry - built in ~1200 LOC with minimal dependencies. ## Features - **Unified thread tracks** with expandable call stacks (click headers to toggle) - **Collapsed view** shows when threads are active (easy to spot blocking) - **Expanded view** shows full call stack hierarchy with flame graph visualization - **Ongoing span support** for long-running functions (main loops, render threads) - **Pause mechanism** to freeze your application for inspection (Space bar) - **Monokai color palette** for easy visual distinction - **Incremental tree building** - only processes new spans each frame - **Ringbuffer storage** (~16MB, 1M events) for recent history - **Lock-free event recording** via MPSC channels ## Dependencies Only 7 direct dependencies (~70 total including transitive): - `minifb` - Window and framebuffer - `crossbeam-channel` - Lock-free MPSC - `once_cell` - Lazy statics - `fontdue` - Font rasterization - `procmacro2`, `syn`, `quote` - Proc macros ## Usage ### Add to your `Cargo.toml`: ```toml [dependencies] teleprof = { path = "../teleprof" } ``` ### In your code: ```rust fn main() { // Start the profiler window (separate thread) #[cfg(debug_assertions)] teleprof::start(); // Name your thread (optional, shows in UI) #[cfg(debug_assertions)] teleprof::set_thread_name("main"); game_loop(); } fn game_loop() { loop { teleprof::span!("main_frame"); update(); render(); } } fn update() { teleprof::span!("update"); // Your update code } fn render() { teleprof::span!("render"); // Your render code } ``` ## Controls - **Space**: Toggle pause (freezes ongoing spans at current time) - **Left click + drag**: Box select to zoom (click background not function) - **Right click + drag**: Pan timeline - **Scroll**: Zoom timeline horizontally - **Click track header**: Expand/collapse thread's call stack - **Escape**: Close profiler window ## How it works 1. `span!()` macro creates a `SpanGuard` that sends `SpanStart` on creation 2. When the guard drops, sends `SpanEnd` 3. Events are sent via lock-free MPSC channel 4. Window thread drains events into a fixed-size ringbuffer 5. Incrementally builds per-thread call trees (only processes new spans) 6. Renders unified thread tracks with expandable call stacks ## Design Goals - **Minimal overhead**: Lock-free event recording, incremental tree building - **Debug-only**: Compile out in release builds with `#[cfg(debug_assertions)]` - **Separate window**: Doesn't interfere with your app's rendering - **Simple API**: Just `span!("name")` and you're done - **Handle any thread pattern**: Long-lived, short-lived, thread pools (Rayon, etc.) ## Examples Run the included examples: ```bash # Multi-threaded physics simulation cargo run --example demo # Bouncing ball with color-picking thread (30 FPS) cargo run --example bouncing_ball ``` The bouncing ball example demonstrates: - Main thread running at 30 FPS with clear frame gaps - Background thread spawned on wall collision to pick colors - Clear visual separation between thread activities ## License ???