Трассировка ядра: ftrace и trace-cmd

Рейтинг: 62.1% · 15 голосов
Подробный курс по диагностике и производительности Linux для админов и DevOps: с чего начать, методология USE, логи (journalctl, dmesg), процессы, CPU, память и OOM, диск и IO (iostat), сеть (ss, tcpdump), системные вызовы и strace, ltrace, perf, флеймграфы, ftrace, eBPF и bpftrace, lsof, мониторинг. Разбор каждого инструмента с чтением вывода.
Ответить
Аватара пользователя
Dmitry_SRE
Сообщения: 47
Зарегистрирован: 11 май 2026, 05:31

Трассировка ядра: ftrace и trace-cmd

Сообщение Dmitry_SRE »

Оглавление курса (47)
  1. С чего начать диагностику Linux: методология вместо паники
  2. Первые 60 секунд: экспресс-диагностика нагруженного сервера
  3. Методологии диагностики: USE, RED и здравый смысл
  4. Логи systemd через journalctl: где искать причину
  5. Где лежат логи Linux: /var/log, dmesg и rsyslog
  6. Источники правды: load average, /proc и /sys
  7. Процессы Linux: ps, pstree и состояния процессов
  8. Интерактивный мониторинг: top и htop
  9. Метрики процессов во времени: pidstat
  10. Приоритеты и ограничения: nice, ionice, cgroups
  11. Сигналы и зависшие процессы: kill, и что делать с D-state
  12. Загрузка CPU: user, system, iowait, steal и контекст-свитчи
  13. Диагностика CPU по ядрам: vmstat и mpstat
  14. Профилирование CPU: perf top и поиск пожирателя
  15. Частоты, троттлинг и NUMA: turbostat и numastat
  16. Память Linux: RSS, VSZ, page cache и миф о нехватке памяти
  17. Сколько памяти занято: free, /proc/meminfo и vmstat
  18. Поиск утечек и пожирателей памяти: smem, pmap, smaps
  19. Swap и подкачка: swapon, swappiness, когда своп - это боль
  20. OOM killer: кто и за что убил процесс
  21. Память ядра и slab: slabtop и куда уходит RAM
  22. Подсистема ввода-вывода: путь запроса от приложения до диска
  23. Диагностика диска: iostat и чтение await, %util
  24. Кто грузит диск: iotop и атрибуция io процессам
  25. Файловые системы: df, du, иноды и куда делось место
  26. Глубокая диагностика блочного слоя: blktrace и biolatency
  27. Кеш страниц и грязные данные: dirty pages, fsync, drop_caches
  28. Сетевой стек Linux: путь пакета и где возникают задержки
  29. Сокеты и соединения: ss и netstat
  30. Захват трафика: tcpdump для диагностики сети
  31. Задержки и потери в сети: ping, mtr, диагностика латентности
  32. Сеть как источник проблем: nftables, conntrack, дропы
  33. Что такое системный вызов и зачем его трассировать
  34. strace: трассировка системных вызовов на практике
  35. strace в бою: почему программа висит, падает или тормозит
  36. ltrace: трассировка вызовов библиотек
  37. Накладные расходы трассировки и безопасные альтернативы
  38. perf: универсальный профайлер Linux
  39. Флеймграфы: визуализация профиля производительности
  40. Трассировка ядра: ftrace и trace-cmd (вы здесь)
  41. eBPF: революция в наблюдаемости Linux
  42. Инструменты eBPF на практике: BCC и bpftrace
  43. lsof: открытые файлы, дескрипторы, кто держит файл и порт
  44. Разбор кейса: приложение тормозит - пошаговая диагностика
  45. Непрерывный мониторинг: sar, node_exporter, Grafana, Zabbix
  46. Диагностика в контейнерах: cgroups, лимиты, Docker и Kubernetes
  47. Карта инструментов и сквозной разбор инцидента производительности
