A CPU-bound workload
This page answers what a single-threaded bottleneck looks like in the per-core data, and why the device total hides it. The workload was provoked on purpose.
Measured on RB5009UG+S+ · 4 × 1.4 GHz Cortex-A72 · RouterOS 7.24.2 · Linux 5.6.3 · · agent at 10 Hz in an ephemeral privileged container
How it was provoked
Section titled “How it was provoked”With no configuration change and no external dependency — a console loop that burns one core and ends on its own:
:local i 0; :while ($i < 4000000) do={ :set i ($i + 1) }It ran 58.8 s.
What the agent recorded
Section titled “What the agent recorded”In 5-second buckets. The agent ships raw tick deltas; the percentages below were computed from them afterwards.
t busy% per-core busy% ctxt/s temp MHz 0 22.3 31.8 7.4 40.4 9.6 9192 36.5 1400 1 30.9 11.7 11.4 89.7 10.6 11325 37.0 1400 2 29.9 14.3 9.4 19.6 76.0 9476 37.0 1400 3 29.1 7.4 9.4 17.6 81.6 10805 37.0 1400 4 29.3 3.1 9.4 4.9 99.8 9257 37.2 1400 8 28.4 2.2 7.0 4.6 99.8 11947 37.2 1400 11 33.0 11.8 11.2 9.0 99.7 12222 37.3 1400What to read
Section titled “What to read”- Total ~29 % is one core of four. A device total is a trap; always look at the per-core row. “29 % CPU” here means “one core is saturated and three are idle”, which for a single-threaded bottleneck is the whole story.
- The scheduler took ~20 s to settle. Buckets 0–3 show the work moving between cores (40 % → 90 % → 76 % → 82 %) before pinning on core 3 at 99.8 %. If you sample at 1 s or slower you see a vague plateau; at 10 Hz you see the migration. This is the resolution earning its cost.
- Temperature followed: 36.5 → 37.3 °C. One saturated core is worth ~0.8 °C
on this passively cooled board. Small, but it tracks, and it is read from
/sys/class/thermalwith no API call. - Frequency stayed flat at 1400 MHz. On this device that is a
configuration, not an observation: the owner has pinned the clock to maximum,
which
/reports assystem/ routerboard/ settings Warning: cpu not running at default frequency. On a device that scales, thefreq_khzfield is where you would see a busy tick that was earned slowly. The agent reads the frequency every tick and storesfreq_khzonly when it changes, plus a heartbeat once every 60 s, so on a pinned clock you get one row a minute, and on a scaling clock you get every step that lasts at least one tick.
Check the sampler before the CPU
Section titled “Check the sampler before the CPU”Before you conclude anything from a CPU number, confirm
mikroscope_slipped_total is 0. A slipped tick is one whose read finished
after the next tick was due, and the sampler’s own accounting is then the first
thing you should distrust.
The signature
Section titled “The signature”Provoked on purpose ·
- A device total near 100 % divided by the core count — here ~29 % on four cores — with one per-core column at 99.7–99.8 %.
- Before it settles, the load visibly hopping between cores for tens of seconds.
- A temperature rise of under a degree that tracks the load.