wandres.dev
FTRACE Y TRACEPOINTS · seguir la ejecución

La interfaz: tracefs y trace-cmd

El sistema de archivos tracefs en /sys/kernel/tracing como panel de control de ftrace —sus archivos clave, el reloj de traza, y las instancias que aíslan buffers para que varias herramientas no choquen— y trace-cmd como frontend que captura a un trace.dat binario y lo reproduce sin pelear con echo.

⏱ 14 min

Toda la potencia de ftrace se maneja a través de un sistema de archivos especial: tracefs. No hay llamadas al sistema propias, no hay biblioteca; configurar el trazado es escribir texto en archivos y leer los resultados de otros. Es una interfaz brutalmente simple y por eso universal —funciona por SSH, en un script, en un contenedor sin más herramientas— pero también tediosa cuando el trabajo crece. Ahí entra trace-cmd: un frontend que habla ese mismo tracefs por debajo, pero te da comandos legibles, captura binaria eficiente a disco y una reproducción que ordena las trazas de todas las CPU en una sola línea temporal.

🎯 Al terminar esta lección sabrás
  • Montar y reconocer tracefs en /sys/kernel/tracing y su función como panel de control.
  • Identificar los archivos clave: tracer, buffer, reloj de traza y máscara de CPU.
  • Usar instancias para aislar buffers y que varias herramientas no se pisen.
  • Capturar y reproducir con trace-cmd record y trace-cmd report sobre un trace.dat.

tracefs: el panel de control

tracefs es un sistema de archivos independiente, montado por defecto en /sys/kernel/tracing. Históricamente colgaba de debugfs (/sys/kernel/debug/tracing), y aún hay un enlace de compatibilidad, pero el punto canónico hoy es el primero. Si no está montado:

sudo mount -t tracefs nodev /sys/kernel/tracing
ls /sys/kernel/tracing
# available_tracers  current_tracer  trace  trace_pipe  tracing_on
# set_ftrace_filter  events/  instances/  per_cpu/  options/  trace_clock ...

La filosofía es que cada control es un archivo. No hay estado oculto: cat current_tracer te dice qué trazador corre, cat tracing_on si está capturando, ls events/ qué puntos hay. Escribir configura; leer observa. Esta transparencia es la razón de que ftrace sea depurable incluso cuando todo lo demás falla.

Los archivos clave

Más allá de current_tracer, trace y tracing_on, hay un puñado de archivos que gobiernan cómo y dónde se captura.

cd /sys/kernel/tracing
cat buffer_size_kb            # tamaño del buffer por CPU, en KiB
echo 4096 > buffer_size_kb    # agrandarlo si se pierden eventos

cat trace_clock              # [local] global counter tsc mono ...
echo global > trace_clock    # reloj comun a todas las CPU para ordenar

echo 2 > tracing_cpumask     # mascara de bits: solo trazar la CPU 1

Tres decisiones importan aquí. El tamaño del buffer (buffer_size_kb) es por CPU y circular: si es pequeño, los eventos viejos se sobrescriben y pierdes historia. El reloj de traza (trace_clock) determina si las marcas de tiempo de distintas CPU son comparables: local es rápido pero no coordinado entre núcleos, global y mono son coherentes a costa de algo de sobrecarga, y esa elección decide si puedes fusionar las trazas de varias CPU en un orden fiable. La máscara de CPU (tracing_cpumask) restringe qué núcleos trazan. Bajo per_cpu/ hay además un buffer y un trace_pipe separados por cada CPU, que es como trace-cmd lee sin serializar.

Dos comodidades más viven aquí. El directorio options/ expone interruptores por tracer —func_stack_trace para apilar la pila en cada función, sym-offset para ver el desplazamiento dentro del símbolo— y el archivo trace_marker deja que el espacio de usuario inyecte una anotación en la misma línea temporal, para correlacionar lo que hace tu programa con lo que hace el kernel debajo.

echo 'inicio del experimento' > trace_marker   # aparece en el buffer, fechado

Instancias: buffers aislados

Un solo buffer global sería un cuello de botella social: si tú activas el function tracer y otra herramienta activa eventos de sched, os mezcláis y os pisáis la configuración. La solución son las instancias: subdirectorios bajo instances/ que son tracefs completos e independientes, con su propio current_tracer, sus propios eventos y su propio buffer.

mkdir /sys/kernel/tracing/instances/miapp
cd /sys/kernel/tracing/instances/miapp
echo 1 > events/block/block_rq_issue/enable   # solo en esta instancia
cat trace                                      # buffer propio, sin interferencias
# al terminar:
rmdir /sys/kernel/tracing/instances/miapp

Crear el directorio crea la instancia; borrarlo con rmdir la destruye y libera su buffer. Esto es lo que permite que perf, trace-cmd y un script propio tracen a la vez sin corromperse mutuamente: cada uno en su instancia.

trace-cmd: el frontend

Manejar tracefs a mano es perfecto para una comprobación rápida, pero para una captura seria —varias CPU, muchos eventos, a disco, para analizar luego— trace-cmd es la herramienta. Por debajo escribe los mismos archivos, pero orquesta la captura y guarda el resultado en un trace.dat binario que preserva los datos crudos.

