How to read LatencyLab output
LatencyLab does not tell you what is slow.
It tells you why the user waited.
This is the application's own information panel, shortened. The full version ships in the app, under the info button.
The screen, element by element
- The histogram (makespan distribution). Each bar counts runs by how long the whole flow took. Read the shape: a tight cluster means predictable latency; a long right tail means some runs go badly; two humps mean the system has two distinct behavioural modes, which is a structural fact worth explaining before you optimise anything.
- The percentiles (p50 / p90 / p95 / p99). p50 is the typical experience; p99 is what 1 in 100 users hits. They describe exposure, not targets to game.
- The critical path. The named chain of tasks, queue waits and delays that set the finish time of a run. Read it left to right as "this is literally why the user waited". Critical does not mean slow: a fast task on the path matters and a slow task off it does not.
- The critical-path frequency chart. How often each distinct chain was the bottleneck across all runs. A path dominating, say more than a fifth of runs, is how your design behaves rather than a fluke: that is the thing to design against. This chart is the tool's real answer; the histogram is context for it.
A worked example: the shipped Checkout model
Load Examples → Checkout and press Run. The model:
a click fires user.checkout_clicked, a UI task handles it
and emits checkout.started, which fans out to four backend
tasks at once. Two of them (db.load_cart and
db.load_saved_cards) share a database context with
concurrency 1, so one always queues behind the other. A fixed 150 ms
delay sits on the wiring to net.fetch_promotions: a
debounce, added for politeness.
Intuition says the slowest backend, the shipping quote around 165 ms, dominates. Now read the screen: the histogram shows where the runs landed, the percentiles say what typical and unlucky users got and the frequency chart says the chain through the 150 ms debounce and the totals render is the critical path in most runs. A politeness feature owns the median latency; no profiler could have told you that before the system existed. That is the kind of finding the tool exists to produce.
Six things the output means
- Many runs, because one run is not evidence. Contention, scheduling and coordination delays are not noise to be averaged away. They are the system.
- Percentiles describe exposure, not goals. p50 is what typically happens; p90, p95 and p99 are how often it goes badly. The shape behind them matters more than any one of them; lowering one blind usually shifts the cost elsewhere.
- A critical path is not what was slow. It is the chain that prevented progress in one run. Expensive work that was not on it delayed nobody, however bad it looks in isolation.
- A dominant path is structure, not a bug. A path holding things up in a large share of runs, conventionally more than a fifth, is a behavioural mode: how the system usually behaves.
- The long tail can usually be left alone, unless you are designing to a strict worst case. Optimising rare worst cases is how systems get complicated without getting faster.
- A representative run is one run chosen to make a dominant mode concrete, commonly its median or p95. It illustrates; it does not explain every outcome.
How to use it
Do not read every run. Name the dominant behaviour before proposing any fix. If a task never appears on a dominant path, making it faster changes nothing anybody experiences.
LatencyLab does not optimise systems.
It exposes structure.
Where to next
Every page answers one question.