Ir al contenido

Techo de muestreo

El agente no perdió ninguna muestra en el RB5009 a ninguna cadencia hasta el tope de 100 Hz de la propia CLI, con todas las fuentes leídas en cada tick en el peor caso. Eso no es una extrapolación desde la cifra de 10 Hz: son seis ejecuciones.

Cada cifra sale del propio cgroup del agente, viaja en cada muestra y se lee de vuelta desde el almacén, con el conjunto completo de fuentes. Cada fila es una ventana con el anillo ya lleno:

Medido en RB5009UG+S+ · 4 × 1,4 GHz Cortex-A72 · RouterOS 7.24.2 ·  · ventanas de 300 s en régimen estacionario (con el anillo ya lleno), conjunto completo de fuentes, la configuración que se envía —anillo de 60 s, límite de memoria derivado de él y el tope de contenedor de serie de 64M— con el colector reenviando a InfluxDB 3

Las ejecuciones medidas
cadenciasuelosCPU de un núcleoµs/muestraRSSticks retrasadoshuecos / descartes
10 Hz (por defecto)por defecto2,69 %2 68513,2 MiB00 / 0
20 Hzpor defecto4,61 %2 30315,4 MiB00 / 0
50 Hzpor defecto9,63 %1 92623,3 MiB00 / 0
100 Hzpor defecto16,83 %1 68445,7 MiB5 (0,02 %)0 / 0
50 HzFLOOR_HZ=5022,56 %4 51125,1 MiB4 (0,03 %)0 / 0
100 HzFLOOR_HZ=10042,70 %4 27049,5 MiB178 (0,59 %)0 / 0

FLOOR_HZ significa que cada fuente se lee en cada tick, sin ningún suelo por fuente — el peor caso que se le puede pedir al agente.

Todas las filas corrieron la configuración que se envía y no pasaron ninguna opción de memoria: el anillo de 60 s es el valor por defecto y el límite se deriva de él —16 MiB a 10 y 20 Hz, 25 a 50, 48 a 100— bajo el tope de contenedor de serie de 64M. La campaña anterior no podía hacer eso: necesitaba --memory-max 96M a 50 Hz y 128M a 100, y su fila de 10 Hz guardaba un anillo de 300 s. Mismo equipo, mismas fuentes: entre un 38 y un 59 % menos de memoria por fila, y la CPU sin moverse: 2,85 % de un núcleo a 10 Hz el 2026-09-15 frente a 2,69 % el 2026-09-18.

La memoria sigue cambiando de fila en fila porque el anillo cambia: guarda 60 s de muestras sea cual sea el ritmo, así que diez veces el ritmo son diez veces el anillo.

Una muestra cuesta 2 685 µs a 10 Hz frente a 1 684 µs a 100 Hz. No es una paradoja, son los suelos funcionando: las fuentes caras se amortizan entre más muestras. /proc/slabinfo, una de las fuentes caras (13,8 kB), se lee cada 2 ticks a 10 Hz y cada 17 a 100 Hz, así que una muestra media cuesta menos mientras la frecuencia de lecturas de slabinfo se queda cerca de su suelo de 6 Hz en ambos casos (5 Hz a 10 Hz, unos 5,9 Hz a 100 Hz). Así que diez veces los datos cuestan unas 6,3 veces la CPU, no diez: 16,83 % a 100 Hz frente a 2,69 % a 10.

Con FLOOR_HZ no hay nada que amortizar y el coste por muestra es plano — son 4 511 µs a 50 Hz y 4 270 µs a 100 Hz — así que la CPU escala linealmente con la cadencia: 22,56 %, y luego 42,70 %.

La muestra se produce igual y se entrega igual, llevando su dt_ns real, así que cualquier tasa calculada a partir de ella sigue siendo correcta. Es un emborronamiento, no un agujero, y se ve en mikroscope_tick_interval_seconds. A 100 Hz con todo en cada tick, 29 777 de 29 994 intervalos —el 99,3 %— cayeron aun así dentro de 11 ms de un período de 10 ms; el percentil 99,5 fue 11,3 ms y el peor intervalo suelto, 21,7 ms.

Con los suelos por defecto, todas las fuentes de un tick se leen en menos de 2 ms en el 97,7 % de las muestras a 100 Hz, holgadamente dentro de un período de 10 ms. FLOOR_HZ empuja el 1,45 % de las lecturas más allá de 5 ms —y ni una sola de 29 996 bajó de 2 ms—, y esos son los ticks que se retrasan: el 0,593 % de ellos a 100 Hz con cada fuente en cada tick, frente al 0,017 % con los suelos por defecto. El margen de CPU es mayor que el margen de tiempo, que es por lo que el techo es una afirmación sobre E/S y no sobre el A72. Incluso con los suelos por defecto a 100 Hz la lectura media fue de 1,2 ms pero la peor de 17,9 ms, y un tick cuya lectura dura más que su período llega tarde por definición. De ahí, y no de un muro de CPU con un 16,83 % de un núcleo, vienen los pocos retrasos de esa ejecución.

La memoria es el anillo. Todas las demás cifras —el runtime de Go, el margen del recolector, la fragmentación del asignador— se derivan de cuántas entradas guarda, porque el límite blando de memoria se calcula justo de ahí. Así que la pregunta «¿puede esta placa muestrear a 100 Hz?» es sobre todo «¿puede guardar 100 × tus segundos de búfer en muestras?», y la respuesta para toda la tabla de arriba es que sí, dentro del tope de serie de 64M.

Compra el margen en segundos de búfer, no en ingenio. A 100 Hz un búfer de 20 s ocupa 6,59 MiB y deriva un límite de 17 MiB —el mismo alivio que daría comprimir el anillo 4,7×, y la compresión se midió en este equipo en +1 331 µs por muestra, que a 100 Hz son +74 % de CPU y seis veces los ticks retrasados—. Los segundos son gratis; la compresión no.

Resolución de porcentaje de CPU no. El jiffie son 10 ms, así que a 100 Hz una muestra contiene 0 o 1 ticks ocupados y la proporción de ocupación por muestra tiene dos valores posibles. Por encima de unos 20 Hz los contadores de ticks dejan de ser un porcentaje y pasan a ser un indicador de ocupación; a partir de ahí la resolución la pone la PMU.

Lo que sí compra una cadencia mayor es todo lo que no está cuantizado por el jiffie — cuentas de paquetes de softnet, deltas de interrupciones, contadores de la PMU, las marcas de tiempo del propio log del kernel — y una cota más estrecha sobre cuánto puede esconderse una ráfaga entre dos muestras.