# Límites de resolución

El tick de 10 ms del kernel como suelo de toda lectura de CPU en un router MikroTik, los contadores de la PMU que leen por debajo de él y hasta dónde llega el anillo del agente.

Source: https://docs.jmrp.io/mikroscope/es/limits/

Cada número de CPU que produce mikroscope se cuenta en ticks del kernel, así que el cambio más
pequeño que puede mostrar lo pone el kernel, no el agente. Una fuente lee por debajo del tick, los
contadores de la propia CPU, y el anillo del agente fija hasta dónde llega cualquier lectura hacia
atrás.

## Resolución del tick

Un tick dura 10 ms. [`/proc/stat`](https://man7.org/linux/man-pages/man5/proc_stat.5.html) no cuenta tiempo, cuenta ticks de
`USER_HZ`, 100 por segundo. Una muestra de 100 ms puede contener por tanto 10 ticks por núcleo, así que la
fracción de ocupación de un núcleo se resuelve en escalones del 10 %,
y la media de cuatro núcleos en escalones del 2,5 %. Sobre 1 s, la resolución de un núcleo es del 1 %.

Eso es aritmética del tick, no una propiedad del agente, y ninguna cadencia ni ajuste lo cambia.
El agente envía los ticks en bruto y el intervalo real de cada muestra (`dt_ns`), nunca un
porcentaje, de modo que la ventana sobre la que divides la eliges tú.

La contabilidad de ticks también está cuantizada en los bordes: un intervalo de 100,3 ms puede
llevar 11 ticks, lo que daría una fracción de ocupación por encima de 1. La fracción de ocupación
derivada está limitada a 1; los ticks en sí siguen en bruto.

Muestrear más rápido no afina esto. A 100 Hz una muestra contiene 0 o 1 tick ocupado, así que la
fracción de ocupación por muestra tiene dos valores posibles; por encima de unos 20 Hz los
contadores de ticks son un indicador de ocupación más que un porcentaje. Lo que sí compra una
cadencia mayor está en [Techo de muestreo](https://docs.jmrp.io/mikroscope/es/cost/rate-ceiling/).

## Contadores de la PMU

Una fuente lee por debajo del tick: la unidad de monitorización del rendimiento de la CPU (PMU),
a través de [`perf_event_open`](https://man7.org/linux/man-pages/man2/perf_event_open.2.html), que el agente recoge como la fuente `perf` cuando el contenedor
es privilegiado. Es la única fuente de mikroscope que no viene de un fichero.

Una muestra en la que `/proc/stat` no marca ningún tick ocupado en ningún núcleo puede contener aun
así millones de ciclos e instrucciones ejecutadas ([medido](https://docs.jmrp.io/mikroscope/es/about/status/#reference-hardware)).
El tick redondea ese trabajo hasta hacerlo desaparecer; el contador no.

El número que merece la pena vigilar es el de instrucciones por ciclo (IPC), y el agente no lo
calcula: envía las cuentas en bruto y la división la haces tú. El IPC distingue un núcleo que
trabaja de un núcleo parado esperando a la memoria, algo que ningún contador de ticks puede
expresar. Compáralo núcleo a núcleo: el IPC en reposo de dos núcleos de una misma placa puede
diferir en más del doble ([medido](https://docs.jmrp.io/mikroscope/es/about/status/#reference-hardware)).

- El agente pide siete contadores: `cycles`, `instructions`, `cache-references`,
  `cache-misses`, `branch-instructions`, `branch-misses` y `bus-cycles`.
- Cuáles se abren depende de la CPU. Un contador que no se puede abrir está ausente, nunca a
  cero, así que lee la etiqueta `counter` de `mikroscope_perf_events_total{counter,cpu}` en vez
  de dar por hecho un conjunto ([CPU sin probar](https://docs.jmrp.io/mikroscope/es/about/status/#not-tested)).
- Los eventos genéricos `stalled-frontend` y `stalled-backend` no se piden. Devuelven `ENOENT`
  donde se probaron y harían falta códigos de evento en bruto, propios de cada CPU.
- Cada cuenta lleva `enabled_ns` y `running_ns`. En una CPU que multiplexa sus contadores, la
  cuenta en bruto cubre solo la parte del intervalo en que funcionó el contador, no el intervalo.
- Sin `privileged=yes` falta la familia entera: los contadores se abren a nivel de sistema, y
  eso un contenedor sin privilegios no puede hacerlo. Consulta
  [Modo privilegiado](https://docs.jmrp.io/mikroscope/es/limits/privileged/).

El colector usa esos mismos dos contadores para una de sus detecciones, `ipc-collapse`: por
núcleo, una vez que hay al menos 20 s de historia, que las instrucciones por ciclo de un segundo caigan por debajo de la mitad de su mediana de los 60 s
anteriores mientras la tasa de ciclos está por encima de su propia mediana. Se describe junto
con las demás reglas en [Reglas de detección](https://docs.jmrp.io/mikroscope/es/sinks/detections/).

## PSI, schedstat y trazado

No esperes un reloj más fino de [PSI](https://docs.kernel.org/accounting/psi.html), cuyos totales de espera van en microsegundos, ni
de [`schedstat`](https://docs.kernel.org/scheduler/sched-stats.html), cuyos tiempos de ejecución y espera van en nanosegundos. El kernel de
RouterOS medido hasta ahora no tiene ni `/proc/pressure` ni `/proc/schedstat` ([medido](https://docs.jmrp.io/mikroscope/es/about/status/#campaign-kernel-2026-09-11)).
El agente lee ambos donde el kernel los tiene ([aún no en un router](https://docs.jmrp.io/mikroscope/es/about/status/#not-tested)).

En un kernel cuya columna `irq` de `/proc/stat` se queda en 0, como en el medido, el tiempo de IRQ
hardware se cuenta dentro de `system`.

Tampoco hay un camino de trazado. El kernel medido no tiene ni eBPF, ni kprobes, ni ftrace, y el
router no tiene directorio de módulos del kernel, ni cabeceras, ni compilador con que añadirlos ([comprobado](https://docs.jmrp.io/mikroscope/es/about/status/#reference-hardware)).
Una función del kernel que falta no se puede añadir desde un contenedor.

El agente detecta al arrancar lo que tiene el kernel y lo publica en `/capabilities`: el mapa
`sources` dice qué fuentes lee realmente este despliegue. Los campos de una fuente ausente faltan
en cada muestra y en cada destino, nunca valen cero.

## Profundidad del anillo

El otro límite duro es la profundidad, no la resolución. El agente guarda sus muestras en un
anillo de `--buffer` segundos, 60 s por defecto y entre 10 y 3600 s permitidos, que contiene
cadencia × búfer muestras. Nada más antiguo existe en ningún sitio del router.

Esa profundidad es también toda la ventana de la sección `health` de `doctor`, que lee el anillo
una vez (el anillo entero cuando no guarda más de 10 000 muestras, y si no las 10 000 más
recientes, así que lo más corto entre `--buffer` y 10 000 / cadencia segundos) e imprime cuántos segundos cubrió. Un `doctor` limpio dice que no hubo bucle, churn de
STP, flap de enlace ni descartes de softnet en el último minuto con los valores por defecto, no
en todo el día; un fallo que ocurre una vez al día es cosa de los paneles y de las reglas de alerta.

Un corte del colector o del grabador más corto que el anillo se rellena al reconectar: pide
`since=<seq>` y recibe todas las muestras que se perdió. Un corte más largo que el anillo se
informa como un hueco de longitud conocida, nunca se tapa. El agente responde con una línea
`{"gap":{"from":…,"to":…}}` que nombra los números de secuencia perdidos, antes de las muestras
que aún conserva; `record` lo escribe como un marcador que dice `samples N..M lost`, y `forward`
lo cuenta en `mikroscope_collector_gaps_total` y se lo pasa a cada destino.

Un anillo más largo cuesta memoria en el agente, y el agente rechaza uno que no quepa. Al arrancar
cobra cada línea a 3 456 B: la clase de tamaño del asignador de la
que se sirve una línea con todas las fuentes activas (3 230 B), porque es
lo que paga el heap. Una placa con más núcleos o líneas de interrupción cuesta más por línea, y
una sin PMU, menos. El agente suma el presupuesto de la captura por disparo y sale con un error si
el total supera el `memory.max` del contenedor. Si el total es más de la mitad del límite blando
de memoria de Go, arranca pero registra un aviso, porque un heap tan justo mantiene al recolector
de basura trabajando sin parar. Cómo dimensionar ambos límites está en
[Coste del agente](https://docs.jmrp.io/mikroscope/es/cost/).

## Véase también

- [Cadencias de las fuentes](https://docs.jmrp.io/mikroscope/es/limits/source-floors/): las fuentes que no se
  leen en cada tick, y el motivo con nombre de cada una.
- [Modo privilegiado](https://docs.jmrp.io/mikroscope/es/limits/privileged/): la PMU, el log del kernel y las
  cachés slab, y lo que el contenedor sigue sin ver.
- [Techo de muestreo](https://docs.jmrp.io/mikroscope/es/cost/rate-ceiling/): lo que compra muestrear más rápido
  cuando el tick ya ha dejado de ser un porcentaje.
- [Límites de la evidencia](https://docs.jmrp.io/mikroscope/es/cost/limits/): lo que `/metrics` puede y no puede
  recuperar de estas muestras.
