name: hotpath-rs description: Use when profiling Rust applications with pawurb/hotpath-rs: timing, allocations, CPU sampling, Tokio runtime metrics, async channels/streams/futures, static reports, live TUI, MCP server integration, or AI-assisted performance analysis.
Hotpath Rust
Use these conventions for Rust performance profiling with pawurb/hotpath-rs.
Source Baseline
- Prefer current docs from
hotpath.rs, docs.rs, crates.io, and the matching GitHub release. - Current baseline checked for this skill:
hotpath 0.16.1. hotpathinstruments Rust code for wall-clock timing, allocations, CPU samples, thread stats, async data flow, Tokio runtime metrics, static reports, live TUI dashboards, and MCP access for AI agents.- Keep profiling behind local crate features. With the main
hotpathfeature disabled, instrumentation macros are noops. - Treat JSON report formats, TUI internals, MCP internals, and advanced configuration as evolving surfaces.
Cargo
Keep hotpath optional and expose profiling as explicit application features:
[dependencies]
hotpath = "0.16.1"
[features]
hotpath = ["hotpath/hotpath"]
hotpath-alloc = ["hotpath/hotpath-alloc"]
hotpath-cpu = ["hotpath/hotpath-cpu"]
hotpath-mcp = ["hotpath/hotpath-mcp"]
hotpath-tokio = ["hotpath/hotpath", "hotpath/tokio"]
For Tokio applications, keep the normal Tokio dependency explicit:
[dependencies]
tokio = { version = "1", features = ["macros", "rt-multi-thread", "sync", "time"] }
hotpath = "0.16.1"
Add channel-family features only for the channel APIs actually used:
[features]
hotpath-data-flow = ["hotpath/hotpath", "hotpath/tokio", "hotpath/futures"]
Basic Function Profiling
Use #[hotpath::main] to create the profiling guard and #[hotpath::measure] for the functions worth observing.
use std::time::Duration;
#[hotpath::measure]
fn parse_batch(items: &[String]) -> usize {
std::thread::sleep(Duration::from_millis(2));
items.iter().map(String::len).sum()
}
#[hotpath::measure(log = true, label = "load_user")]
async fn load_user(id: u64) -> String {
tokio::time::sleep(Duration::from_millis(5)).await;
format!("user-{id}")
}
#[tokio::main]
#[hotpath::main(percentiles = [50, 95, 99], report = "functions-timing,functions-alloc,threads")]
async fn main() {
let items = vec!["alpha".to_owned(), "beta".to_owned()];
for id in 0..100 {
let _bytes = parse_batch(&items);
let _user = load_user(id).await;
hotpath::measure_block!("serialize_response", {
std::hint::black_box(format!("response-{id}"));
});
}
}
Run static timing reports with:
cargo run --features=hotpath
Run allocation reports with:
cargo run --features='hotpath,hotpath-alloc'
Use HOTPATH_OUTPUT_FORMAT=json and HOTPATH_OUTPUT_PATH=report.json when a test, benchmark, CI job, or AI agent should parse the result.
Tokio Runtime Profiling
For Tokio services, add runtime sampling near the start of async main.
use tokio::{sync::mpsc, time::{sleep, Duration}};
#[hotpath::measure]
async fn handle_job(job: u64) {
sleep(Duration::from_millis(job % 10)).await;
}
#[tokio::main]
#[hotpath::main(report = "functions-timing,channels,tokio_runtime,threads")]
async fn main() {
hotpath::tokio_runtime!();
let (tx, mut rx) = hotpath::channel!(
mpsc::channel::<u64>(128),
label = "jobs",
log = true
);
let producer = tokio::spawn(async move {
for job in 0..1_000 {
tx.send(job).await.expect("jobs receiver alive");
}
});
let consumer = tokio::spawn(async move {
while let Some(job) = rx.recv().await {
hotpath::future!(
handle_job(job),
label = "job_future",
log = true
)
.await;
}
});
producer.await.expect("producer task");
consumer.await.expect("consumer task");
}
Run:
cargo run --features='hotpath-tokio'
For extra Tokio metrics, build with Tokio unstable cfg:
RUSTFLAGS="--cfg tokio_unstable" cargo run --features='hotpath-tokio'
- Put
#[tokio::main]above#[hotpath::main]. - Use
hotpath::tokio_runtime!(&handle)when profiling a runtime through an explicittokio::runtime::Handle. - Use
HOTPATH_TOKIO_RUNTIME_INTERVAL_MSto tune runtime sampling cadence. - Include
tokio_runtimeinHOTPATH_REPORTor#[hotpath::main(report = "...")]when generating static reports.
Async Data Flow
Use channel!, stream!, future!, and #[future_fn] when queue pressure, stream throughput, or future polling behavior is the suspected bottleneck.
use futures::{stream, StreamExt};
#[hotpath::future_fn(log = true)]
async fn fetch_page(page: u64) -> Vec<u8> {
tokio::time::sleep(std::time::Duration::from_millis(page % 5)).await;
vec![page as u8; 16]
}
#[tokio::main]
#[hotpath::main(report = "streams,futures")]
async fn main() {
let pages = hotpath::stream!(
stream::iter(1..=100),
label = "pages",
log = true
);
let total: usize = pages
.then(|page| hotpath::future!(fetch_page(page), label = "fetch_page"))
.map(|bytes| bytes.len())
.sum()
.await;
std::hint::black_box(total);
}
- Label high-value channels, streams, and futures so the TUI and MCP tools are easy to query.
- Use
log = trueonly when values implementDebugand logs are safe to expose. futuresbounded channels require an explicitcapacity = N; Tokio channels do not.- Remember that monitored channels add a proxy on the receive side and can subtly affect edge-case channel behavior such as
try_send.
AI via MCP
Use MCP for long-running services or load tests where an AI agent should query live profiling data while the app runs.
- Instrument functions, Tokio runtime, channels, streams, or futures.
- Run the app with MCP enabled:
HOTPATH_OUTPUT_FORMAT=none \
HOTPATH_MCP_PORT=6771 \
cargo run --features='hotpath,hotpath-alloc,hotpath-mcp,hotpath-tokio'
- Connect the AI agent over HTTP MCP:
claude mcp add --transport http hotpath http://localhost:6771/mcp
With auth:
HOTPATH_MCP_AUTH_TOKEN=secret123 \
cargo run --features='hotpath,hotpath-mcp'
claude mcp add --transport http hotpath http://localhost:6771/mcp \
--header "Authorization: secret123"
Equivalent MCP config:
{
"mcpServers": {
"hotpath": {
"type": "http",
"url": "http://localhost:6771/mcp",
"headers": {
"Authorization": "secret123"
}
}
}
}
Ask targeted questions that map to hotpath tools:
- "Which functions dominate total execution time right now?"
- "Where are allocations concentrated?"
- "Which channel has the highest queue pressure?"
- "Show the last 10 timing events for handle_job."
- "Are Tokio workers saturated or building up queue depth?"
- "Compare latency and allocation behavior for parse_batch and load_user."
Useful MCP summary tools include functions_timing, functions_alloc, channels, streams, futures, threads, tokio_runtime, gauges, dbg_entries, val_entries, and profiler_status.
Useful log tools include function_timing_logs, function_alloc_logs, channel_logs, stream_logs, future_logs, gauge_logs, dbg_logs, and val_logs.
Live TUI
Install the dashboard separately:
cargo install hotpath --features=tui --version '^0.16.1'
Run the console in one terminal:
hotpath console
Run the instrumented app in another terminal:
cargo run --features='hotpath,hotpath-alloc,hotpath-tokio'
- Use TUI for HTTP servers, queue workers, and other long-running processes.
- Use
HOTPATH_TUI_TAB=6to start on the Tokio tab. - Use
HOTPATH_METRICS_PORTandHOTPATH_METRICS_HOSTwhen the console needs non-default connection settings.
CPU Sampling
Use CPU sampling when wall-clock timing alone cannot distinguish CPU-bound work from I/O waits.
[profile.profiling]
inherits = "release"
debug = true
cargo install samply --locked
cargo install hotpath --bin hotpath-samply --version '^0.16.1'
cargo run --features='hotpath,hotpath-alloc,hotpath-cpu' --profile profiling
On Linux, CPU profiling may need temporary kernel profiling permissions and setsid -w:
setsid -w cargo run --features='hotpath,hotpath-alloc,hotpath-cpu' --profile profiling
- Ensure
samplyandhotpath-samplyare inPATH, or setHOTPATH_SAMPLY_BINandHOTPATH_SAMPLY_WRAPPER_BIN. - For methods in
implblocks, use#[hotpath::measure(impl_type = "TypeName")]or#[hotpath::measure_all]so CPU attribution matches demangled method names. hotpath-cpurewrites measured functions to#[inline(never)]for better attribution unlessHOTPATH_KEEP_INLINE=1is set before macro expansion.
Reporting and Configuration
Common environment variables:
HOTPATH_OUTPUT_FORMAT:table,json,json-pretty, ornone.HOTPATH_OUTPUT_PATH: write report to a file.HOTPATH_REPORT: comma-separated sections such asfunctions-timing,functions-alloc,channels,streams,futures,threads,tokio_runtime,debug, orall.HOTPATH_FOCUS: substring or/regex/filter for function names.HOTPATH_LIMIT,HOTPATH_FUNCTIONS_LIMIT,HOTPATH_CHANNELS_LIMIT,HOTPATH_STREAMS_LIMIT,HOTPATH_FUTURES_LIMIT,HOTPATH_THREADS_LIMIT: cap report rows.HOTPATH_MCP_PORTandHOTPATH_MCP_AUTH_TOKEN: configure MCP access.HOTPATH_SHUTDOWN_MS: force shutdown and report generation after a fixed profiling window.HOTPATH_LOGS_LIMITandHOTPATH_MAX_LOG_LEN: control retained debug/log payloads.
Guidance
- Start with the smallest instrumentation that can answer the question: a few functions and one queue before
measure_allacross a module. - Prefer static JSON reports for repeatable benchmarks and CI comparisons.
- Prefer live TUI or MCP for services whose bottlenecks depend on runtime load.
- Keep logged return values and channel payloads free of secrets or personal data.
- Disable or omit profiling features in production builds unless the deployment intentionally needs live profiling.
- Do not create more than one
HotpathGuardat a time;#[hotpath::main]and manualHotpathGuardBuilderare mutually exclusive for a profiling lifetime.
Helper Script
Generate starter snippets without loading extra context:
bash /mnt/skills/user/hotpath-rs/scripts/hotpath-rs-bootstrap.sh basic
bash /mnt/skills/user/hotpath-rs/scripts/hotpath-rs-bootstrap.sh tokio
bash /mnt/skills/user/hotpath-rs/scripts/hotpath-rs-bootstrap.sh data-flow
bash /mnt/skills/user/hotpath-rs/scripts/hotpath-rs-bootstrap.sh mcp
bash /mnt/skills/user/hotpath-rs/scripts/hotpath-rs-bootstrap.sh cpu
The script prints JSON with a scenario, cargo, command, and snippet field.