Compare commits

...

2 Commits

5 changed files with 919 additions and 499 deletions

View File

@@ -2,7 +2,7 @@
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 ~400 LOC with minimal dependencies.
Inspired by RAD Telemetry - built in ~1200 LOC with 'minimal' dependencies (for a Rust project).
## Features
@@ -15,10 +15,14 @@ Inspired by RAD Telemetry - built in ~400 LOC with minimal dependencies.
## Dependencies
Only 3 dependencies (~15 total including transitive):
Only 7 dependencies (~70 total including transitive):
- `minifb` - Window and framebuffer
- `crossbeam-channel` - Lock-free MPSC
- `once_cell` - Lazy statics
- `fontdue`
- `procmacro2`
- `syn`
- `quote`
## Usage
@@ -26,7 +30,7 @@ Only 3 dependencies (~15 total including transitive):
```toml
[dependencies]
teleprof = { path = "../teleprof" } # or from crates.io when published
teleprof = { path = "../teleprof" }
```
### In your code:
@@ -99,26 +103,6 @@ let work = || {
- **Separate window**: Doesn't interfere with your app's rendering
- **Simple API**: Just `span!("name")` and you're done
## Example Output
```
┌─────────────────────────────────────┐
│ Icicle Graph (Call Stack) │
│ ┌──────────────────────────┐ │
│ │ frame_work │ │
│ ├──────────┬───────────────┤ │
│ │ physics │ render │ │
│ ├────┬─────┤ │ │
│ │ w0 │ w1 │ │ │
│ └────┴─────┴───────────────┘ │
├─────────────────────────────────────┤
│ Thread Timeline │
│ Main: ████████████████████ │
│ Work 0: ░░██████░░░░░░░░░░░ │
│ Work 1: ░░░░░░██████░░░░░░░ │
└─────────────────────────────────────┘
```
## Examples
Run the included examples:
@@ -138,4 +122,4 @@ The bouncing ball example demonstrates:
## License
MIT / Apache-2.0 (choose whichever you prefer)
???

View File

@@ -32,6 +32,7 @@ impl Ball {
}
}
#[instrument]
fn main() {
// Start the telemetry window
teleprof::start();
@@ -49,7 +50,7 @@ fn main() {
println!("- Flame graph rendering (all depth-N spans on row N)");
println!("- instrument_calls macro for automatic call instrumentation");
println!("- Runtime deduplication preventing double-wrapping");
println!();
println!();
let mut window = Window::new(
"Bouncing Ball",
@@ -102,6 +103,7 @@ fn main_frame(
teleprof::set_thread_name(format!("ColorPicker-{}", id));
pick_new_color(ball_clone);
});
let _ = COLOR_PICKER_COUNTER.fetch_update(Ordering::Relaxed,Ordering::Relaxed,|cnt| Some(cnt -1));
}
// Render - also instrumented, so dedup will handle it
@@ -118,7 +120,7 @@ fn main_frame(
}
}
#[instrument]
fn update_physics(ball: &Arc<Mutex<Ball>>, dt: f32) -> bool {
let mut ball = ball.lock().unwrap();
@@ -163,7 +165,6 @@ fn pick_new_color(ball: Arc<Mutex<Ball>>) {
}
// Using instrument_calls here too to see the breakdown of rendering
#[instrument_calls]
fn render(ball: &Arc<Mutex<Ball>>, framebuffer: &mut [u32]) {
clear_background(framebuffer);
draw_ball(ball, framebuffer);
@@ -203,7 +204,6 @@ fn submit_frame() {
thread::sleep(Duration::from_millis(2));
}
#[instrument]
fn print_status(ball: &Arc<Mutex<Ball>>, frame: u32) {
let ball = ball.lock().unwrap();
println!(

View File

@@ -11,6 +11,10 @@ let
# Wayland support
wayland
libxkbcommon
# Rust
rust-analyzer
];
in
mkShell {

View File

@@ -66,7 +66,22 @@ pub fn instrument_calls(_args: TokenStream, input: TokenStream) -> TokenStream {
let mut visitor = CallInstrumenter;
visitor.visit_block_mut(&mut input_fn.block);
TokenStream::from(quote! { #input_fn })
// Add an outer span for the function itself
let fn_name = input_fn.sig.ident.to_string();
let fn_vis = &input_fn.vis;
let fn_sig = &input_fn.sig;
let fn_block = &input_fn.block;
let fn_attrs = &input_fn.attrs;
let instrumented = quote! {
#(#fn_attrs)*
#fn_vis #fn_sig {
let _guard = ::teleprof::SpanGuard::new(#fn_name);
#fn_block
}
};
TokenStream::from(instrumented)
}
struct CallInstrumenter;

File diff suppressed because it is too large Load Diff