Stress Test CPUs on Linux machines

I came across a scenario where I needed to stress test some new servers CPU and didn’t want to install any program to do it so I wrote a script to stress test CPU’s.

Features:

  • Customizable duration: Set any positive integer duration with -t.
  • Customizable core count: Stress a specific number of cores with -c, up to the maximum available.
  • Quiet mode: Use -q for minimal output, ideal for scripting or automated runs.
  • Input validation: Checks for valid duration and core count, with clear error messages.
  • Verbose reporting: Logs start/end times, core count, PIDs, and a countdown timer (unless in quiet mode).
  • Reliable cleanup: Stores PIDs and uses kill -9 to ensure yes processes are terminated.
  • Cleanup verification: Checks for lingering yes processes and warns if any remain.

Options:

  • -t duration: Set duration in seconds (default: 30).
  • -c cores: Specify number of CPU cores to stress (default: all available cores, as detected by nproc).
  • -q: Quiet mode, suppresses detailed output (only shows warnings or errors).

How to use:

  1. Save as max_cpu.sh.
  2. Make executable: chmod +x max_cpu.sh.
  3. Run with options, e.g.:
    • ./max_cpu.sh (default: 30 seconds, all CPU cores, verbose output)
    • ./max_cpu.sh -t 60 (run for 60 seconds)
    • ./max_cpu.sh -t 45 -c 2 (run for 45 seconds, stress 2 cores)
    • ./max_cpu.sh -t 20 -q (run for 20 seconds, minimal output)

Example output (verbose mode, ./max_cpu.sh -t 5 -c 2):

Starting CPU stress test at Fri May 30 22:25:47 NZST 2025
Using 2 CPU core(s) for 5 seconds
Launching 'yes' processes to max out CPU...
Started 'yes' process with PID 12345
Started 'yes' process with PID 12346
Running CPU at 100% for 5 seconds...
Time remaining: 5 seconds
Time remaining: 4 seconds
Time remaining: 3 seconds
Time remaining: 2 seconds
Time remaining: 1 seconds
Stopping 'yes' processes...
Terminated process with PID 12345
Terminated process with PID 12346
All 'yes' processes terminated successfully
CPU stress test completed at Fri May 30 22:25:52 NZST 2025

Example output (quiet mode, ./max_cpu.sh -t 5 -q):

All 'yes' processes terminated successfully

Script:

#!/bin/bash

# Default values
DURATION=30
CORES=$(nproc)
VERBOSE=1  # 1 for verbose output, 0 for minimal

# Function to display usage
usage() {
    echo "Usage: $0 [-t duration] [-c cores] [-q]"
    echo "  -t duration: Duration in seconds (default: 30)"
    echo "  -c cores: Number of CPU cores to stress (default: all, $CORES)"
    echo "  -q: Quiet mode (minimal output)"
    exit 1
}

# Parse command-line options
while getopts "t:c:q" opt; do
    case $opt in
        t) DURATION=$OPTARG ;;
        c) CORES=$OPTARG ;;
        q) VERBOSE=0 ;;
        *) usage ;;
    esac
done

# Validate inputs
if ! [[ "$DURATION" =~ ^[0-9]+$ ]] || [ "$DURATION" -le 0 ]; then
    echo "Error: Duration must be a positive integer"
    usage
fi
if ! [[ "$CORES" =~ ^[0-9]+$ ]] || [ "$CORES" -le 0 ] || [ "$CORES" -gt "$(nproc)" ]; then
    echo "Error: Number of cores must be a positive integer up to $(nproc)"
    usage
fi

# Function to log messages (respects verbose mode)
log() {
    if [ "$VERBOSE" -eq 1 ]; then
        echo "$1"
    fi
}

log "Starting CPU stress test at $(date)"
log "Using $CORES CPU core(s) for $DURATION seconds"

# Array to store process IDs
pids=()

# Start 'yes' processes for specified number of cores
log "Launching 'yes' processes to max out CPU..."
for i in $(seq $CORES); do
    yes > /dev/null &
    pids+=($!)
    log "Started 'yes' process with PID ${pids[$i-1]}"
done

# Wait for specified duration, showing progress if verbose
if [ "$VERBOSE" -eq 1 ]; then
    log "Running CPU at 100% for $DURATION seconds..."
    for ((i=$DURATION; i>0; i--)); do
        echo "Time remaining: $i seconds"
        sleep 1
    done
else
    sleep $DURATION
fi

# Terminate all 'yes' processes
log "Stopping 'yes' processes..."
for pid in "${pids[@]}"; do
    kill -9 "$pid" 2>/dev/null
    log "Terminated process with PID $pid"
done

# Wait briefly to ensure cleanup
wait 2>/dev/null

# Verify no 'yes' processes remain
if ! pgrep -x "yes" > /dev/null; then
    log "All 'yes' processes terminated successfully"
else
    echo "Warning: Some 'yes' processes may still be running. Run 'sudo killall -9 yes' manually."
fi

log "CPU stress test completed at $(date)"