bi-12 — Analysis
The governing principle
Source reading answers "what could happen." Tracing answers "what did happen."
In a codebase with generated code, feature flags, and platform branches, that gap is wide enough to invalidate confident conclusions. Every claim in a bug report should be labelled with which of the two produced it.
Instrument selection
| Situation | Instrument | Why |
|---|---|---|
| No hypothesis | tracing | a breakpoint requires knowing where to put it |
| Does this run? | tracing / one LOG | a breakpoint costs 100× |
| How often, how long? | tracing | the debugger destroys the timing |
| How did I get here? | debugger backtrace | nothing else gives the stack |
| A sequence over many iterations | logging | stepping 400 times is not a plan |
| Timing-dependent or racy | tracing only | breakpoints change the schedule and hide the bug |
| Cross-process ordering | tracing with flow events | the only tool showing both sides |
Why a breakpoint fails to hit
Three causes, in frequency order:
- Wrong process — Blink runs in a renderer, not the browser process you launched.
- Inlined — set it on the caller, break on a line, or fall back to a trace event.
- Feature-gated — the path is behind a
RuntimeEnabledFeaturethat is off.
The bridge that makes tracing a navigation tool
Trace events are TRACE_EVENT macros with literal string names, so:
see an event in a trace → grep the exact name → land in the code that ran
add a TRACE_EVENT → rebuild that target → watch it appear
Bidirectional. This is why tracing sits at rung 3 of the ladder rather than being a specialist
performance tool, and why devtools.timeline being a trace category matters: the DevTools panel
is a curated view over data you can widen.
The build flag that changes what you learn
dcheck_always_on = true keeps Blink's invariants live in a release build. Breaking one then
produces a message naming the invariant instead of a confusing misrender ten stages later. For a
learning checkout this is the single highest-value flag.