06 — Profilers and Tracers¶
By M9 you must be able to run a C program under a profiler and answer “where is the time going?” without guessing. Guessing is what junior engineers do; measurement is what senior engineers do. This file is the toolchain. Every tool listed is free.
The 2026 landscape¶
Tool |
Platform |
Type |
Overhead |
Primary use |
|---|---|---|---|---|
perf |
Linux |
Sampling profiler + counters |
Low (1-3%) |
CPU time, cache misses, branch mispredicts |
hotspot |
Linux |
GUI for perf |
Same as perf |
Visualize perf data as flame graphs, call trees |
Instruments |
macOS |
Sampling profiler (Xcode) |
Low |
The Mac equivalent of perf |
Tracy |
Cross-platform |
Instrumented profiler |
Low if you insert zones |
Frame-by-frame, low-latency loops (game/audio/HFT) |
bpftrace |
Linux |
Tracing (eBPF) |
Variable |
Dynamic tracing of syscalls, kernel events |
ftrace |
Linux |
Kernel tracer |
Low |
Kernel function tracing |
strace |
Linux |
syscall tracer |
High (2-100x) |
“What syscalls is this process making?” |
dtrace |
macOS + illumos |
Dynamic tracing |
Low |
Historical; on macOS partially disabled by SIP |
eu-perf-report / flamegraph.pl |
Linux |
Post-processing |
— |
Turn perf output into flame graphs |
perf on Linux — the workhorse¶
Install: sudo apt install linux-tools-common linux-tools-$(uname -r) on Ubuntu. Some cloud VMs require additional setup.
Basic recipes:
# Where is CPU time going?
perf record -F 99 -g -- ./prog
perf report
# CPU cycles, cache misses, branch misses at once
perf stat -e cycles,instructions,cache-misses,cache-references,branch-misses ./prog
# Live top-like view
perf top
# Kernel and user together (needs root usually)
sudo perf record -F 99 -a -g -- sleep 10
sudo perf report
Turn perf output into a flame graph (Brendan Gregg’s classic):
git clone https://github.com/brendangregg/FlameGraph
perf record -F 99 -g -- ./prog
perf script | FlameGraph/stackcollapse-perf.pl | FlameGraph/flamegraph.pl > out.svg
open out.svg
Set /proc/sys/kernel/perf_event_paranoid to 1 (or -1) to allow unprivileged perf. Some distros default to 4 and you’ll see “No permission” errors otherwise.
hotspot — GUI for perf¶
KDE’s hotspot is a Qt-based GUI that wraps perf record and shows flame graphs, top-down/bottom-up trees, and disassembly annotated with samples. On Ubuntu: sudo apt install hotspot.
Worth using once you have a real profiling problem. Not needed on Day 1.
Instruments on macOS¶
Xcode’s Instruments is genuinely excellent — possibly the best sampling profiler UI on any platform. Launch: xcrun xctrace or just run Instruments.app (part of Xcode; requires full Xcode, not just Command Line Tools).
Useful templates for C:
Time Profiler — sampling CPU profile.
System Trace — syscalls and scheduler.
Allocations — heap allocation tracking (redundant with ASan for correctness; useful for perf).
Counters — CPU perf counters (Apple Silicon has its own set; documented at https://developer.apple.com/documentation/apple-silicon).
Command-line equivalent: sample <pid> 10 — sample any running process for 10 seconds, print a call-tree summary.
Tracy Profiler — for low-latency C¶
Tracy is a nanosecond-resolution frame profiler. You add small macros to your code marking zones:
#include <tracy/TracyC.h>
void render_frame(void) {
TracyCZone(ctx, 1);
// ... work ...
TracyCZoneEnd(ctx);
}
A separate GUI client connects over TCP and shows a real-time timeline. Perfect for game engines, audio processing, HFT-style code, and “why is this loop 3x slower than expected” analysis.
Supports: C, C++, CUDA, Vulkan, D3D11/12, Metal. 10,500+ commits, actively maintained.
When to use: M11+ when you’re doing SIMD/perf-critical work. Overkill for general profiling.
bpftrace — dynamic tracing¶
bpftrace is eBPF-backed dynamic tracing with a DTrace-inspired language. Alive at https://github.com/bpftrace/bpftrace, FOSDEM 2025 talk. Linux 5.x+ only.
Example one-liners:
# Trace all open() syscalls from a process
sudo bpftrace -e 'tracepoint:syscalls:sys_enter_openat { printf("%s %s\n", comm, str(args->filename)); }'
# Histogram of read() sizes
sudo bpftrace -e 'tracepoint:syscalls:sys_enter_read { @sizes = hist(args->count); }'
When to reach for it: you have a running production system and want to attach a probe without stopping it. This is a M10+ skill.
Brendan Gregg’s book “BPF Performance Tools” is the canonical reference.
Latency numbers, memorized¶
Before any profiling, know the rough numbers. Peter Norvig’s original “Latency Numbers Every Programmer Should Know” (see 09_resources/05_papers_and_talks.md):
L1 cache reference 0.5 ns
Branch mispredict 5 ns
L2 cache reference 7 ns
Mutex lock/unlock 25 ns
Main memory reference 100 ns
Compress 1KB with zippy 3 μs
Send 1KB over 1 Gbps network 10 μs
Read 4KB randomly from SSD 150 μs
Read 1MB sequentially from RAM 250 μs
Round trip within data center 500 μs
Read 1MB sequentially from SSD 1 ms
Disk seek 10 ms
Read 1MB sequentially from disk 20 ms
CA → Netherlands → CA network 150 ms
Memorize the order of magnitude. When you’re guessing where time is going, these numbers tell you if your guess is even plausible.
What most people get wrong about profiling¶
They guess. They add printf timers. They optimize the wrong loop. Rule: never optimize C without a profiler. Ever. If you “think it’s slow because of X,” measure. Then measure again after your change. Amdahl’s law is not a suggestion.
Return to README.md · Next: 07_containers_and_vms.md