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