Ir al contenido

Comandos de bpftrace

bpftrace es un lenguaje de rastreo de alto nivel para eBPF en Linux. Proporciona una sintaxis concisa para escribir scripts de rastreo utilizando sondas del kernel y del espacio de usuario, haciendo accesible la instrumentación dinámica para el análisis de rendimiento y la depuración.

Instalación

Linux/Ubuntu

# Ubuntu 22.04+
sudo apt install bpftrace

# Fedora
sudo dnf install bpftrace

# Build from source
git clone https://github.com/bpftrace/bpftrace.git
cd bpftrace && mkdir build && cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
make -j$(nproc) && sudo make install

Verificar la instalación

# Comprobar versión y sondas soportadas
bpftrace --version
bpftrace -l 'tracepoint:syscalls:*' | head -20

Tipos de sondas

Tipo de sondaSintaxisDescripción
kprobekprobe:func_nameEntrada de función del kernel
kretprobekretprobe:func_nameRetorno de función del kernel
uprobeuprobe:/path:funcEntrada de función del espacio de usuario
uretprobeuretprobe:/path:funcRetorno de función del espacio de usuario
tracepointtracepoint:category:nameTracepoint estático del kernel
usdtusdt:/path:probeSonda estática del espacio de usuario
profileprofile:hz:99Muestreo temporal
intervalinterval:s:1Salida periódica
softwaresoftware:faults:100Eventos de software
hardwarehardware:cache-misses:1000000Eventos PMC de hardware
BEGINBEGINInicio del script
ENDENDFinalización del script

Variables incorporadas

VariableDescripción
pidID del proceso
tidID del hilo
uidID del usuario
gidID del grupo
commNombre del proceso
nsecsMarca de tiempo en nanosegundos
elapsedNanosegundos desde el inicio de bpftrace
cpuID de CPU actual
curtaskPuntero task_struct actual
retvalValor de retorno (kretprobe/uretprobe)
arg0-argNArgumentos de la sonda
argsEstructura de argumentos del tracepoint
cgroupID de cgroup del proceso actual
kstackTraza de pila del kernel
ustackTraza de pila del espacio de usuario

Comandos esenciales de una línea

# Rastrear nuevos procesos con argumentos
sudo bpftrace -e 'tracepoint:syscalls:sys_enter_execve { printf("%s %s\n", comm, str(args.filename)); }'

# Contar llamadas al sistema por nombre de proceso
sudo bpftrace -e 'tracepoint:raw_syscalls:sys_enter { @[comm] = count(); }'

# Distribución de tamaños de read()
sudo bpftrace -e 'tracepoint:syscalls:sys_enter_read { @bytes = hist(args.count); }'

# Rastrear aperturas de archivos por proceso
sudo bpftrace -e 'tracepoint:syscalls:sys_enter_openat { printf("%s %s\n", comm, str(args.filename)); }'

# Medir latencia de lectura VFS
sudo bpftrace -e 'kprobe:vfs_read { @start[tid] = nsecs; } kretprobe:vfs_read /@start[tid]/ { @us = hist((nsecs - @start[tid]) / 1000); delete(@start[tid]); }'

# Contar llamadas a funciones del kernel
sudo bpftrace -e 'kprobe:tcp_sendmsg { @[comm] = count(); }'

# Perfilar pilas del kernel a 99 Hz
sudo bpftrace -e 'profile:hz:99 { @[kstack] = count(); }'

# Rastreo de conexiones TCP
sudo bpftrace -e 'kprobe:tcp_v4_connect { printf("%s PID:%d -> connecting\n", comm, pid); }'

# Histograma de latencia de E/S de bloques
sudo bpftrace -e 'tracepoint:block:block_rq_issue { @start[args.dev, args.sector] = nsecs; } tracepoint:block:block_rq_complete /@start[args.dev, args.sector]/ { @usecs = hist((nsecs - @start[args.dev, args.sector]) / 1000); delete(@start[args.dev, args.sector]); }'

Mapas y agregaciones

# Mapa de conteo
sudo bpftrace -e 'kprobe:vfs_read { @reads[comm] = count(); }'

# Mapa de suma
sudo bpftrace -e 'tracepoint:syscalls:sys_exit_read /args.ret > 0/ { @bytes[comm] = sum(args.ret); }'

# Promedio
sudo bpftrace -e 'tracepoint:syscalls:sys_exit_read /args.ret > 0/ { @avg_bytes[comm] = avg(args.ret); }'