Бывает так: процесс висит в состоянии D, нагрузка на диск вроде есть, но top и iostat показывают "среднюю температуру по больнице". Ты уже посмотрел логи, потыкал strace - а strace ловит только переход юзерспейс/ядро через системные вызовы и не показывает, что именно ядро делает ВНУТРИ. И вот тут начинается настоящая трассировка ядра linux: тебе нужно заглянуть под капот и увидеть, какие функции ядра вызываются, в каком порядке и сколько каждая выполняется.

Хорошая новость: для этого ничего ставить не надо. В каждом современном ядре с systemd уже встроен трассировщик - ftrace. Это не отдельная программа, а интерфейс прямо в ядре, которым ты управляешь через обычные файлы. В этом уроке разберём ftrace linux руками, потом наденем сверху удобную обёртку trace-cmd, а в конце честно сравним ftrace с perf и eBPF, чтобы ты понимал, какой инструмент брать в 2026 году.

Что такое ftrace и где он живёт

ftrace (function tracer) - это механизм внутри самого ядра. Когда ядро собрано с нужными опциями (CONFIG_FUNCTION_TRACER, CONFIG_FUNCTION_GRAPH_TRACER, CONFIG_DYNAMIC_FTRACE - в дистрибутивных ядрах это включено), компилятор вставляет в начало почти каждой функции ядра вызов-крючок (через -pg / fentry). Благодаря динамическому ftrace по умолчанию эти крючки заменены на nop-инструкции и стоят ровно ноль. Когда ты включаешь трассировку, ftrace на лету патчит нужные крючки в реальный вызов, пишет события в кольцевой буфер в памяти (отдельный буфер на каждый CPU), а ты потом этот буфер читаешь.

Управление - через специальную файловую систему tracefs. На современных ядрах (2026) она монтируется сюда автоматически при загрузке:

Код: Выделить всё

/sys/kernel/tracing
На старых системах то же самое лежало в debugfs - /sys/kernel/debug/tracing, и этот путь до сих пор работает как симлинк-совместимость. Если первого пути нет, смонтируй вручную:

Код: Выделить всё

sudo mount -t tracefs nodev /sys/kernel/tracing
Загляни внутрь (нужен root):

Код: Выделить всё

sudo ls /sys/kernel/tracing
available_tracers   current_tracer    trace
set_ftrace_filter   available_events  trace_pipe
set_graph_function  tracing_on        events
buffer_size_kb      options           ...
Главные файлы, которые надо запомнить:
  • available_tracers - какие режимы (трейсеры) доступны.
  • current_tracer - какой режим включён сейчас. Запись в него меняет режим И очищает буфер. По умолчанию там nop (трассировка выключена).
  • set_ftrace_filter - белый список функций, которые трассируем (фильтр для function/function_graph).
  • set_graph_function - для function_graph: трассировать только эти функции и всё, что они вызывают внутри (а не плоский фильтр).
  • trace - снимок буфера, читаешь как обычный файл (чтение не опустошает буфер).
  • trace_pipe - то же, но потоком в реальном времени (чтение опустошает буфер).
  • tracing_on - 1 включить запись, 0 поставить на паузу (режим при этом сохраняется).
  • buffer_size_kb - размер кольцевого буфера на CPU. По умолчанию мало, под большую запись увеличивают.
Изображение

Function и function_graph: kernel trace своими руками

Посмотрим, какие режимы есть:

Код: Выделить всё

sudo cat /sys/kernel/tracing/available_tracers
function_graph function blk hwlat wakeup_dl wakeup_rt wakeup nop
Нас интересуют два главных. function пишет плоский список: какая функция ядра, на каком CPU и когда вызвана. function_graph умнее - он рисует дерево вызовов с отступами и, главное, замеряет ДЛИТЕЛЬНОСТЬ каждой функции от входа до выхода. Для поиска латентности это золото.

ВАЖНО про грабли с производительностью. Если включить function на всё ядро без фильтра, система зальёт буфер миллионами событий в секунду и нагруженный сервер может ощутимо просесть или подвиснуть. Поэтому железное правило: сначала ставим фильтр, потом включаем режим. Протрассируем работу с блочным слоем - функции, имена которых начинаются на blk:

