Skip to content

Commit 4adc5bd

Browse files
committed
fix(docs): correct chart asset paths; reuse ResizeObserver and destroy old uPlot
Per Gemini review on PR #24. 1. `docs/benchmarks.md` and `docs/assets/bench-charts.js`: `./assets/` resolves to `/<version>/benchmarks/assets/` under mkdocs `use_directory_urls` (default true), which 404s — assets actually live at `/<version>/assets/`. Switch to `../assets/` so the chart page reaches them via one level up. 2. `.github/workflows/docs.yml` mike-asset verifier: same path bug — was probing `/dev/benchmarks/assets/bench-results/latest.json` which would have returned 404 once the snapshot landed (the verify step only runs on devel push, so the bug wouldn't surface until then). Aligned with the page's `../assets/` path. 3. `bench-charts.js` ResizeObserver leak on log-scale toggle: `attachResizeObserver` was called from inside `rebuild()` which fires on every toggle. Each click left a stranded observer + a stale `plot` reference its setSize closure was still firing on. Refactored to a single observer attached after the first build, which resolves `plot` lazily through a getter — toggle just swaps the underlying instance. 4. `bench-charts.js` orphaned uPlot DOM/listeners: `rebuild()` mounted a new uPlot without destroying the previous one. Added `if (plot) plot.destroy()` at the top of `rebuild()`. Combined with the observer fix above, the toggle is now state-clean across arbitrarily many flips. Syntax-checked bench-charts.js with `node --check`.
1 parent 5d1d7e3 commit 4adc5bd

3 files changed

Lines changed: 29 additions & 10 deletions

File tree

.github/workflows/docs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ jobs:
7373
github.ref == 'refs/heads/devel'
7474
run: |
7575
set -euo pipefail
76-
URL="https://elijahr.github.io/lockfreequeues/dev/benchmarks/assets/bench-results/latest.json"
76+
URL="https://elijahr.github.io/lockfreequeues/dev/assets/bench-results/latest.json"
7777
sleep 30
7878
HTTP_CODE=$(curl -sS -o /tmp/latest.json -w "%{http_code}" "$URL")
7979
if [ "$HTTP_CODE" != "200" ]; then

docs/assets/bench-charts.js

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
/* lockfreequeues bench charts — uPlot wiring for docs/benchmarks.md.
22
*
33
* Loads the merged Bencher Metric Format (BMF) snapshot from
4-
* `./assets/bench-results/latest.json` (relative path so the same page
5-
* works under /dev/, /latest/, and /v*\/ mike aliases without rewrite),
4+
* `../assets/bench-results/latest.json` — page lives at
5+
* `/<version>/benchmarks/` under mike + mkdocs `use_directory_urls`,
6+
* so we go up one level to reach `/<version>/assets/`. The same
7+
* relative path works under /dev/, /latest/, and /v*\/ aliases,
68
* groups slugs by library, and renders a single uPlot line chart of
79
* throughput_ops_ms across (P,C) shapes. The X axis is the producer/
810
* consumer-count index; the Y axis is throughput in ops/ms with an
@@ -27,7 +29,7 @@
2729
(function () {
2830
'use strict';
2931

30-
const SNAPSHOT_URL = './assets/bench-results/latest.json';
32+
const SNAPSHOT_URL = '../assets/bench-results/latest.json';
3133
const CHART_MEASURE = 'throughput_ops_ms';
3234

3335
// Stable colour palette (uPlot has no default cycle for many series).
@@ -269,10 +271,17 @@
269271
};
270272
}
271273

272-
function attachResizeObserver(host, plot) {
274+
/* Single persistent ResizeObserver — `getPlot` is a closure that
275+
* always returns the *current* uPlot instance, so the toggle's
276+
* rebuild() can destroy + replace `plot` without re-attaching the
277+
* observer. Re-attaching on every rebuild leaks an observer +
278+
* orphaned setSize callbacks per toggle.
279+
*/
280+
function attachResizeObserver(host, getPlot) {
273281
if (typeof ResizeObserver === 'undefined') return;
274282
const ro = new ResizeObserver(() => {
275-
plot.setSize({ width: host.clientWidth, height: 420 });
283+
const plot = getPlot();
284+
if (plot) plot.setSize({ width: host.clientWidth, height: 420 });
276285
});
277286
ro.observe(host);
278287
}
@@ -331,13 +340,17 @@
331340
const data = toUplotData(xLabels, libraries);
332341

333342
const rebuild = () => {
343+
// Drop the previous uPlot instance before mounting the next.
344+
// Without destroy() the toggle accumulates uPlot DOM/listeners
345+
// per click; the observer attaches once below and re-resolves
346+
// `plot` via the closure on each setSize.
347+
if (plot) plot.destroy();
334348
plotMount.innerHTML = '';
335349
plot = new window.uPlot(
336350
makeOpts(plotMount, libraries, xLabels, logScale),
337351
data,
338352
plotMount
339353
);
340-
attachResizeObserver(plotMount, plot);
341354
};
342355

343356
const controls = buildControls(logScale, (next) => {
@@ -356,6 +369,12 @@
356369
host.appendChild(plotMount);
357370
host.appendChild(legend);
358371
rebuild();
372+
373+
// Attach the ResizeObserver once, after plotMount is mounted and
374+
// sized. The closure resolves `plot` on each callback so a later
375+
// rebuild() (log-scale toggle) just hands the observer a new
376+
// instance — no observer churn.
377+
attachResizeObserver(plotMount, () => plot);
359378
}
360379

361380
if (document.readyState === 'loading') {

docs/benchmarks.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,12 @@ underlying measure carries one.
6363
<div id="bench-chart">
6464
<noscript>
6565
Charts require JavaScript. The raw data is published at
66-
<code>./assets/bench-results/latest.json</code>; download the JSON
66+
<code>../assets/bench-results/latest.json</code>; download the JSON
6767
snapshot if you need to consume it programmatically.
6868
</noscript>
6969
</div>
70-
<script src="./assets/uplot-1.6.27.iife.min.js"></script>
71-
<script src="./assets/bench-charts.js"></script>
70+
<script src="../assets/uplot-1.6.27.iife.min.js"></script>
71+
<script src="../assets/bench-charts.js"></script>
7272
</div>
7373

7474
### Methodology and fairness caveats

0 commit comments

Comments
 (0)