Further Reading & Resources
Chapter 8 — Further Reading & Resources
The tools covered in this course — top, iostat, ss, vmstat, strace, sysctl — are the everyday instruments every Linux administrator should reach for first. But performance work goes deeper. This chapter introduces the next layer: kernel-level profiling with perf, modern tracing with eBPF and bpftrace, the most valuable books and resources in the field, and a complete one-liner cheat sheet covering every topic from all eight chapters.
perf — Kernel-Level CPU Profiling
perf is the Linux kernel's built-in profiling tool. Unlike top or htop — which show what processes are running — perf shows what those processes are doing at the CPU instruction level. It can tell you which functions inside a program are consuming CPU, whether the bottleneck is in your code or in a library, and even whether cache misses or branch mispredictions are the root cause of high CPU usage.
apt install linux-perf linux-tools-common (Debian/Ubuntu) or dnf install perf (RHEL/Fedora). You may also need linux-tools-$(uname -r). Run as root or with CAP_SYS_ADMIN capability.
perf stat -e cache-misses,instructions ./myprogram
a to annotate a function with its assembly.
perf.data. Attach to a running process with -p PID, or profile a command directly. -g enables call graph recording (stack traces) — required for flamegraphs. perf record -g -p 8821 sleep 30 profiles PID 8821 for 30 seconds.
perf.data in an interactive TUI. Shows samples sorted by overhead %. Expand a function to see its callers and callees. Press a to annotate with source code (if debug symbols are available). perf report --stdio for plain text output.
Flame Graphs — visualising the whole call stack at once
A flame graph collapses thousands of perf samples into a single SVG. Each box is a function. Width represents time spent. The call stack grows upward — a wide box at the top means that function is directly consuming CPU. Narrow boxes below it are its callers.
eBPF and bpftrace — Modern Kernel Tracing
eBPF (extended Berkeley Packet Filter) allows small, safe programs to run inside the Linux kernel in response to events — system calls, function calls, network packets, scheduler events — without modifying kernel source code or loading a kernel module. The kernel verifies the program before running it, guaranteeing it can't crash the system. This makes eBPF the foundation of modern Linux observability.
bpftrace is a high-level scripting language for eBPF — it compiles one-liners and short scripts into eBPF programs and attaches them to kernel and user-space events. Think of it as awk for the kernel.
BCC — Ready-Made eBPF Tools
BCC (BPF Compiler Collection) ships with dozens of production-ready tracing tools. Install with apt install bpfcc-tools or dnf install bcc-tools. On Ubuntu the binaries are suffixed -bpfcc.
-p PID. Great for finding what config files an application actually reads.funclatency vfs_read shows how long filesystem reads take.uname -r.
Brendan Gregg's Resources
Brendan Gregg (Senior Principal Engineer at Intel, formerly Netflix) is the most influential figure in Linux performance analysis. He created the USE method, the flamegraph visualisation, and the Linux Performance Observability Tools diagram — the field's most-referenced one-page reference.
- Linux Performance Observability Tools diagram — a single diagram showing which tool covers which layer of the Linux stack (hardware → kernel → user space), organised by CPU/memory/file/network/system call. Available at brendangregg.com/linuxperf.html. Print this and keep it on your desk.
- The USE Method — Utilisation / Saturation / Errors. For every resource, check if it's over-utilised, if there's a queue forming (saturation), and if there are error counts. Covered in Chapter 1 of this course.
- FlameGraph repository — github.com/brendangregg/FlameGraph — the Perl scripts used to generate flamegraph SVGs from perf, DTrace, or bpftrace data.
- brendangregg.com — extensive blog posts on perf, eBPF, and performance analysis methodology. The posts are long, detailed, and worth reading in full.
Essential Books
Essential Man Pages
| Man Page | What it covers | Why it matters for performance work |
|---|---|---|
| man 5 proc | The /proc filesystem — every file under /proc/ documented | Explains what each field in /proc/meminfo, /proc/PID/status, /proc/stat, /proc/net/dev actually means. The authoritative source when a metric is ambiguous. |
| man sysctl.conf | Format and semantics of /etc/sysctl.conf and /etc/sysctl.d/ files | File format, ordering rules, how wildcards work, and which files override which. |
| man 5 limits.conf | PAM limits configuration — the format for /etc/security/limits.conf | All supported resource types (nofile, nproc, memlock, etc.) with valid value ranges. |
| man iostat | All iostat flags and column definitions | Precise definition of %util, await, aqu-sz, and the difference between -x and basic output. |
| man ss | Socket statistics — all filter expressions and output fields | The filter syntax for selecting sockets by state, address, or port. More powerful than the man page initially suggests. |
| man tc | Traffic control — queueing disciplines, classes, filters | Very large man page covering the full tc syntax for bandwidth shaping and throttling. |
| man perf | Linux perf tool — events, record options, report format | List of available hardware events (perf list) and all record/report flags. |
| man bpftrace | bpftrace language reference — probes, builtins, functions | Full language spec: all probe types (kprobe/uprobe/tracepoint/usdt), builtin variables (comm, pid, tid, nsecs), and map functions (count/hist/avg). |
| man 7 signal | Signal overview — all signal numbers, default actions, and semantics | Complete table of every signal, whether it can be caught/blocked, and what it does by default. Useful when you don't remember a signal number. |
| man free | free command output field definitions | Clarifies the "available" column vs "free" — a common source of confusion when reading memory output. |
Diagnostic One-Liner Cheat Sheet
The following one-liners cover the most common diagnostic tasks from all eight chapters. Keep this as a reference for the next time something is slow and you need to start somewhere.
| uptime | Load average (1/5/15 min). Divide by nproc — above 1.0 = saturation |
| top -b -n 1 | head -20 | One-shot CPU snapshot sorted by %CPU (no interactive mode) |
| mpstat -P ALL 1 3 | Per-core CPU breakdown — spot single-core saturation hidden by averages |
| ps aux --sort=-%cpu | head -10 | Top 10 processes by CPU consumption right now |
| pgrep -c -f "pattern" | Count processes matching a full command-line pattern |
| ps faux | grep -A10 "script.sh" | Show process tree rooted at a specific process |
| renice +10 -p PID | Throttle a CPU-hungry process without killing it (nice +10 = lower priority) |
| taskset -cp 0,1 PID | Pin a process to CPU cores 0 and 1 to isolate it from other workloads |
| ps -o pid,stat,comm -p PID | Check if a process is D (uninterruptible), Z (zombie), or S (sleeping) |
| free -h | Memory overview — read "available" not "free" for usable RAM |
| vmstat 1 5 | Memory + swap + I/O every second (5 samples) — si/so = swap in/out |
| grep -E "Mem|Swap|Dirty|Commit" /proc/meminfo | Key meminfo fields — committed memory, dirty pages, swap usage |
| ps aux --sort=-%mem | head -10 | Top 10 processes by RSS (actual RAM usage) |
| smem -r | head -10 | Top 10 by PSS (proportional memory — accounts for shared libraries correctly) |
| dmesg -T | grep -i "oom\|killed" | Check if the OOM killer has fired recently |
| watch -n 2 'grep -E "Dirty|Writeback" /proc/meminfo' | Monitor dirty page accumulation in real time |
| cat /proc/PID/oom_score | OOM kill priority for a specific process (0=immune, 1000=kill first) |
| sysctl vm.swappiness | Check current swap aggressiveness setting (default 60) |
| df -h | Disk space by filesystem — spot filesystems near 100% |
| df -i | Inode usage — "disk full" errors with free space = inode exhaustion |
| du -sh /* 2>/dev/null | sort -rh | head -15 | Find the largest top-level directories consuming space |
| iostat -x 1 5 | Disk I/O — watch %util, await, aqu-sz for saturation |
| iotop -o -b -n 3 | Which processes are doing I/O right now (requires root) |
| lsof | grep deleted | awk '$NF ~ /\(deleted\)/' | Files deleted but still held open (df vs du discrepancy) |
| find / -xdev -printf '%h\n' | sort | uniq -c | sort -rn | head -5 | Find directories with most files (inode exhaustion investigation) |
| journalctl --disk-usage | How much space systemd journal is consuming |
| truncate -s 0 /var/log/bigfile.log | Empty a log file without breaking open file handles |
| ss -tulpn | Listening TCP/UDP ports with process names (no DNS lookup) |
| ss -s | Socket summary — total counts by state (TIME_WAIT, ESTABLISHED, etc.) |
| ss -tan | awk '{print $1}' | sort | uniq -c | sort -rn | Count TCP connections by state |
| ping -c 5 host && mtr --report host | Latency baseline then per-hop breakdown — spot where packet loss occurs |
| dig host +stats | grep "Query time" | DNS resolution time — is DNS adding latency? |
| curl -w "@curl-format.txt" -o /dev/null -s URL | HTTP timing breakdown: DNS / TCP connect / TLS / TTFB / total |
| nethogs eth0 | Bandwidth by process — which process is saturating the NIC |
| cat /proc/net/dev | column -t | NIC error counters — RX errors, dropped, overrun, TX errors |
| ethtool eth0 | grep -E "Speed|Duplex|Link" | NIC link speed and duplex — spot half-duplex mismatches |
| ps faux | Full process list with parent→child tree (forest view) |
| pstree -p PID | Process tree rooted at a specific PID with all PIDs shown |
| ps -o pid,ppid,pgid,stat,comm -p PID | Process details including parent PID and process group |
| kill -0 PID | Check if a PID exists without sending a real signal |
| pkill -TERM -f "full-command-pattern" | SIGTERM by full command line — safer than name-only match |
| kill -- -PGID | SIGTERM to entire process group (parent + all descendants) |
| cat /proc/PID/wchan | What kernel function a D-state process is stuck in |
| strace -p PID -T 2>&1 | head -20 | What system calls a running process is making (with timing) |
| lsof -p PID | wc -l | Count open file descriptors for a process |
| systemctl edit service | Create a drop-in systemd override (e.g. add LimitNOFILE=65536) |
| sysctl -a | grep "param" | Find kernel parameters matching a pattern |
| sysctl -w vm.swappiness=10 | Change a kernel parameter at runtime (lost on reboot) |
| sysctl --system | Reload all sysctl config files (simulate what happens at boot) |
| cat /proc/sys/fs/file-nr | System-wide open FD count: used / unused / max |
| cat /proc/PID/limits | grep "open files" | Process's actual open file limit (soft and hard) |
| ulimit -Hn | Hard open-files limit for the current shell session |
| grep -r "nofile" /etc/security/limits.d/ /etc/security/limits.conf | Find persistent ulimit configuration |
| tuned-adm recommend | Ask tuned which profile suits this hardware |
| sar -u -s 08:00 -e 12:00 | Historical CPU usage between 08:00 and 12:00 today |
| sar -r -f /var/log/sysstat/sa13 | Historical memory data from the 13th of the month |
| perf top | Live CPU profiler — which kernel/user functions are consuming cycles |
| perf stat -a sleep 5 | System-wide hardware event counts for 5 seconds |
| perf record -g -p PID sleep 30 && perf report | Record 30s CPU profile with call graphs and browse results |
| bpftrace -e 'tracepoint:syscalls:sys_enter_openat { printf("%s %s\n", comm, str(args->filename)); }' | Trace every file open on the system in real time |
| execsnoop-bpfcc | Show every new process spawned (BCC tool — requires bpfcc-tools) |
| biolatency-bpfcc | Block I/O latency histogram — reveals disk response time distribution |
| tcpconnect-bpfcc | Every outgoing TCP connection — destination IP and port |
| runqlat-bpfcc | CPU run-queue latency — how long processes wait to get CPU time |
| memleak-bpfcc -p PID 30 | Track memory allocations for 30 seconds — confirm a memory leak |