Код: Выделить всё

cd /sys/kernel/tracing
sudo bash -c 'echo "blk*" > set_ftrace_filter'
sudo bash -c 'echo function_graph > current_tracer'
sudo bash -c 'echo 1 > tracing_on'
sleep 1
sudo bash -c 'echo 0 > tracing_on'
sudo head -20 trace
Читаем вывод function_graph по колонкам:

Код: Выделить всё

 CPU  DURATION       FUNCTION CALLS
  2)               |  blk_mq_submit_bio() {
  2)   1.230 us    |    blk_mq_get_tag();
  2) + 18.450 us   |    blk_mq_dispatch_rq_list();
  2)   0.890 us    |    blk_account_io_start();
  2) ! 142.300 us  |  }
Что тут что:
  • CPU - на каком ядре процессора это происходило (буфер per-CPU, поэтому колонка важна).
  • DURATION - сколько функция выполнялась. us это микросекунды, ns - наносекунды.
  • Скобки { и } - вход в функцию и выход. Отступ показывает вложенность вызовов, как дерево. У вложенных листовых функций (которые никого не зовут) длительность пишется сразу в строке.
  • Символы-маркеры важны: + значит дольше 10 us, ! - дольше 100 us, # - дольше 1000 us (1 ms), * и @ - ещё дольше. Это ftrace сам подсвечивает подозрительно долгие вызовы. Увидел "!" или "#" - вот туда и копай.
В примере вся blk_mq_submit_bio заняла 142 us, и львиную долю съел dispatch_rq_list - значит затык в диспетчеризации запроса к диску, а не в получении тега. Вот так из абстрактного "тормозит диск" получается конкретное имя функции. Хочешь чисто посчитать, не трассируя, - есть отдельный счётчик в файле set_ftrace_filter с экшеном или утилита funccount (о ней ниже).

События подсистем и обёртка trace-cmd

Кроме трассировки произвольных функций, у ftrace есть готовые события (tracepoints) - заранее расставленные разработчиками ядра стабильные точки в важных местах. Их тысячи, сгруппированы по подсистемам: sched (планировщик), block (диск), net (сеть), irq, syscalls, ext4/xfs, kmem. Посмотреть список:

Код: Выделить всё

sudo head /sys/kernel/tracing/available_events
События удобнее сырых функций: у них осмысленный текст, стабильные имена полей и они дешевле, потому что точек мало и стоят они в выверенных местах. Например, sched_switch покажет переключения контекста с именами процессов. Но дёргать десятки файлов руками утомительно, поэтому есть trace-cmd - консольная обёртка над всем этим хозяйством (актуальная ветка на 2026 - trace-cmd v3.x; ставится одноимённым пакетом в Ubuntu/Debian и RHEL/Fedora; в Astra Linux и RED OS тоже есть в репозиториях).

Базовый цикл - record, потом report. Записываем все события планировщика во время команды:

Код: Выделить всё

sudo trace-cmd record -e sched dd if=/dev/zero of=/tmp/t bs=1M count=50
trace-cmd по процессу на CPU сольёт кольцевые буферы в файл trace.dat в текущем каталоге. Теперь читаем человекочитаемо:

Код: Выделить всё

sudo trace-cmd report | head
   dd-4821  [001]  9023.118: sched_wakeup:  comm=kworker/1:1 pid=88 prio=120
   dd-4821  [001]  9023.118: sched_switch:  dd:4821 [120] R ==> kworker/1:1:88
Разбор строки: имя-pid процесса, [001] - номер CPU в скобках, дальше timestamp в секундах, имя события и его поля. sched_switch читается как "кто уступил процессор кому": dd ушёл, kworker пришёл. Символ перед стрелкой - состояние процесса, который уступил: R - runnable (его просто вытеснили, он ещё хочет считать), S - спит по своей воле, D - непрерывный сон (обычно ожидание диска/IO), а вот частое R ==> с одним и тем же процессом намекает на конкуренцию за CPU.

