Set up Linux performance monitoring with perf tools and flame graphs

Intermediate 45 min Apr 13, 2026 225 views
Ubuntu 24.04 Debian 12 AlmaLinux 9 Rocky Linux 9

Configure perf tools and FlameGraph toolkit to capture detailed CPU profiling data and generate interactive flame graphs for Linux performance analysis. Monitor application hotspots, CPU usage patterns, and identify performance bottlenecks in production environments.

Prerequisites

  • Root or sudo access
  • Active Linux system with kernel version 3.0+
  • At least 2GB free disk space for profiling data
  • Basic familiarity with command line

What this solves

Linux perf tools provide detailed CPU profiling and performance analysis capabilities for applications and system processes. This tutorial helps you set up comprehensive performance monitoring with flame graph visualization to identify CPU hotspots, analyze function call patterns, and optimize application performance in production environments.

Step-by-step installation

Update system packages

Start by updating your package manager to ensure you get the latest versions of perf tools and dependencies.

sudo apt update && sudo apt upgrade -y
sudo dnf update -y

Install perf tools and dependencies

Install the perf profiling tools, debug symbol packages, and essential build tools for flame graph generation.

sudo apt install -y linux-tools-common linux-tools-generic linux-tools-$(uname -r) \
                     libc6-dbg build-essential git perl
sudo dnf install -y perf kernel-debuginfo glibc-debuginfo \
                     make gcc git perl which

Configure kernel symbol access

Configure the system to allow perf access to kernel symbols and enable proper symbol resolution for detailed profiling.

echo 'kernel.perf_event_paranoid = 1' | sudo tee -a /etc/sysctl.conf
echo 'kernel.kptr_restrict = 0' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

Install debug information packages

Install debug symbols for better function name resolution in flame graphs and performance reports.

sudo apt install -y libc6-dbg
echo 'deb http://ddebs.ubuntu.com $(lsb_release -cs) main restricted universe multiverse' | \
sudo tee -a /etc/apt/sources.list.d/ddebs.list
echo 'deb http://ddebs.ubuntu.com $(lsb_release -cs)-updates main restricted universe multiverse' | \
sudo tee -a /etc/apt/sources.list.d/ddebs.list
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 428D7C01 C8CAB6595FDFF622
sudo apt update
sudo dnf install -y glibc-debuginfo kernel-debuginfo
sudo dnf debuginfo-install -y kernel glibc

Clone FlameGraph toolkit

Download the FlameGraph toolkit from GitHub for generating interactive SVG flame graphs from perf data.

cd /opt
sudo git clone https://github.com/brendangregg/FlameGraph.git
sudo chown -R $USER:$USER /opt/FlameGraph
echo 'export PATH="/opt/FlameGraph:$PATH"' >> ~/.bashrc
source ~/.bashrc

Configure perf data collection settings

Set up optimal perf configuration for comprehensive CPU profiling and stack trace collection.

# Add perf settings for all users
* soft nofile 65536
* hard nofile 65536
* soft nproc 32768
* hard nproc 32768
sudo mkdir -p /tmp/perf-data
sudo chmod 755 /tmp/perf-data

Test basic perf functionality

Verify that perf tools are working correctly by running a simple CPU profiling test.

perf stat -e cycles,instructions,cache-references,cache-misses sleep 3

Configure advanced profiling setup

Create perf data collection script

Create a reusable script for capturing detailed performance data with optimal settings for flame graph generation.

#!/bin/bash

Perf profiling script with flame graph generation

Usage: ./perf-profile.sh [duration] [process_name_or_pid]

DURATION=${1:-30} TARGET=${2:-""} OUTPUT_DIR="/tmp/perf-data/$(date +%Y%m%d_%H%M%S)" DATA_FILE="$OUTPUT_DIR/perf.data" FLAMEGRAPH_FILE="$OUTPUT_DIR/flamegraph.svg" mkdir -p "$OUTPUT_DIR" echo "Starting perf recording for $DURATION seconds..." echo "Output directory: $OUTPUT_DIR" if [ -n "$TARGET" ]; then # Profile specific process if [[ "$TARGET" =~ ^[0-9]+$ ]]; then # PID provided perf record -F 997 -g --call-graph=dwarf -p "$TARGET" \ -o "$DATA_FILE" sleep "$DURATION" else # Process name provided PID=$(pgrep -f "$TARGET" | head -1) if [ -z "$PID" ]; then echo "Error: Process '$TARGET' not found" exit 1 fi perf record -F 997 -g --call-graph=dwarf -p "$PID" \ -o "$DATA_FILE" sleep "$DURATION" fi else # System-wide profiling perf record -F 997 -g --call-graph=dwarf -a \ -o "$DATA_FILE" sleep "$DURATION" fi echo "Generating perf report..." perf report -i "$DATA_FILE" --stdio > "$OUTPUT_DIR/perf_report.txt" echo "Generating flame graph..." perf script -i "$DATA_FILE" | stackcollapse-perf.pl | flamegraph.pl > "$FLAMEGRAPH_FILE" echo "Profiling complete!" echo "Flame graph: $FLAMEGRAPH_FILE" echo "Perf report: $OUTPUT_DIR/perf_report.txt" echo "Raw data: $DATA_FILE"
sudo chmod +x /usr/local/bin/perf-profile.sh

Configure automatic symbol server setup

Set up automatic symbol download and caching for better flame graph accuracy.

[buildid-dir]
dir = /home/$USER/.debug

[annotate]
hide_src_code = false
use_offset = true

[report]
group = true
sort_order = comm,dso,symbol
demangle = true

[record]
call-graph = dwarf

