---
title: Deep Dive into perf
url: https://doc.liz6.com/en/systems-programming/08-performance-and-debugging/01-deep-dive-into-perf
locale: en
area: systems-programming
tags:
- systems-programming
- performance-and-debugging
date: 2026-06-30
modified: 2026-07-16
description: 'Coverage: perf record/report/annotate → Flame Graph → perf stat → PEBS → perf probe → Performance Analysis Methodology Applicable to: Linux perf_events (kernel 2.6.31+)'
---

# Deep Dive into perf

> Coverage: perf record/report/annotate → Flame Graph → perf stat → PEBS → perf probe → Performance Analysis Methodology
> Applicable to: Linux perf_events (kernel 2.6.31+)

## perf stat: CPU Performance Counters

```bash
# Counting mode: Hardware events during the entire program execution
perf stat ls /

# Output:
#   task-clock:        # Actual CPU time
#   cycles:            # CPU cycles (can be affected by frequency scaling; use cycles:u to restrict to user space)
#   instructions:      # Number of executed instructions
#   IPC:               # instructions/cycles (>1 = good superscalar utilization)
#   branches:          # Branch instructions
#   branch-misses:     # Branch prediction misses
#   cache-misses:      # Cache misses
#   context-switches:  # Context switches
#   page-faults:       # Page faults

# Key Metrics:
#   IPC < 0.5: Severe stalling (cache miss, branch miss, data dependency)
#   IPC > 2:   High superscalar utilization
#   branch-miss rate > 5%: Branch prediction issues
#   cache-miss rate > 10%: Data locality issues

# Specify events:
perf stat -e cycles,instructions,cache-references,cache-misses,branch-misses ./prog
```

## perf record: Sampling

```bash
# Sampling (default cycles, sampling rate 4000 Hz):
perf record -g ./prog        # -g: Record call graph (callchain)
perf record -F 99 -g ./prog  # 99 Hz sampling (similar to standard flame graph)

# Reporting:
perf report                   # Interactive (functions/call chains)
perf report --sort=dso,sym    # Sort by .so + function
perf report -n --stdio        # Plain text + sample count

# Annotate (mixed source code + assembly + sampling):
perf annotate function_name

# Real-time top:
perf top -e cycles
```

## Flame Graph

```bash
# 1. Sampling:
perf record -F 99 -g -- ./prog

# 2. Generate Flame Graph (Brendan Gregg's tools):
perf script > out.perf
stackcollapse-perf.pl out.perf > out.folded
flamegraph.pl out.folded > flamegraph.svg

# Or in one line:
perf script | stackcollapse-perf.pl | flamegraph.pl > flame.svg
```

## perf probe: Dynamic Probing

```bash
# Add a probe point to any user-space function:
perf probe -x ./prog my_function
perf probe -x ./prog 'my_function arg1=%di arg2=%si'   # Capture arguments

# Add a probe point at any line:
perf probe -x ./prog my_file.c:42

# Record:
perf record -e probe_myprog:my_function -g -- ./prog

# View added probe points:
perf probe -l

# Delete:
perf probe -d my_function
```

## PEBS: Precise Sampling

```bash
# Default sampling: Reads instruction pointer after interrupt (may be imprecise, skid)
# PEBS (Precise Event-Based Sampling): Hardware records precise IP
perf record -e cycles:pp ./prog    # :pp = precise (2 levels)
perf record -e cycles:ppp ./prog   # :ppp = most precise (requires hardware support)
```

## System-Level Analysis

```bash
# System-wide sampling (requires root):
perf record -a -g -- sleep 10     # All CPUs, for 10 seconds

# Filter by process:
perf record -e cycles -p <pid> -- sleep 10
perf record -e cycles -t <tid>    # By thread

# Filter by CPU:
perf record -e cycles -C 0,2 -- sleep 10

# CPU utilization breakdown (topdown):
perf stat --topdown ./prog        # Intel 6th gen and later
# frontend bound / backend bound / bad speculation / retiring
```

## Performance Analysis Methodology