Чтобы трассировать функции через trace-cmd (а не events), есть плагины function и function_graph:

Код: Выделить всё

sudo trace-cmd record -p function_graph -l 'vfs_*' cat /etc/hostname
sudo trace-cmd report
Флаг -p выбирает плагин (function_graph), -l задаёт фильтр функций (поддерживает glob-маски, можно несколько -l). Это тот же set_ftrace_filter, только без возни с echo в три файла. Полезные опции: -P PID привязать к процессу, -F запускать команду с самого старта трассировки, -M маска CPU.

Когда хочется не текст, а картинку - есть KernelShark, графический вьюер для trace.dat (актуальная линейка - KernelShark 2.x, умеет грузить и сливать несколько trace-файлов через концепцию data streams). Он рисует временную шкалу по CPU: видно, как процессы скачут между ядрами, где простои, где всплески прерываний, где кто кого вытеснил. Запускается просто:

Код: Выделить всё

kernelshark trace.dat
Типичные грабли и заблуждения
  • Включил function без фильтра. Самая частая ошибка новичка. Сначала set_ftrace_filter (или -l у trace-cmd), и только потом запись. Иначе оверхед просадит нагруженный сервер. На проде по возможности используй events вместо широкого function - они дешевле.
  • Забыл сбросить трейсер. После экспериментов верни режим в покой: echo nop > current_tracer и echo > set_ftrace_filter. Самый надёжный способ обнулить всё разом - echo 0 > tracing_on и затем trace-cmd reset. Иначе ftrace продолжит молотить в фоне и съедать такты.
  • Маленький буфер - потерянные события. Кольцевой буфер перезаписывает старое новым. Если в report/KernelShark пропуски или строка "LOST EVENTS", подними buffer_size_kb или у trace-cmd флаг -b (размер в KB). Это не глюк, это переполнение.
  • Путаю ftrace и strace. strace - это про системные вызовы одного процесса с границы юзерспейса (и он тормозит цель в разы из-за ptrace). ftrace - про внутренности ядра целиком и почти без оверхеда при фильтре. Разные слои и разная цена.
  • Думаю, что надо писать скрипты с нуля. Не надо. У Брендана Грегга есть набор perf-tools на чистом ftrace: funcgraph (дерево вызовов функции), funccount (счётчик вызовов), funcslower (функции медленнее порога), iolatency (гистограмма латентности диска), kprobe. Это готовые шелл-обёртки, ставятся почти без зависимостей и работают даже там, где eBPF недоступен (старое ядро, урезанная сборка, отсутствие BTF).
ftrace против perf и eBPF в 2026

Чтобы не брать молоток на каждый винт, держи карту в голове:
  • ftrace - отвечает на "какие функции ядра вызываются, в каком порядке и сколько длятся" дёшево и из коробки, без компиляторов и пакетов. Идеален для function_graph по конкретной подсистеме и для быстрого взгляда на tracepoints.
  • perf - профилирование по сэмплам (perf record/report, флеймграфы) и аппаратные счётчики PMU (кэш-промахи, IPC). Берёшь, когда вопрос "где в целом горит CPU", а не "что делает одна функция".
  • eBPF (bpftrace/bcc) - когда нужна своя логика, фильтрация и АГРЕГАЦИЯ прямо в ядре, чтобы не тащить мегабайты сырых событий в юзерспейс. На современных ядрах (2026) с BTF предпочитают пробы fentry/fexit (раньше назывались kfunc/kretfunc): они вешаются на функции ядра через eBPF-трамплины с почти нулевым оверхедом, типы аргументов берут из BTF (меньше ручного каста), и - в отличие от kretprobe - в fexit доступны и аргументы, и возвращаемое значение. Готовые bcc/bpftrace инструменты (biolatency, execsnoop, runqlat, tcpconnect, opensnoop) во многих расследованиях уже заменили связки на сыром ftrace и strace.
