Skip to content

Reuse Dygraph line chart data structures#223

Merged
novykh merged 3 commits into
mainfrom
agent/reuse-dygraph-line-data
Jul 16, 2026
Merged

Reuse Dygraph line chart data structures#223
novykh merged 3 commits into
mainfrom
agent/reuse-dygraph-line-data

Conversation

@ktsaou

@ktsaou ktsaou commented Jul 16, 2026

Copy link
Copy Markdown
Member

What changed

  • add a Dygraphs line-data handler that reuses the allocated series arrays, point arrays, and point objects across compatible updates
  • overwrite every timestamp and value in those reusable containers from every new response
  • discard the reusable containers when labels, label order, row count, or the visible point boundary changes
  • fall back to Dygraphs' default handler when labels are not unique
  • keep stacked and stacked-bar charts on their existing data handler
  • add parity and lifecycle coverage for compatible updates, historical corrections, shape changes, label reordering, annotations, zoom boundaries, gaps, log scale, and rolling

Root cause

Dygraphs' default line handler reconstructs extracted [x, y] pairs and point records on every data update. A chart with thousands of dimensions therefore creates millions of short-lived arrays and objects per refresh, increasing preparation time, heap growth, and garbage-collection pressure even when the response shape is unchanged.

Measured benefit

An isolated local preparation benchmark used the production CommonJS build on Node.js 22.22.2 with 6,000 dimensions × 297 timestamps (1,782,000 values). Both handlers were warmed first, all values changed before every sample, 20 samples per handler were run in alternating order, and explicit garbage collection preceded each sample.

The measured scope is exactly the stage changed by this PR: extractSeries plus seriesToPoints.

Repeated compatible update Dygraphs default Reusable handler Change
Median preparation time 102.5 ms 49.3 ms 51.9% lower; 2.08× faster
p95 preparation time 121.8 ms 66.2 ms 45.6% lower
Median transient heap increase 455.38 MiB 0.09 MiB 99.98% lower
p95 transient heap increase 455.44 MiB 0.13 MiB 99.97% lower

The heap figures measure additional allocation during one update, not total retained chart heap. The reusable-handler baseline already contains the current chart structures.

The first render still constructs the arrays and point objects. These results apply to subsequent structurally compatible updates. They exclude response creation, SDK transformation, extrema and range calculation, layout, and canvas drawing; no end-to-end rendering percentage is claimed.

What is reused — and what is not

This change reuses allocations, not data.

Every new response is still fully processed:

  • every series and every row is traversed
  • every reusable [x, y] pair receives the latest timestamp and value, including corrected historical values
  • every reusable visible point receives the latest xval and yval
  • Dygraphs recalculates ranges, normalized coordinates, and canvas coordinates from those new values

The handler does not cache query results, skip values, or keep previous values merely because the response shape is unchanged.

A response is structurally compatible only when:

  • labels have exactly the same count, names, and order
  • labels are unique
  • the row count is unchanged
  • a reused visible point array has the same starting boundary and length

If dimensions connect, disconnect, reconnect, or replicate and this changes the label sequence or row count, the reusable containers are discarded and rebuilt. If the structure stays the same but any current or historical values change, the containers are retained and every value is overwritten from the new response.

Behavior and compatibility

This uses Dygraphs' supported public dataHandler extension point; it does not fork Dygraphs or mutate undocumented Dygraphs state.

Queries, payloads, chart results, line rendering, gaps, logarithmic scales, rolling windows, annotations, zoom behavior, and stacked-chart behavior remain unchanged. Structural incompatibility causes a safe rebuild; duplicate labels use Dygraphs' original handler.

Validation

  • 145 Jest suites passed
  • 1,378 tests passed and 2 skipped
  • focused handler suite: 7 tests passed
  • same-label, same-row-count, same-timestamp historical corrections retain object identity while matching the stock handler's values, ranges, normalized coordinates, and canvas coordinates
  • focused ESLint passed
  • CommonJS build compiled 465 files
  • ES-module build compiled 465 files
  • installed into Cloud Frontend and manually exercised on a high-cardinality dashboard

@ktsaou
ktsaou marked this pull request as ready for review July 16, 2026 12:48
@novykh
novykh merged commit 2bd6659 into main Jul 16, 2026
2 checks passed
@novykh
novykh deleted the agent/reuse-dygraph-line-data branch July 16, 2026 13:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants