How to Simulate Precise CPU Percentage Load per Core Using stress-ng for Monitoring System Testing


10 views

Recently while testing a monitoring system that triggers alerts at specific CPU thresholds (30-50%, 51-70%, >90%), I ran into an issue where stress-ng wasn't behaving as documented. Despite specifying -l 30 for 30% load, all cores were pegged at 100% utilization.

After digging through the source code and testing various scenarios, I discovered that stress-ng's CPU load parameter behaves differently depending on:

  • Whether you're using CPU-bound or I/O-bound stressors
  • The number of worker threads specified
  • The system's scheduler behavior

Here are working examples for precise per-core load simulation:

# Single core at 30% load
stress-ng --cpu 1 --cpu-load 30 --timeout 60s

# All cores at different loads (requires multiple instances)
stress-ng --cpu 4 --cpu-load 25 &
stress-ng --cpu 2 --cpu-load 50 &
stress-ng --cpu 1 --cpu-load 75 &

Key observations from testing across Debian/Ubuntu/CentOS:

# This DOES NOT WORK AS EXPECTED:
stress-ng -c 4 -l 30  # Will still peg all cores

# This works correctly:
stress-ng --cpu 4 --cpu-load 30 --cpu-method matrixprod

For more accurate results, combine taskset with stress-ng:

# Pin 30% load to core 0
taskset -c 0 stress-ng --cpu 1 --cpu-load 30 --cpu-method fft

# Verify with mpstat
mpstat -P ALL 1 5

The --cpu-method parameter significantly affects the accuracy of load simulation. Matrix multiplication (matrixprod) and FFT methods provide the most consistent results.

Here's a complete bash script for testing monitoring systems:

#!/bin/bash

# Test 30-50% range
echo "Testing 30-50% CPU range"
stress-ng --cpu $(nproc) --cpu-load 40 --timeout 120s &

# Test 51-70% range
sleep 30
echo "Testing 51-70% CPU range"
killall stress-ng
stress-ng --cpu $(nproc) --cpu-load 60 --timeout 90s &

# Test >90% range
sleep 30
echo "Testing >90% CPU range"
killall stress-ng
stress-ng --cpu $(nproc) --cpu-load 95 --timeout 60s

When testing monitoring systems that trigger alarms at specific CPU thresholds (30-50%, 51-70%, >90%), I needed precise CPU load generation. The stress-ng -c 1 -l 30 command should theoretically create 30% load on one core, but instead maxes out all CPUs.

The correct approach combines several flags:

stress-ng --cpu 1 --cpu-load 30 --timeout 60s --metrics-brief

Key parameters:

  • --cpu N: Number of worker processes (match to core count)
  • --cpu-load P: Target percentage (0-100)
  • --taskset 0x1: Pin to specific cores when needed

To confirm the actual CPU utilization:

# Method 1: Using mpstat
mpstat -P ALL 1 5

# Method 2: Using top in batch mode
top -b -n 3 -d 1 | grep "Cpu(s)"

Issue 1: Hyperthreading skewing results
Fix: Disable HT or use --taskset to pin workers

Issue 2: Other processes interfering
Fix: Run on isolated cores or use nice -n -20

For complex load patterns across multiple cores:

# Ramp load from 30% to 70% over 2 minutes
for load in {30..70..5}; do
  stress-ng --cpu 4 --cpu-load $load --timeout 15s
done

Combining with other stressors for realistic scenarios:

stress-ng --cpu 2 --cpu-load 60 --io 1 --vm 1 --vm-bytes 1G

When stress-ng isn't suitable:

  • cpulimit: For limiting existing processes
  • sysbench: For database-focused testing
  • lookbusy: Simpler but less precise