Test 3 – Scaling from 1 to 16 CPU Workers
I next progressively increase the number of continuously runnable processes.
cd ~/m2-scheduler-tests
for n in 1 4 8 12 16; do
sudo -v
sudo perf sched record -a \
-o "workers-$n.data" \
-- sleep 70 \
> "workers-$n-perf-record.txt" 2>&1 &
workers_perf_pid=$!
sudo turbostat --quiet \
--interval 1 \
--num_iterations 70 \
--show 'CPU,Core,Busy%,Avg_MHz,Bzy_MHz,CPU%c1,CPU%c6,CoreTmp,PkgWatt' \
> "workers-$n-turbostat.txt" 2>&1 &
workers_turbo_pid=$!
sleep 2
stress-ng \
--cpu "$n" \
--cpu-method matrixprod \
--timeout 60s \
--metrics-brief \
2>&1 | tee "workers-$n-workload.txt"
wait "$workers_perf_pid"
wait "$workers_turbo_pid"
if [ "$n" != "16" ]; then
sleep 60
fi
done
for n in 1 4 8 12 16; do
sudo perf sched timehist \
-i "workers-$n.data" \
--no-call-graph \
-M -V \
> "workers-$n-sched.txt"
grep 'stress-ng-cpu' "workers-$n-sched.txt" \
> "workers-$n-stress-ng-sched.txt"
done
Scheduler Placement
The results show that Linux follows Panther Lake’s CPU capacity hierarchy correctly. The scheduler fills the P-cores first, followed by the E-cores, and reserves the LP E-cores until all 16 CPUs are required.
The figures below represent aggregate CPU time across all workers.
| Workers | P-core time | E-core time | LP E-core time | CPU migrations |
|---|---|---|---|---|
| 1 | 59.861 seconds (99.78%) | 0.132 seconds (0.22%) | 0 seconds | 2 (0 steady) |
| 4 | 239.492 seconds (99.79%) | 0.497 seconds (0.21%) | 0 seconds | 16 (0 steady) |
| 8 | 239.496 seconds (49.90%) | 240.209 seconds (50.05%) | 0.264 seconds (0.06%) | 46 (23 steady) |
| 12 | 239.895 seconds (33.32%) | 479.672 seconds (66.63%) | 0.327 seconds (0.05%) | 67 (25 steady) |
| 16 | 239.955 seconds (25.02%) | 479.255 seconds (49.97%) | 239.940 seconds (25.02%) | 42 (2 steady) |
For the steady-state figures, I exclude migrations during the first and final second of each workload.
The single worker initially ran on an E-core but moved to a P-core within approximately 133 milliseconds. The four-worker workload settled onto all four P-cores within approximately 160 milliseconds. Neither configuration recorded another migration during the steady portion of the test.
With eight workers, the scheduler used all four P-cores and four E-cores. With 12 workers, it used all four P-cores and all eight E-cores. LP E-core residency remained below 0.06% in both tests and consisted only of brief transitional placements.
Only the 16-worker test placed sustained work on the four LP E-cores. Its residency percentages closely match the processor’s physical distribution of four P-cores, eight E-cores and four LP E-cores.
The eight- and 12-worker tests produced more migrations after their initial placement. However, the scheduler preserved the appropriate overall division between the core classes. This represents occasional load balancing rather than continuous movement of the entire workload.
Performance, Frequency and Power
The frequency, power and temperature figures below are averages from the full-load turbostat intervals 4 to 61. The temperature column reports the highest recorded temperature during those intervals.
| Workers | Average busy frequency | Package power | Maximum temperature | Bogo ops/s | Scaling |
|---|---|---|---|---|---|
| 1 | 4,190 MHz | 9.16 W | 71°C | 2,445.00 | 1.00× |
| 4 | 4,155 MHz | 28.36 W | 84°C | 10,158.84 | 4.15× |
| 8 | 3,691 MHz | 40.79 W | 90°C | 20,624.54 | 8.44× |
| 12 | 3,482 MHz | 51.00 W | 90°C | 30,586.50 | 12.51× |
| 16 | 3,189 MHz | 53.81 W | 91°C | 38,128.52 | 15.59× |
The average busy frequency falls as more core types become active and the processor’s shared power and thermal budgets become more important. Breaking the figures down by core class makes this clearer.
| Workers | P-core busy frequency | E-core busy frequency | LP E-core busy frequency |
|---|---|---|---|
| 1 | 4,193 MHz | – | – |
| 4 | 4,157 MHz | – | – |
| 8 | 4,127 MHz | 3,255 MHz | – |
| 12 | 3,932 MHz | 3,258 MHz | – |
| 16 | 3,822 MHz | 3,040 MHz | 2,853 MHz |
Although stress-ng reported that the scaling governor was set to powersave, this clearly did not prevent the processor from boosting. The P-cores operated at approximately 4.2 GHz during the lighter workloads.
The 16-worker run shows a distinct power-management transition. It initially averaged approximately 3,348 MHz while consuming 59.1 W. After around 37 to 38 seconds, it settled at approximately 2,916 MHz and 44.7 W.
This behaviour strongly suggests that the short-term turbo power window expired and the processor subsequently operated close to a long-term package power limit of 45 W. It is not evidence of a scheduler problem. Confirming the precise limiting mechanism would require power-limit or throttling counters that were not included in this capture.
The stress-ng bogo-operation figures are internal work units rather than an absolute measure of performance. They are nevertheless useful for comparing these otherwise identical runs. Total throughput increased from 2,445 bogo operations per second with one worker to 38,128.52 with 16 workers, representing 15.59 times the single-worker result.
Overall, the scheduler behaves very well. It selects the highest-capacity cores first, almost entirely avoids the LP E-cores until they are needed, and maintains the intended distribution between the three core classes. Even with every CPU active and the package settling to its sustained power limit, the 16-worker workload achieved close to linear scaling.
Next page: Page 6 – Real-World Multithreaded Scheduling with FFmpeg
Pages in this article:
Page 1 – Introduction
Page 2 – Monitoring CPU Frequency and Activity
Page 3 – Sustained Single-Thread Scheduling
Page 4 – Bursty Single-Thread Scheduling
Page 5 – Scaling from 1 to 16 CPU Workers
Page 6 – Real-World Multithreaded Scheduling with FFmpeg
Page 7 – Foreground Work Against 12 Low-Priority Workers
Page 8 – Foreground Work with All 16 CPUs Busy
Page 9 – Conclusions
Complete list of articles in this series:
| MINISFORUM M2 Core Ultra 7 356H Mini PC | |
|---|---|
| Introduction | Introduction to the series and interrogation of the machine |
| NPU | Setting up and testing the NPU |
| Benchmarks | I run a series of benchmarks focusing on the CPU, GPU, Memory, and Disk performance |
| Power | Testing and comparing the power consumption |
| BIOS | In the world of computing, BIOS, which stands for Basic Input/Output System, plays a crucial role |
| Cores | A look at Intel’s hybrid architecture |
| Intel processors | P-Cores, E-Cores and LP E-Cores Compared Across 4 Intel Processors |
| NPU | NPU and Llama |
| Scheduling | Does Linux Schedule Panther Lake Correctly? |
| Next articles in the series will continue to focus on the machine's NPU | |

Please read our Comment Policy before commenting.