# Capturar el arbol de llamadas de openat durante un comando concreto
trace-cmd record -p function_graph -g __x64_sys_openat -- cat /etc/hostname

# Capturar dos tracepoints mientras corre una carga
trace-cmd record -e sched:sched_switch -e sched:sched_wakeup -- ./mi_carga

# Reproducir lo capturado, ya ordenado por tiempo entre todas las CPU
trace-cmd report | head

# Listar que tracers y eventos ofrece el kernel
trace-cmd list -t         # tracers
trace-cmd list -e sched   # eventos del subsistema sched

La ventaja no es solo comodidad. trace-cmd record levanta una instancia, ajusta buffers, lee los buffers por CPU en paralelo y los fusiona; trace-cmd report decodifica el binario usando los archivos format que se guardaron dentro del trace.dat, de modo que puedes analizar la captura en otra máquina sin el kernel original. Para explorar visualmente, kernelshark abre ese mismo trace.dat en una interfaz gráfica donde ves las CPU como carriles y cada tarea como una banda de color.

Captura en vivo sin envolver un comando

trace-cmd record es ideal cuando puedes lanzar el proceso bajo trazado, pero muchas veces el sujeto es un servicio que ya lleva días corriendo. Para eso están start, stop y extract: arrancan la captura, la congelan y vuelcan el buffer a un trace.dat, sin envolver ningún comando.

trace-cmd start -e sched:sched_switch -e block:block_rq_issue  # empezar a capturar
# ... esperar a que el sintoma asome en produccion ...
trace-cmd stop                                                  # congelar los buffers
trace-cmd extract                                               # volcar a trace.dat
trace-cmd stat                                                  # que hay activo y si se pierden eventos
trace-cmd reset                                                 # dejar tracefs limpio

Ese ciclo es el patrón real de un diagnóstico en caliente: enciendes justo los eventos que sospechas, dejas correr el sistema hasta que el problema aparece y solo entonces congelas y extraes. Nada te obliga a saber de antemano cuándo ocurrirá.

✍️

tracefs a mano

Un echo y un cat, sin dependencias. Perfecto para una comprobación rápida, un script de arranque o una sesión SSH degradada. Tedioso para capturas grandes de muchas CPU.

🎛️

trace-cmd

Orquesta instancias y buffers, lee las CPU en paralelo, guarda un trace.dat portable con sus formatos dentro y lo reproduce ordenado en el tiempo. La opción para trabajo serio.

💡
record deja el sistema como estaba

Al terminar, trace-cmd reset devuelve tracefs a su estado inicial: apaga tracers, borra filtros y vacía buffers. Es el equivalente a limpiar tras de ti, y conviene lanzarlo si una captura interrumpida dejó eventos activos consumiendo CPU.

El archivo como llamada al sistema, y el porqué de su austeridad

Detente en la decisión de diseño que atraviesa todo este nivel: la interfaz de la máquina de trazado más sofisticada del kernel no es una llamada al sistema ni una biblioteca, sino un puñado de archivos de texto. Podría parecer primitivo, un rezago de otra época, y es justo lo contrario: es la aplicación más pura de la filosofía todo es un archivo a un problema donde de verdad importa. Piensa en las alternativas que se descartaron. Una ioctl dedicada habría atado las herramientas a una ABI binaria versionada, difícil de evolucionar y opaca a la introspección. Una biblioteca habría exigido enlazar código en cada consumidor. En cambio, tracefs hace que configurar el trazado sea una operación que cualquier cosa capaz de escribir un archivo puede realizar: un echo en un script de arranque, un cat por una sesión SSH degradada, una línea en un contenedor sin más binarios que la shell. La interfaz se vuelve el mínimo común denominador de todo lo que corre en Linux, y por eso mismo indestructible. Pero hay una lección más honda debajo. Que la configuración sea legible —que cat current_tracer te diga la verdad del estado sin intermediarios— convierte al sistema de trazado en algo autoexplicativo y depurable con sus propias reglas: el instrumento de observación es a su vez observable con ls y cat. Y las instancias llevan esa austeridad a su conclusión elegante: en vez de inventar un mecanismo de multiplexación, se reutiliza la abstracción de directorio, y cada mkdir es un espacio de trazado nuevo. trace-cmd no oculta esta interfaz: la envuelve. Cuando entiendes que por debajo solo hay archivos, dejas de necesitar memorizar comandos y empiezas a razonar sobre qué archivo tocar, que es el nivel donde el trazado deja de ser magia.

⚔️ Captura una vez a tracefs y otra con trace-cmd
  1. Confirma dónde está montado tu tracefs y comprueba si /sys/kernel/debug/tracing es un enlace al canónico.
  2. Cambia trace_clock a global, activa sched_switch en una instancia propia y explica por qué el reloj global importa al fusionar CPU.
  3. Repite la misma captura con trace-cmd record -e sched:sched_switch y compara la comodidad y la fidelidad del trace-cmd report frente al cat trace.
  4. Agranda buffer_size_kb, reproduce una carga intensa y razona cómo sabrías, mirando la salida, que estabas perdiendo eventos.
  5. Copia un trace.dat a otra máquina, ábrelo con trace-cmd report allí y argumenta por qué funciona sin el kernel original.