Skip to content

The rate ceiling

The question this page answers is the one worth asking before trusting any of it: how fast can it sample before it starts losing data?

On the reference device the answer is that it does not, up to the CLI’s own 100 Hz cap, with every source read on every tick. That is not an extrapolation from the 10 Hz figure. It is five runs.

Every figure is from the agent’s own cgroup and /metrics, with the full source set. Each row is one window with the ring already full:

Measured on RB5009UG+S+ · 4 × 1.4 GHz Cortex-A72 · RouterOS 7.24.2 · · 60 s windows at steady state (ring full), full source set, collector forwarding to a file, a Prometheus exposition and InfluxDB 3 at once

The measured runs
ratefloorsCPU of one coreµs/sampleRSSslipped ticksgaps / drops
10 Hz (default)default2.85 %2 85631.3 MiB00 / 0
50 Hzdefault10.13 %2 02651.9 MiB00 / 0
100 Hzdefault17.81 %1 78176.5 MiB5 (0.08 %)0 / 0
50 HzFLOOR_HZ=5022.47 %4 49460.6 MiB6 (0.20 %)0 / 0
100 HzFLOOR_HZ=10043.95 %4 39579.6 MiB14 (0.23 %)0 / 0

FLOOR_HZ means every source is read on every tick, with no per-source floor at all — the worst case the agent can be asked for.

Memory differs by row because the ring does. The 10 Hz row is the install default (300 s ring, --mem-limit-mb 40 --memory-max 64M); the 50 Hz rows used --buffer 120 --mem-limit-mb 64 --memory-max 96M and the 100 Hz rows --buffer 120 --mem-limit-mb 80 --memory-max 128M. Give the agent’s garbage collector room or the cost jumps for reasons that have nothing to do with the rate.

Two things in that table worth reading twice

Section titled “Two things in that table worth reading twice”

A sample costs 2 856 µs at 10 Hz against 1 781 µs at 100 Hz. That is not a paradox, it is the floors working: the expensive sources are amortised over more samples. /proc/slabinfo, one of the expensive sources (13.8 kB), is read every 2nd tick at 10 Hz and every 17th at 100 Hz, so an average sample costs less while the rate of slabinfo reads stays near its 6 Hz floor either way (5 Hz at 10 Hz, about 5.9 Hz at 100 Hz).

With FLOOR_HZ there is no amortisation to be had and the per-sample cost is flat — 4 494 µs at 50 Hz and 4 395 µs at 100 Hz — so CPU scales linearly with the rate: 22.47 %, then 43.95 %.

The sample is still produced and still delivered, carrying its real dt_ns, so any rate computed from it stays correct. It is a smear, not a hole, and mikroscope_tick_interval_seconds is where you see it. At 100 Hz with everything on every tick, 99.5 % of ticks still landed within 11 ms of a 10 ms period and the worst was 15 ms.

At the default floors a whole tick’s sources are read in under 2 ms for 97.5 % of samples at 100 Hz, comfortably inside a 10 ms period. FLOOR_HZ pushes 1.4 % of reads past 5 ms, and those are the ticks that slip. The CPU headroom is larger than the timing headroom, which is why the ceiling is a statement about I/O rather than about the A72.

Not CPU-percent resolution. The jiffie is 10 ms, so at 100 Hz a sample holds either 0 or 1 busy tick and the per-sample busy ratio has two possible values. Above roughly 20 Hz the tick counters stop being a percentage and become an occupancy indicator; the PMU is the resolution from there.

What a higher rate does buy is everything that is not jiffie-quantised — softnet packet counts, interrupt deltas, PMU counters, the kernel log’s own timestamps — and a tighter bound on how long a burst can hide between two samples.