Rust
Profiling
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 = true
In 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 topla
The inferno crate produces an SVG flamegraph from this format.
Exercise 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.
Show example 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);
}
}
Test yourself
-
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
Show answer
Bottlenecks in a debug build are completely different; unoptimized abstractions give misleading results — debug = true adds symbols to the release build; optimization is kept and function names are visible.
-
Take the leaf
let yaprak = yigin.____(';').next().unwrap();
Show answer
let yaprak = yigin.rsplit(';').next().unwrap();
-
Tool and role
- perf / samply
- Sampling profiler
- cargo flamegraph
- Produces a flame graph
- debug = true
- Symbols in release
- criterion
- Micro benchmark
Next lesson: Unsafe guidelines