<svg viewBox="0 0 720 390" xmlns="http://www.w3.org/2000/svg" font-family="-apple-system,'Source Han Sans CN','Microsoft YaHei',sans-serif" role="img" aria-label="Performance Analysis Methodology Decision Tree: First suspect the bottleneck type, then use corresponding perf commands to locate it">
  <defs>
    <marker id="pfah" markerWidth="10" markerHeight="8" refX="8" refY="3" orient="auto"><path d="M0,0 L8,3 L0,6 Z" fill="#475569"/></marker>
  </defs>
  <rect width="720" height="390" fill="#ffffff"/>
  <text x="360" y="28" text-anchor="middle" font-size="17" font-weight="700" fill="#1f2933">Performance Analysis Methodology: Qualify the bottleneck first, then dig deeper layer by layer</text>

  <text x="95" y="48" text-anchor="middle" font-size="11" font-weight="600" fill="#64748b">Suspect What</text>
  <text x="315" y="48" text-anchor="middle" font-size="11" font-weight="600" fill="#64748b">First Qualify With</text>
  <text x="580" y="48" text-anchor="middle" font-size="11" font-weight="600" fill="#64748b">Then Deep Dive With</text>

  <!-- row 1: CPU bound -->
  <rect x="20" y="58" width="150" height="40" rx="8" fill="#4f46e5"/>
  <text x="95" y="83" text-anchor="middle" font-size="13" font-weight="700" fill="#ffffff">CPU bound?</text>
  <line x1="170" y1="78" x2="196" y2="78" stroke="#475569" stroke-width="1.6" marker-end="url(#pfah)"/>
  <rect x="200" y="58" width="230" height="40" rx="6" fill="#f0fdfa" stroke="#99f6e4"/>
  <text x="212" y="83" font-size="11" fill="#115e59">perf stat: IPC / instructions / cycles</text>
  <line x1="430" y1="78" x2="456" y2="78" stroke="#475569" stroke-width="1.6" marker-end="url(#pfah)"/>
  <rect x="460" y="58" width="240" height="40" rx="6" fill="#f0fdfa" stroke="#99f6e4"/>
  <text x="472" y="83" font-size="11" fill="#115e59">perf record: Find hot functions</text>

  <!-- row 2: memory bound -->
  <rect x="20" y="114" width="150" height="40" rx="8" fill="#4f46e5"/>
  <text x="95" y="139" text-anchor="middle" font-size="13" font-weight="700" fill="#ffffff">memory bound?</text>
  <line x1="170" y1="134" x2="196" y2="134" stroke="#475569" stroke-width="1.6" marker-end="url(#pfah)"/>
  <rect x="200" y="114" width="230" height="40" rx="6" fill="#f0fdfa" stroke="#99f6e4"/>
  <text x="212" y="134" font-size="11" fill="#115e59">perf stat: cache-misses,</text>
  <text x="212" y="147" font-size="11" fill="#115e59">LLC-loads / LLC-load-misses</text>
  <line x1="430" y1="134" x2="456" y2="134" stroke="#475569" stroke-width="1.6" marker-end="url(#pfah)"/>
  <rect x="460" y="114" width="240" height="40" rx="6" fill="#f0fdfa" stroke="#99f6e4"/>
  <text x="472" y="139" font-size="11" fill="#115e59">perf record -e cache-misses</text>

  <!-- row 3: IO bound -->
  <rect x="20" y="170" width="150" height="40" rx="8" fill="#4f46e5"/>
  <text x="95" y="195" text-anchor="middle" font-size="13" font-weight="700" fill="#ffffff">IO bound?</text>
  <line x1="170" y1="190" x2="196" y2="190" stroke="#475569" stroke-width="1.6" marker-end="url(#pfah)"/>
  <rect x="200" y="170" width="230" height="40" rx="6" fill="#f0fdfa" stroke="#99f6e4"/>
  <text x="212" y="195" font-size="11" fill="#115e59">iostat / blktrace</text>
  <line x1="430" y1="190" x2="456" y2="190" stroke="#475569" stroke-width="1.6" marker-end="url(#pfah)"/>
  <rect x="460" y="170" width="240" height="40" rx="6" fill="#f0fdfa" stroke="#99f6e4"/>
  <text x="472" y="195" font-size="11" fill="#115e59">perf trace (trace syscalls + latency)</text>

  <!-- row 4: lock contention -->
  <rect x="20" y="226" width="150" height="40" rx="8" fill="#4f46e5"/>
  <text x="95" y="251" text-anchor="middle" font-size="13" font-weight="700" fill="#ffffff">Lock contention?</text>
  <line x1="170" y1="246" x2="196" y2="246" stroke="#475569" stroke-width="1.6" marker-end="url(#pfah)"/>
  <rect x="200" y="226" width="230" height="40" rx="6" fill="#f0fdfa" stroke="#99f6e4"/>
  <text x="212" y="251" font-size="11" fill="#115e59">perf lock record + perf lock report</text>
  <line x1="430" y1="246" x2="456" y2="246" stroke="#475569" stroke-width="1.6" marker-end="url(#pfah)"/>
  <rect x="460" y="226" width="240" height="40" rx="6" fill="#f0fdfa" stroke="#99f6e4"/>
  <text x="472" y="251" font-size="11" fill="#115e59">perf stat -e context-switches</text>

  <!-- row 5: branch prediction -->
  <rect x="20" y="282" width="150" height="40" rx="8" fill="#4f46e5"/>
  <text x="95" y="307" text-anchor="middle" font-size="13" font-weight="700" fill="#ffffff">Branch prediction?</text>
  <line x1="170" y1="302" x2="196" y2="302" stroke="#475569" stroke-width="1.6" marker-end="url(#pfah)"/>
  <rect x="200" y="282" width="230" height="40" rx="6" fill="#f0fdfa" stroke="#99f6e4"/>
  <text x="212" y="307" font-size="11" fill="#115e59">perf stat -e branch-misses,branches</text>
  <line x1="430" y1="302" x2="456" y2="302" stroke="#475569" stroke-width="1.6" marker-end="url(#pfah)"/>
  <rect x="460" y="282" width="240" height="40" rx="6" fill="#f0fdfa" stroke="#99f6e4"/>
  <text x="472" y="307" font-size="11" fill="#115e59">perf record -e branch-misses</text>

  <!-- insight -->
  <rect x="20" y="336" width="680" height="36" rx="8" fill="#eef2ff" stroke="#c7d2fe"/>
  <text x="360" y="358" text-anchor="middle" font-size="12" fill="#3730a3">First use perf stat to qualify the bottleneck type, then use perf record / trace / lock to dig deeper layer by layer to specific functions or call sites.</text>
</svg>

## References

- **Documentation**: https://perf.wiki.kernel.org, Brendan Gregg's perf examples
- **Tools**: https://github.com/brendangregg/FlameGraph
- **Books**: "Systems Performance" (Brendan Gregg), "BPF Performance Tools"

*Keywords: perf, PEBS, IPC, cache-misses, flame graph, perf probe, topdown, branch prediction*
