Skip to content

Latency chart: plot the summary p95 over time, not the trace window #78

Closed

Description

@htcom-code

Problem

Latency p95 over time collapses as traffic rises. The chart is derived from the in-memory trace window (TRACE_WINDOW = 500 rows) bucketed per minute (deriveP95), so the time it covers shrinks with load:

traffic 500 rows cover 1-minute buckets
1 req/s ~8 min 8 (a line)
10 req/s 50 s 1–2
67 req/s 7.5 s 1 (a single dot)

Measured during a 4,000-request burst: no polyline, one circle. The chart dies exactly when an operator needs it.

On a fresh connect it is worse: the first points come from the platform's ring-buffer dump, a few seconds of traffic from well before the connection, drawn under "over time".

The p95 card and the chart also disagree: the card shows the max of per-module metrics p95, the chart shows a value derived from the trace window, and neither is the platform's windowed summary.

Decision

The chart, the p95 card and the status mix are live widgets: they show what arrived after this connection, and a reload clears them. History is the trace table's job.

  • Source. Plot summary.p95LatencyMs, one point per summary frame received after connecting. Sample spacing comes from ready.tickMs, which the platform declares, so no 1 Hz assumption. Each point is the p95 over the platform's windowMs (60 s), sampled from at most capacity rows. The chart says both.
  • Time axis. The x axis spans the selected range and ends at now, not at the last point. When the stream goes quiet, the line slides left and the silence is visible. A chart pinned to its last point would look live while frozen.
  • Draw what exists. Before the range fills, the left side stays empty. Axis end labels show the times. With no samples, the existing empty frame is kept.
  • Gaps. The line breaks where two neighbouring points are more than 2 × tickMs apart (the same reasoning as the silence watchdog). Joining them would draw a measurement that was never taken.
  • Range option. TimeRange (5m · 15m · 1h · 6h) becomes a setting. The default is 15m, and the value is shared across tabs like the other settings.
  • Buffer. Up to 6 h of points are always kept (21,600 at 1 s), whatever range is selected. Widening the range shows what has already arrived.
  • p95 card. It reads summary.p95LatencyMs, so the card equals the chart's last point.
  • Status mix. It stays count-based and says so ("last N requests"). summary carries no per-status split.
  • Sample data. The generated curve is kept, already labelled sample data (fix(chart): label the sample latency curve as sample data #74). It gets timestamps that fill the selected range.
  • Hover. The crosshair picks the point nearest in time.
  • TRACE_WINDOW stays unexposed. The setting the user gets is a time, not a row count.

Done when

  • The chart no longer depends on the trace window: a burst of any size leaves it a line, not a dot.
  • The connect dump does not reach the chart.
  • A gap in the stream shows as a break in the line, and silence shows as empty space at the right edge.
  • Scenario tests drive real connect sequences through the stream fixtures. Reverting the change makes them fail.

Activity

  1. added a commit that references this issue on Oct 12, 2026
    7f4baba
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions