Profiling
- Rust course
- Expert
- Lesson 40/46
- 4 min
Profile with perf and flamegraph.
Profiling
The first rule of optimization: don't guess, measure. Sampling profilers (perf on Linux, Instruments on macOS, samply everywhere) stop the program at regular intervals and record the stack trace. These samples are turned into a flamegraph: the width is the share of time spent in a function:
$ cargo install flamegraph
$ cargo flamegraph --release -- girdi.txt
# Cargo.toml: symbol info in the profile
[profile.release]
debug = trueIn a flamegraph, the widest "plateaus" (wide boxes with no calls above them) are the first places to optimize.
Folded stacks
Flamegraph tools process samples in a "folded" form: each line is a call chain separated by semicolons. Counting how many samples the same leaf function appears in gives where the time goes:
main;hesapla;topla
main;hesapla;topla
main;yaz
// leaf count: topla 2, yaz 1 → 2/3 of the time in toplaThe inferno crate produces an SVG flamegraph from this format.
Practice Count the samples
In the samples ["main;hesapla;topla", "main;hesapla;topla", "main;yaz"], find the leaf functions with rsplit(';') and count them in a BTreeMap. Print each as name count on separate lines.
Starter code
use std::collections::BTreeMap;
fn main() {
// buraya yaz
}Sample solution
use std::collections::BTreeMap;
fn main() {
let yiginlar = ["main;hesapla;topla", "main;hesapla;topla", "main;yaz"];
let mut sayim: BTreeMap<&str, u32> = BTreeMap::new();
for o in yiginlar {
let yaprak = o.rsplit(';').next().unwrap();
*sayim.entry(yaprak).or_insert(0) += 1;
}
for (ad, n) in &sayim {
println!("{} {}", ad, n);
}
}Expected output
topla 2 yaz 1
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 Why must the profile be taken on a release build?
- Debug can't be profiled
- Convention
- It isn't needed
- Bottlenecks in a debug build are completely different; unoptimized abstractions give misleading results Correct answer
Explanation: debug = true adds symbols to the release build; optimization is kept and function names are visible.
2 Take the leaf
let yaprak = yigin.____(';').next().unwrap();
let yaprak = yigin.rsplit(';').next().unwrap();
Explanation: rsplit splits from the right; the first piece is the chain's last function.
3 Tool and role
| Term | Meaning |
|---|---|
perf / samply |
Sampling profiler |
cargo flamegraph |
Produces a flame graph |
debug = true |
Symbols in release |
criterion |
Micro benchmark |