[top]
sort_order = dso,symbol

Create monitoring service configuration

Set up a systemd service for continuous background performance monitoring when needed.

[Unit]
Description=Continuous Performance Monitoring
After=multi-user.target

[Service]
Type=simple
User=root
ExecStart=/bin/bash -c 'while true; do perf record -F 99 -g --call-graph=dwarf -a -o /tmp/perf-data/continuous_$(date +%%s).data sleep 300; done'
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
Warning: The continuous monitoring service generates large data files. Only enable for specific troubleshooting periods and ensure adequate disk space.

Generate your first flame graph

Capture sample performance data

Run a performance capture session to generate sample data for flame graph creation.

# System-wide profiling for 30 seconds
sudo perf record -F 997 -g --call-graph=dwarf -a sleep 30

Generate interactive flame graph

Convert the perf data into an interactive SVG flame graph for analysis.

perf script | stackcollapse-perf.pl | flamegraph.pl > /tmp/flamegraph_$(date +%Y%m%d_%H%M%S).svg

echo "Flame graph generated: /tmp/flamegraph_$(date +%Y%m%d_%H%M%S).svg"
echo "Open this file in a web browser to view the interactive flame graph"

Profile specific application

Example of profiling a specific running application using the custom script.

# Profile nginx process for 60 seconds
sudo /usr/local/bin/perf-profile.sh 60 nginx

Profile specific PID

sudo /usr/local/bin/perf-profile.sh 30 1234

System-wide profiling

sudo /usr/local/bin/perf-profile.sh 45

Advanced flame graph analysis

Configure differential flame graphs

Set up scripts for comparing performance between different time periods or configurations.

#!/bin/bash

Generate differential flame graphs

Usage: ./perf-diff.sh [baseline_perf_data] [current_perf_data]

BASELINE=$1 CURRENT=$2 if [ ! -f "$BASELINE" ] || [ ! -f "$CURRENT" ]; then echo "Usage: $0 baseline.data current.data" exit 1 fi OUTPUT_DIR="/tmp/perf-diff-$(date +%Y%m%d_%H%M%S)" mkdir -p "$OUTPUT_DIR" echo "Generating differential analysis..."

Generate folded stacks for both datasets

perf script -i "$BASELINE" | stackcollapse-perf.pl > "$OUTPUT_DIR/baseline.folded" perf script -i "$CURRENT" | stackcollapse-perf.pl > "$OUTPUT_DIR/current.folded"

Create differential flame graph

difffolded.pl "$OUTPUT_DIR/baseline.folded" "$OUTPUT_DIR/current.folded" | \ flamegraph.pl > "$OUTPUT_DIR/diff_flamegraph.svg" echo "Differential flame graph: $OUTPUT_DIR/diff_flamegraph.svg"
sudo chmod +x /usr/local/bin/perf-diff.sh

Configure memory profiling integration

Add memory allocation tracking to complement CPU profiling for comprehensive performance analysis.

# Install additional tools for memory profiling
sudo apt install -y valgrind massif-visualizer || sudo dnf install -y valgrind

Create memory+CPU profiling script

sudo tee /usr/local/bin/perf-memory.sh > /dev/null << 'EOF' #!/bin/bash DURATION=${1:-30} TARGET=${2:-""} OUTPUT_DIR="/tmp/perf-memory-$(date +%Y%m%d_%H%M%S)" mkdir -p "$OUTPUT_DIR" if [ -n "$TARGET" ]; then PID=$(pgrep -f "$TARGET" | head -1) if [ -z "$PID" ]; then echo "Process not found: $TARGET" exit 1 fi # CPU profiling perf record -F 997 -g --call-graph=dwarf -p "$PID" \ -o "$OUTPUT_DIR/cpu.data" sleep "$DURATION" & # Memory events perf record -e cache-misses,page-faults -p "$PID" \ -o "$OUTPUT_DIR/memory.data" sleep "$DURATION" & wait else echo "System-wide memory+CPU profiling" perf record -F 997 -g -e cycles,cache-misses,page-faults -a \ -o "$OUTPUT_DIR/combined.data" sleep "$DURATION" fi echo "Memory and CPU profiling complete: $OUTPUT_DIR" EOF sudo chmod +x /usr/local/bin/perf-memory.sh

Verify your setup

# Verify perf installation
perf --version
perf list | grep -E "cpu|cache|memory" | head -10

Check FlameGraph tools

ls -la /opt/FlameGraph/*.pl | head -5

Verify kernel settings

sysctl kernel.perf_event_paranoid sysctl kernel.kptr_restrict

Test basic profiling

sudo perf stat -e cycles,instructions ls /tmp

Verify scripts are executable

ls -la /usr/local/bin/perf-*

Common issues

Symptom Cause Fix
"perf: No such file or directory" Wrong kernel tools package Install linux-tools-$(uname -r) matching your kernel
"Permission denied" when running perf Restrictive paranoia settings Set kernel.perf_event_paranoid = 1 in sysctl
Flame graphs show only hex addresses Missing debug symbols Install debug packages and configure symbol paths
"Failed to open [kernel.kallsyms]" Kernel symbol access restricted Set kernel.kptr_restrict = 0 temporarily for profiling
Empty or minimal flame graphs Low sampling frequency or short duration Increase frequency with -F 997 and capture for longer periods
"stackcollapse-perf.pl: command not found" FlameGraph tools not in PATH Verify PATH includes /opt/FlameGraph or use full paths

Next steps

Automated install script

Run this to automate the entire setup

Need help?

Don't want to manage this yourself?

We handle infrastructure performance optimization for businesses that depend on uptime. From initial setup to ongoing operations.