Важно: это не "или-или". bpftrace под капотом для tracepoints и kprobe опирается на ту же инфраструктуру ядра, что и ftrace, и они отлично дополняют друг друга - ftrace покажет точную последовательность вызовов, eBPF посчитает распределение, perf даст флеймграф. На 2026 для повседневной диагностики на свежем ядре первый выбор - bpftrace, но ftrace остаётся незаменим, когда eBPF выключен политикой безопасности или когда нужен именно граф вызовов с длительностями.

Мини-лаба: повтори прямо сейчас
  • Смонтируй tracefs (если не смонтирована) и выведи available_tracers и первые строки available_events.
  • Через set_ftrace_filter ограничь трассировку функциями vfs_*, включи function_graph на секунду, прочитай trace и найди вызов с маркером "!" или "#".
  • Сделай sudo trace-cmd record -e sched sleep 2, затем trace-cmd report. Найди строки sched_switch и пойми, какой процесс кого вытеснил и в каком состоянии (R/S/D) он ушёл.
  • Запиши то же самое и открой trace.dat в KernelShark - найди на шкале по CPU момент переключения контекста.
  • Обязательно верни систему в покой: trace-cmd reset, либо вручную echo nop > current_tracer и echo > set_ftrace_filter.
Контрольные вопросы
  • Чем function_graph отличается от function и какое поле в его выводе показывает латентность? Что означают маркеры +, ! и #?
  • Почему перед включением трассировки всего ядра обязательно задавать set_ftrace_filter, и чем events безопаснее для прода?
  • Что делают команды trace-cmd record и trace-cmd report, в каком файле оказывается результат и как его посмотреть картинкой?
  • Когда ты возьмёшь ftrace, а когда уйдёшь к perf или bpftrace? В чём преимущество fexit над kretprobe?
Итог: что запомнить

ftrace - встроенный в ядро трассировщик, рулится файлами в /sys/kernel/tracing (tracefs, монтируется сама на 2026). function_graph рисует дерево вызовов с длительностью и сам подсвечивает долгие функции маркерами +, ! и #. События (sched, block, net) - готовые стабильные tracepoints в подсистемах, дешевле сырых функций. trace-cmd record/report - удобная обёртка (ветка v3.x), KernelShark - картинка по времени. Главное правило: сначала фильтр, потом запись, и не забудь trace-cmd reset. Когда логов и strace не хватает, чтобы понять поведение ядра, - kernel trace через ftrace это твой следующий шаг, а за более умной агрегацией иди в bpftrace с fentry/fexit.
👍2 ❤️3 🔥 😄 🤔
Аватара пользователя
kafkaaddict
Сообщения: 1
Зарегистрирован: 07 июн 2026, 03:06

Re: Трассировка ядра: ftrace и trace-cmd

Сообщение kafkaaddict »

Спасибо, наконец дошло чем ftrace отличается от strace - все время думал это одно и то же. А маркеры + ! # в function_graph реально удобные, сразу видно куда копать.
👍 ❤️ 🔥 😄 🤔
Аватара пользователя
zfs4
Сообщения: 1
Зарегистрирован: 02 июн 2026, 19:17

Re: Трассировка ядра: ftrace и trace-cmd

Сообщение zfs4 »

Подтверждаю про фильтр: запустил function без set_ftrace_filter на тестовой вирталке и она знатно подвисла секунд на десять. Теперь всегда сначала -l, потом запись, а в конце trace-cmd reset. Раздел про fexit vs kretprobe тоже зашел.
👍 ❤️ 🔥 😄 🤔
Ответить
← Предыдущая глава
Флеймграфы: визуализация профиля производительности
Следующая глава →
eBPF: революция в наблюдаемости Linux

Все главы курса «Диагностика и производительность Linux: логи, strace, perf и eBPF»

Поделиться темой: ✈ Telegram VK
Похожие запросы: что такое системный вызов и зачем трассироватьМониторинг и метрики nginxЛоги nginx: access_log и JSON

Вернуться в «Диагностика и производительность Linux: логи, strace, perf и eBPF»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость