Compare commits
2 Commits
11d9ebe2b6
...
09457e56d4
| Author | SHA1 | Date | |
|---|---|---|---|
| 09457e56d4 | |||
| cd790cbf7e |
32
README.md
32
README.md
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
A lightweight, debug-only telemetry profiler for Rust applications. Shows thread activity and call stack hierarchy in real-time.
|
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
|
## Features
|
||||||
|
|
||||||
@@ -15,10 +15,14 @@ Inspired by RAD Telemetry - built in ~400 LOC with minimal dependencies.
|
|||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
Only 3 dependencies (~15 total including transitive):
|
Only 7 dependencies (~70 total including transitive):
|
||||||
- `minifb` - Window and framebuffer
|
- `minifb` - Window and framebuffer
|
||||||
- `crossbeam-channel` - Lock-free MPSC
|
- `crossbeam-channel` - Lock-free MPSC
|
||||||
- `once_cell` - Lazy statics
|
- `once_cell` - Lazy statics
|
||||||
|
- `fontdue`
|
||||||
|
- `procmacro2`
|
||||||
|
- `syn`
|
||||||
|
- `quote`
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
@@ -26,7 +30,7 @@ Only 3 dependencies (~15 total including transitive):
|
|||||||
|
|
||||||
```toml
|
```toml
|
||||||
[dependencies]
|
[dependencies]
|
||||||
teleprof = { path = "../teleprof" } # or from crates.io when published
|
teleprof = { path = "../teleprof" }
|
||||||
```
|
```
|
||||||
|
|
||||||
### In your code:
|
### In your code:
|
||||||
@@ -99,26 +103,6 @@ let work = || {
|
|||||||
- **Separate window**: Doesn't interfere with your app's rendering
|
- **Separate window**: Doesn't interfere with your app's rendering
|
||||||
- **Simple API**: Just `span!("name")` and you're done
|
- **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
|
## Examples
|
||||||
|
|
||||||
Run the included examples:
|
Run the included examples:
|
||||||
@@ -138,4 +122,4 @@ The bouncing ball example demonstrates:
|
|||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
MIT / Apache-2.0 (choose whichever you prefer)
|
???
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ impl Ball {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument]
|
||||||
fn main() {
|
fn main() {
|
||||||
// Start the telemetry window
|
// Start the telemetry window
|
||||||
teleprof::start();
|
teleprof::start();
|
||||||
@@ -49,7 +50,7 @@ fn main() {
|
|||||||
println!("- Flame graph rendering (all depth-N spans on row N)");
|
println!("- Flame graph rendering (all depth-N spans on row N)");
|
||||||
println!("- instrument_calls macro for automatic call instrumentation");
|
println!("- instrument_calls macro for automatic call instrumentation");
|
||||||
println!("- Runtime deduplication preventing double-wrapping");
|
println!("- Runtime deduplication preventing double-wrapping");
|
||||||
println!();
|
println!();
|
||||||
|
|
||||||
let mut window = Window::new(
|
let mut window = Window::new(
|
||||||
"Bouncing Ball",
|
"Bouncing Ball",
|
||||||
@@ -102,6 +103,7 @@ fn main_frame(
|
|||||||
teleprof::set_thread_name(format!("ColorPicker-{}", id));
|
teleprof::set_thread_name(format!("ColorPicker-{}", id));
|
||||||
pick_new_color(ball_clone);
|
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
|
// 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 {
|
fn update_physics(ball: &Arc<Mutex<Ball>>, dt: f32) -> bool {
|
||||||
let mut ball = ball.lock().unwrap();
|
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
|
// Using instrument_calls here too to see the breakdown of rendering
|
||||||
#[instrument_calls]
|
|
||||||
fn render(ball: &Arc<Mutex<Ball>>, framebuffer: &mut [u32]) {
|
fn render(ball: &Arc<Mutex<Ball>>, framebuffer: &mut [u32]) {
|
||||||
clear_background(framebuffer);
|
clear_background(framebuffer);
|
||||||
draw_ball(ball, framebuffer);
|
draw_ball(ball, framebuffer);
|
||||||
@@ -203,7 +204,6 @@ fn submit_frame() {
|
|||||||
thread::sleep(Duration::from_millis(2));
|
thread::sleep(Duration::from_millis(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument]
|
|
||||||
fn print_status(ball: &Arc<Mutex<Ball>>, frame: u32) {
|
fn print_status(ball: &Arc<Mutex<Ball>>, frame: u32) {
|
||||||
let ball = ball.lock().unwrap();
|
let ball = ball.lock().unwrap();
|
||||||
println!(
|
println!(
|
||||||
|
|||||||
@@ -11,6 +11,10 @@ let
|
|||||||
# Wayland support
|
# Wayland support
|
||||||
wayland
|
wayland
|
||||||
libxkbcommon
|
libxkbcommon
|
||||||
|
|
||||||
|
# Rust
|
||||||
|
rust-analyzer
|
||||||
|
|
||||||
];
|
];
|
||||||
in
|
in
|
||||||
mkShell {
|
mkShell {
|
||||||
|
|||||||
@@ -66,7 +66,22 @@ pub fn instrument_calls(_args: TokenStream, input: TokenStream) -> TokenStream {
|
|||||||
let mut visitor = CallInstrumenter;
|
let mut visitor = CallInstrumenter;
|
||||||
visitor.visit_block_mut(&mut input_fn.block);
|
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;
|
struct CallInstrumenter;
|
||||||
|
|||||||
1357
teleprof/src/lib.rs
1357
teleprof/src/lib.rs
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user