awesome-everything EN
↑ Обратно к восхождению

Производительность

Чтение parent и child chains: где применять правку

Суть Широкий leaf с одним parent''''ом — правь caller''''а. Широкий leaf с двадцатью parent''''ами — правь leaf. Граница self-time vs cum-time указывает, где работа, а где диспетчеризация.
Высота — путь к senior
НольJuniorMiddleSenior
Ты на middle-высоте — в небе
◷ 16 min

Сеньор открывает pprof и видит json.Marshal на 28% CPU. Он не тянется за более быстрой JSON-библиотекой. Он проверяет parent chain. Один широкий parent: логгер запросов. Правка не в библиотеке — в логгере, который вызывает Marshal на каждом запросе независимо от уровня логирования.

Чтение parent chain

Parent chain отвечает: «откуда вызывается этот широкий leaf?»

Концентрированный fan-in (один широкий parent-путь): leaf вызывается многократно из одного места. Правь caller’а — вызывать реже, кэшировать результаты, батчить или устранить вызов.

Распределённый fan-in (много узких parents): leaf — это shared-инфраструктура, используемая многими caller’ами. Правь сам leaf, потому что оптимизация любого одного caller’а оставляет остальных девятнадцать неизменными.

Классический пример: json.Marshal широкий с одним широким путём от логгера — значит, проблема в логгере; не меняй JSON-библиотеку, чини логгер. Тот же json.Marshal широкий и вызываемый из двадцати handler’ов — значит, JSON и есть bottleneck; меняй библиотеку или pre-encode.

Production-grade pprof и Pyroscope позволяют переключаться между leaf-up и caller-down view одним кликом; использовать оба — сеньорная привычка.

Чтение child chain (self-time vs cum-time)

Child chain отвечает: «эта функция делает работу сама или делегирует callee?»

Leaf с большим self-time и узкими детьми: функция делает работу сама. Правка внутри функции.

Parent с thin self-time и широким cum-time: это диспетчер. Цена — на уровень ниже в callee. Правь callee, не этот слой.

Правило чтения: иди от leaf’а с высоким self-time вниз по parent chain. Найди уровень, где cum-time резко падает при движении вверх. Этот уровень — «граница содержательной работы» — выше диспетчеризация, ниже исполнение. Правку применяй внутри этой границы.

Неверное определение этой границы — причина переписывания middleware, оборачивающего медленный DB-вызов, или оптимизации HTTP-роутеров, когда цена в теле handler’а.

СигналЧто означаетУровень правки
Широкий leaf, один доминирующий parentКонцентрированный call-siteCaller (реже вызывать / батчить / кэшировать)
Широкий leaf, много тонких parentsShared-инфраструктураСам leaf
Высокий self-time, узкие childrenФункция делает работу самаВнутри функции
Thin self-time, широкий cum-timeДиспетчерВнутри callee (уровнем ниже)

Амортизация fan-in

Когда одна функция вызывается из многих caller’ов, оптимизация leaf’а складывается по каждому caller’у. 30% локальное улучшение в shared-функции, используемой двадцатью путями, даёт 30% по каждому из путей.

Обратный случай — fan-out: один caller, бьющий по многим callees. Оптимизация каждого callee — локальное сокращение одного пути.

Сеньорный приём: смотри fan-in/fan-out shape до выбора leaf vs caller fix. Высокий fan-in (shared infra) — leaf fix амплифицируется. Высокий fan-out (один caller, много callees) — caller fix (батчинг, кэширование, устранение вызова) амплифицируется. Эта математика часто перевешивает выбор семейства правок: даже маленький fix на высоко-fan-in leaf’е может перебить большую правку на single-caller-пути.

Bottom-up vs top-down views

pprof, Pyroscope и Intel VTune поддерживают два дополняющих друг друга view.

Bottom-up: ранжирование функций по self-time, leaf-first. Лучше для поиска одной функции, съедающей больше всего CPU.

Top-down: ранжирование функций по cum-time от корня, parent-first. Лучше для поиска подсистемы, ответственной за бо́льшую часть времени.

Сеньорная привычка чтения: сначала bottom-up — назвать горячий leaf, затем top-down — увидеть, какой entry-point его держит. Leaf, горячий под одним entry-point’ом — локализованная правка; leaf, горячий под многими — shared-инфраструктура.

Почему это работает

Intel Top-Down Microarchitecture Analysis (TMA) расширяет это дальше, классифицируя каждый горячий фрейм в front-end bound, back-end bound, retiring или bad speculation. TMA разобран в уроке об аппаратных счётчиках. Чтение parent/child chain здесь — пресреквизит: TMA добавляет CPU-уровень поверх.

Проследи
1/5

Go API имеет p99 600 мс. Профиль показывает runtime.mallocgc на 18% и runtime.scanobject на 14%. Трассируй диагноз и правку.

1
Step 1 of 5
Шаг 1: runtime.mallocgc + runtime.scanobject = 32% CPU в GC-machinery. Какова категория?
2
Locked
Шаг 2: переключись на /debug/pprof/allocs. Широкий leaf: json.Encode вызываемый из middleware/RequestLog. Что это говорит?
3
Locked
Шаг 3: кандидаты на правку?
4
Locked
Шаг 4: применена правка (а). Предсказанный эффект?
5
Locked
Шаг 5: профиль после правки показывает GC на 18%, а не предсказанные 16%. p99 упал с 600 до 480 мс. Диагноз?
Проследи
1/5

Node-сервис имеет широкий leaf JSON.parse на 24% CPU. Трассируй, почему наивная смена парсера может не помочь.

1
Step 1 of 5
Шаг 1: JSON.parse широкий. Первая проверка?
2
Locked
Шаг 2: parent chain показывает parse вызываемый из одного middleware: requestValidator, один раз на запрос. Средний payload ~50 KB. Что это означает?
3
Locked
Шаг 3: какие ещё варианты до смены библиотеки?
4
Locked
Шаг 4: команда выбирает (а) — переключиться на lazy field extraction. Предсказанный эффект?
5
Locked
Шаг 5: верификация?
Расставь шаги по порядку

Расставь шаги цикла атаки на hot path по порядку, как их выполняет сеньор-инженер:

  1. 1 Открой профиль и найди самый широкий leaf по self-time
  2. 2 Прочти parent chain (один caller или много?) и children (реальная цена уровнем ниже?)
  3. 3 Классифицируй hotspot: CPU, аллокации, кэш, лок, syscall или JIT deopt
  4. 4 Выбери категориальное семейство правок, соответствующее классификации
  5. 5 Напиши только предсказанное изменение, без scope creep
  6. 6 Сними свежий профиль под той же нагрузкой
  7. 7 Diff: локальный фрейм сжался И headline-метрика улучшилась? Оба условия обязательны для релиза
  8. 8 Если headline не сдвинулся, найди новый топ hotspot — он был маскирован первым
Викторина

Широкая leaf-функция вызывается из двадцати разных parent-путей, каждый вносит тонкий вклад. Где применять правку?

Вспомните перед уходом
  1. 01
    Почему важно читать и parent chain, И children при диагностике широкого leaf'а, и что каждое направление говорит?
  2. 02
    Что означает «граница содержательной работы» в pprof и как её найти?
Итог

Parent chain и child chain — две линзы на один и тот же широкий leaf. Parent chain раскрывает форму fan-in: один caller — правь call-site, двадцать caller’ов — правь leaf. Child chain раскрывает, несёт ли функция цену сама или является pass-through к callee. Граница между диспетчеризацией и исполнением указывает, где находится эффективное место правки. Bottom-up и top-down view профилей делают оба прочтения механическими: bottom-up называет горячий leaf, top-down показывает, какая подсистема его держит. Вместе эти два прочтения устраняют самую частую ошибку выбора уровня в performance-работе.

Связанные уроки
встречается в159
Продолжить восхождение ↑JIT deopt, цикл fix-and-verify и PR-time профилирование
хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.