Skip to content

Profiling


Calculon is performance-critical, so optimization is profile-first: measure, change, measure again. Two tools, depending on what you're looking at.

samply (preferred)

A sampling profiler with a real flamegraph and per-thread timeline in the Firefox Profiler UI. Use it for anything multi-threaded (e.g. the parallel matrix) - it shows worker idle/imbalance and inverted call trees that flat text cannot.

cargo install samply          # once

# Record a release binary or example end-to-end, then open the UI:
cargo build -p calculon-matrix --example matrix_profile --release
samply record ./target/release/examples/matrix_profile 100 30

# Headless / CI: save now, inspect later.
samply record --save-only -o /tmp/prof.json ./target/release/examples/matrix_profile 100 15
samply load /tmp/prof.json    # serve the saved profile in the UI

What to read in the UI:

  • Inverted (bottom-up) call tree - heaviest leaf functions first.
  • Per-thread timeline - rayon workers parked in wait_until_cold means idle: a serial bottleneck is starving them (Amdahl), not the parallel region.
  • Stack chart - where wall time actually goes per phase.

Tip

Expect ~2× wall-clock under the sampler. Compare ratios between runs, not absolute times. Build with debug symbols in release (on by default via the workspace profile) for readable frames.

macOS sample (quick & dirty)

No install needed; good for a single-threaded hotspot glance on a running server. Flat text only.

cargo build -p calculon --release
./target/release/calculon --tile-dir ./test_data/france_tiles &

# warm up
curl -s -o /dev/null -X POST http://localhost:8002/route -H 'Content-Type: application/json' \
  -d '{"locations":[{"lat":43.606,"lon":3.857},{"lat":43.612,"lon":3.865}],"costing":"auto"}'

# sample under load
sample $(pgrep -f target/release/calculon) 5 -f /tmp/profile.txt &
for i in $(seq 1 50); do curl -s -o /dev/null -X POST http://localhost:8002/route \
  -H 'Content-Type: application/json' \
  -d '{"locations":[{"lat":43.606,"lon":3.857},{"lat":43.612,"lon":3.865}],"costing":"auto"}'; done

cat /tmp/profile.txt | rustfilt | grep -E '^\s+[0-9]+ ' | sort -rn | head -40   # needs cargo install rustfilt

Common hotspots to expect:

Symbol Meaning
find_candidates_multi_tile, project_onto_edge edge snapping - dominates short routes / matrix setup
expand_forward, expand_reverse A* expansion - dominates long routes
get_tile, TL_CACHE tile cache - should be <5% with the thread-local cache
sin / cos / asin Haversine where DistanceApproximator would do

Benchmarks

Criterion benches give stable before/after numbers (statistical, not a single run):

cargo bench -p calculon-route  --bench routing   # needs france_tiles
cargo bench -p calculon-matrix --bench matrix     # includes 50×50 / 100×100 grids
cargo bench -p calculon-tiles  --bench tiles
cargo bench -p calculon-costing --bench costing

Always run benches before and after a performance change to get a proper comparison with significance, and confirm the hotspot moved with a profiler.