awesome-everything RU
↑ Back to the climb

Performance

Reading parent and child chains: where to apply the fix

Crux A wide leaf with one parent means fix the caller. A wide leaf with twenty parents means fix the leaf. Self-time vs cum-time boundary locates the work vs dispatch split.
Your altitude — climbing toward senior
ZeroJuniorMiddleSenior
You are at middle altitude — in the sky
◷ 16 min

A senior engineer opens pprof and looks at json.Marshal at 28% CPU. They do not reach for a faster JSON library. They check the parent chain. One wide parent: a request logger. The fix is not the library — it is the logger calling Marshal on every request regardless of log level.

Reading the parent chain

The parent chain answers: “where does this wide leaf get called from?”

Concentrated fan-in (one wide parent path): the leaf is called repeatedly from a single location. Fix the caller — call less often, cache results, batch, or eliminate the call.

Distributed fan-in (many narrow parents): the leaf is shared infrastructure used by many callers. Fix the leaf itself, because optimising any one caller leaves the other nineteen unchanged.

The classic example: json.Marshal wide with one wide path from a logger means the logger is the bug — don’t switch JSON libraries, fix the logger. The same json.Marshal wide and called from twenty handlers means JSON is the bottleneck — switch libraries or pre-encode.

Production-grade pprof and Pyroscope let you switch between leaf-up and caller-down views with one click; using both is the senior reading habit.

Reading the child chain (self-time vs cum-time)

The child chain answers: “does this function do the work, or does it delegate to a callee?”

Self-time-heavy leaf with narrow children: the function is doing the work itself. Fix is inside the function.

Cum-time-heavy parent with thin self-time: this function is a dispatcher. The cost sits one level down in a callee. Fix the callee, not this layer.

The reading rule: walk from the leaf with high self-time down the parent chain. Find the level where cum-time drops sharply as you move up. That level is the “boundary of meaningful work” — above it is dispatch, below it is execution. Apply the fix inside that boundary.

Misreading this boundary is how teams end up rewriting middleware that wraps a slow database call, or optimising HTTP routers when the cost is in the handler body.

SignalWhat it meansFix layer
Wide leaf, one dominant parentConcentrated call siteCaller (call less often / batch / cache)
Wide leaf, many thin parentsShared infrastructureLeaf itself
High self-time, narrow childrenFunction does the workInside the function
Thin self-time, wide cum-timeDispatcherInside the callee (one level down)

Fan-in amplification

When one function is called from many callers, optimising the leaf compounds across each caller. A 30% local improvement in a shared function used by twenty paths gives 30% on every one.

The inverse — fan-out: one caller hitting many callees — makes optimising each callee a single-path local saving.

Senior move: look at fan-in/fan-out shape before deciding leaf vs caller fix. High fan-in (shared infra) means leaf fix amplifies. High fan-out (one caller, many callees) means caller fix (batching, caching, eliminating the call) amplifies. This math often outweighs the fix-family choice: even a small fix on a high fan-in leaf can outscore a large fix on a single-caller path.

Bottom-up vs top-down views

pprof, Pyroscope, and Intel VTune all support two complementary views.

Bottom-up: rank functions by self-time, leaf-first. Best for finding which single function eats the most CPU.

Top-down: rank functions by cum-time from root, parent-first. Best for finding which subsystem is responsible for the most time.

Senior reading habit: open bottom-up first to name the hot leaf, then switch to top-down to see which entry-point owns it. A leaf that is hot under one entry-point is a localised fix; a leaf that is hot under many is shared infrastructure.

Why this works

Intel’s Top-Down Microarchitecture Analysis (TMA) extends this further, classifying each hot frame into front-end bound, back-end bound, retiring, or bad speculation. TMA is covered in the hardware counters lesson. The parent/child chain reading here is a prerequisite — TMA adds the CPU-level layer on top.

Trace it
1/5

A Go API has p99 of 600 ms. Profile shows runtime.mallocgc at 18% and runtime.scanobject at 14%. Trace the diagnosis and fix.

1
Step 1 of 5
Step 1: runtime.mallocgc + runtime.scanobject = 32% of CPU in GC machinery. What is the category?
2
Locked
Step 2: switch to /debug/pprof/allocs. Wide leaf: json.Encode called from middleware/RequestLog. What does this say?
3
Locked
Step 3: fix candidates?
4
Locked
Step 4: applied fix (a). Predicted impact?
5
Locked
Step 5: post-fix profile shows GC at 18%, not the predicted 16%. p99 dropped from 600 to 480 ms. Diagnosis?
Trace it
1/5

A Node service has a wide leaf JSON.parse at 24% CPU. Trace why naively swapping parsers might not help.

1
Step 1 of 5
Step 1: JSON.parse is wide. First check?
2
Locked
Step 2: parent chain shows parse called from one middleware: requestValidator, once per request. Mean payload ~50 KB. What does this imply?
3
Locked
Step 3: what other options exist before switching libraries?
4
Locked
Step 4: team picks (a) — switch to lazy field extraction. Predicted impact?
5
Locked
Step 5: verify?
Order the steps

Order the steps of the hot-path attack loop, in the order a senior engineer runs them:

  1. 1 Open the profile and identify the widest leaf by self-time
  2. 2 Read the parent chain (one caller or many?) and the children (is real cost one level down?)
  3. 3 Classify the hotspot: CPU, allocation, cache, lock, syscall, or JIT deopt
  4. 4 Pick the categorical fix family that matches the classification
  5. 5 Write only the predicted change, no scope creep
  6. 6 Capture a fresh profile under the same load
  7. 7 Diff: local frame shrank AND headline metric improved? Both must hold to ship
  8. 8 If headline did not move, find the new top hotspot — it was masked by the first
Quiz

A wide leaf function is called from twenty different parent paths, each contributing a thin slice. Where do you fix?

Recall before you leave
  1. 01
    Why is it important to read both the parent chain AND the children when diagnosing a wide leaf, and what does each direction tell you?
  2. 02
    What does 'boundary of meaningful work' mean in pprof, and how do you find it?
Recap

The parent chain and child chain are two lenses on the same wide leaf. The parent chain reveals fan-in shape: one caller means fix the call site, twenty callers means fix the leaf. The child chain reveals whether the function itself carries the cost or is a pass-through to a callee. The boundary between dispatch and execution is where the effective fix location lives. Bottom-up and top-down profile views make both reads mechanical: bottom-up names the hot leaf, top-down shows which subsystem owns it. Together these two reads eliminate the most common fix-layer error in performance work.

Connected lessons
appears again in159
Continue the climb ↑JIT deopt, the fix-and-verify loop, and PR-time profiling
shortcuts expand
search
K
prev piece
k
next piece
j
cycle tier
t
this menu
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.