Pillar 02 · Performance

Find the slow path — and the redundant one.

Timed traces, frame and jank timing, widget rebuild counts, and startup — every one a truthfully-measured number, surfaced as a dense, sortable analytics table instead of a wall of sparse cards.

Traces · timed spans

One row per operation. Every metric that matters.

Count, averages, the full percentile spread, total cost, how often it fires, and how fast — all sortable, all searchable. Operations fired suspiciously often get a HOT flag so redundant work stops hiding in the noise.

Traces hot / dup errors sorted: total ↓
operation count avg ↓ p95 p99 max total intvl rate err
api.fetchMessagesnetwork 410 182ms 410ms 720ms 980ms 74.6s 220ms 4.5 6
analytics.tracknetwork 980 14ms 40ms 88ms 210ms 13.7s 108ms 9.3 2
db.query(messages)dbHOT 880 12ms 34ms 58ms 120ms 10.6s 120ms 8.3 ·
image.decodecpu 320 28ms 74ms 140ms 280ms 9.0s 330ms 3.0 ·
build:HomeScreenrender 1,240 4.2ms 9.8ms 14ms 22ms 5.2s 96ms 10.4 ·
bloc.mapEventstateHOT 1,500 2.1ms 5.2ms 9.1ms 18ms 3.2s 64ms 15.6 ·
scroll.layoutrenderHOT 5,400 0.6ms 1.4ms 2.8ms 6ms 3.2s 11ms 90.9 ·
json.decodecpuHOT 2,200 0.8ms 2.1ms 4.0ms 9ms 1.8s 40ms 25.0 ·

avg inter-call interval (intvl) + count is how duplicate work surfaces — a tight interval at a high count means the same op is firing back-to-back.

Drill into any key

Distribution, exemplars, and the span tree.

Latency distribution

Where calls actually land — not just the average.

Slowest exemplars
980msroomId=heavy · cold
720msroomId=general
410msroomId=alerts

Real calls with timing + attributes.

Span tree
api.fetchMessages · 182ms
db.query · 96ms
json.decode · 58ms

Nested spans on a shared monotonic clock.

Beyond traces

Frames, rebuilds, and startup.

Frames & jank

14 jank · 4.2%
build p50/95/99
3.2/8.1/16.4
raster p50/95/99
2.1/6.4/12.8

Frame-time timeline with build/raster/total percentiles and the worst recent frames + their cause. Reset the counters to measure a specific interval.

Widget rebuilds

EXCESSIVEChatBubble5,400
EXCESSIVEMessageList1,240
PresenceDot880
ComposerField320

Per-label counts from instrumented subtrees. Excessive rebuilders flagged.

STARTUP · TIME TO FIRST FRAME
480ms

A single headline metric from init to first frame, broken down by phase — and an honest "not measured" state when it wasn't captured.

Engine init120ms
Dart VM + isolate90ms
First frame build210ms
First frame raster60ms

Real code

Trace a span. Count a rebuild.

chat_repository.dart
// Wrap any operation — sync or async.
final messages = await Radar.trace(
  'api.fetchMessages',
  category: 'network',
  () => api.fetchMessages(roomId),
);

// Nested spans share a monotonic clock —
// they roll up into a parent/child tree.