# Mínimo/Máximo
sudo bpftrace -e 'tracepoint:syscalls:sys_exit_read /args.ret > 0/ { @max_read[comm] = max(args.ret); }'

# Histograma lineal (0-100 en pasos de 10)
sudo bpftrace -e 'tracepoint:syscalls:sys_exit_read /args.ret > 0/ { @size = lhist(args.ret, 0, 10000, 1000); }'

# Histograma log2
sudo bpftrace -e 'tracepoint:syscalls:sys_exit_read /args.ret > 0/ { @size = hist(args.ret); }'

# Estadísticas (conteo, promedio, total)
sudo bpftrace -e 'tracepoint:syscalls:sys_exit_read /args.ret > 0/ { @bytes[comm] = stats(args.ret); }'

Filtros y formato

# Filtrar por PID
sudo bpftrace -e 'tracepoint:syscalls:sys_enter_write /pid == 1234/ { @bytes = hist(args.count); }'

# Filtrar por nombre de proceso
sudo bpftrace -e 'kprobe:vfs_read /comm == "nginx"/ { @[kstack] = count(); }'

# Operador ternario
sudo bpftrace -e 'tracepoint:syscalls:sys_exit_read { @result[args.ret >= 0 ? "success" : "error"] = count(); }'

# Formato de marca de tiempo
sudo bpftrace -e 'kprobe:do_nanosleep { printf("%s PID:%d sleeping\n", strftime("%H:%M:%S", nsecs), pid); }'

# Comparación de cadenas con comodines
sudo bpftrace -e 'tracepoint:syscalls:sys_enter_openat /str(args.filename) == "/etc/passwd"/ { printf("%s opened /etc/passwd\n", comm); }'

Scripts (multilínea)

# Guardar como latency.bt y ejecutar con: sudo bpftrace latency.bt
# Medir latencia de lectura por proceso
sudo bpftrace -e '
kprobe:vfs_read {
    @start[tid] = nsecs;
}

kretprobe:vfs_read /@start[tid]/ {
    $duration_us = (nsecs - @start[tid]) / 1000;
    @latency_us[comm] = hist($duration_us);
    if ($duration_us > 10000) {
        printf("SLOW READ: %s pid=%d %d us\n", comm, pid, $duration_us);
    }
    delete(@start[tid]);
}

interval:s:5 {
    print(@latency_us);
    clear(@latency_us);
}

END {
    clear(@start);
}
'

Listar y explorar sondas

# Listar todos los tracepoints
sudo bpftrace -l 'tracepoint:*'

# Listar sondas que coincidan con un patrón
sudo bpftrace -l 'kprobe:tcp_*'

# Listar argumentos del tracepoint
sudo bpftrace -lv 'tracepoint:syscalls:sys_enter_openat'

# Listar sondas USDT en un binario
sudo bpftrace -l 'usdt:/usr/sbin/mysqld:*'

# Contar tipos de sondas disponibles
sudo bpftrace -l | awk -F: '{print $1}' | sort | uniq -c | sort -rn

Rastreo del espacio de usuario

# Rastrear llamadas a malloc en un proceso en ejecución
sudo bpftrace -e 'uprobe:/lib/x86_64-linux-gnu/libc.so.6:malloc { @size = hist(arg0); }' -p 1234

# Rastrear entrada/retorno de función en un binario
sudo bpftrace -e 'uprobe:/usr/local/bin/myapp:process_request { @start[tid] = nsecs; } uretprobe:/usr/local/bin/myapp:process_request /@start[tid]/ { @latency = hist((nsecs - @start[tid]) / 1000); delete(@start[tid]); }'

# Rastrear llamadas a funciones Python mediante USDT
sudo bpftrace -e 'usdt:/usr/bin/python3:function__entry { printf("%s:%s\n", str(arg0), str(arg1)); }'

Patrones útiles

# Procesos principales por conteo de llamadas al sistema (con salida por intervalos)
sudo bpftrace -e 'tracepoint:raw_syscalls:sys_enter { @[comm] = count(); } interval:s:5 { print(@, 10); clear(@); }'

# Rastrear búsquedas DNS
sudo bpftrace -e 'uprobe:/lib/x86_64-linux-gnu/libc.so.6:getaddrinfo { printf("%s is resolving: %s\n", comm, str(arg0)); }'

# Seguimiento de fallos de página
sudo bpftrace -e 'software:page-faults:1 { @[comm, kstack] = count(); }'

# Rastreo del planificador de CPU
sudo bpftrace -e 'tracepoint:sched:sched_switch { @[args.prev_comm] = count(); }'