You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
demo(benchmark-react): report ops/s instead of ms (#3808)
* demo(benchmark-react): report ops/s instead of ms for CI consistency
The Node benchmark (benchmark.yml) reports ops/sec via Benchmark.js,
while the React benchmark reported milliseconds. Switch to ops/s
(1000/ms) with customBiggerIsBetter so both benchmark graphs use
the same units. Non-duration metrics (ref-stability counts, heap
bytes) are unchanged.
Made-with: Cursor
* demo(benchmark-react): parameterize list-detail-switch navigations
Rename list-detail-switch → list-detail-switch-10 to include the
navigation count in the scenario name. Refactor listDetailSwitch()
to accept (navigations, seedCount) instead of a single n that was
used for both seeding and a hardcoded loop. Add machine specs after
the results table.
Made-with: Cursor
* docs: Add specs to bench table
* demo(benchmark-react): exclude ref-stability from CI runs
Ref-stability scenarios emit `count` (lower is better) which is
incompatible with the customBiggerIsBetter CI tool, causing silent
missed regressions. Exclude deterministic scenarios from CI; they
remain available for local comparison runs.
Made-with: Cursor
* bugbot
* enhance: Better design
Copy file name to clipboardExpand all lines: .cursor/rules/benchmarking.mdc
+1-1Lines changed: 1 addition & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -17,7 +17,7 @@ When working on **`packages/react`** or comparing data-client to other React dat
17
17
- **Where it lives**: `examples/benchmark-react/`
18
18
- **How to run**: From repo root: `yarn build:benchmark-react`, then `yarn workspace example-benchmark-react preview &` and in another terminal `cd examples/benchmark-react && yarn bench`
19
19
- **What it measures**: Browser-based init/update duration, ref-stability counts, sorted-view (Query memoization), optional memory (heap delta), startup metrics (FCP/TBT), and React Profiler commit times. Compares data-client, TanStack Query, and SWR.
20
-
- **CI**: `.github/workflows/benchmark-react.yml` runs on changes to `packages/react/src/**`, `packages/core/src/**`, `packages/endpoint/src/schemas/**`, `packages/normalizr/src/**`, or `examples/benchmark-react/**` and reports via `rhysd/github-action-benchmark` (customSmallerIsBetter). CI runs **data-client only** (hot-path scenarios) to track regressions; competitor libraries (TanStack Query, SWR) are for local comparison only.
20
+
- **CI**: `.github/workflows/benchmark-react.yml` runs on changes to `packages/react/src/**`, `packages/core/src/**`, `packages/endpoint/src/schemas/**`, `packages/normalizr/src/**`, or `examples/benchmark-react/**` and reports via `rhysd/github-action-benchmark` (customBiggerIsBetter). CI runs **data-client only** (hot-path scenarios) to track regressions; competitor libraries (TanStack Query, SWR) are for local comparison only.
21
21
- **Report viewer**: Open `examples/benchmark-react/bench/report-viewer.html` in a browser and paste `react-bench-output.json` to view a comparison table and charts. Toggle "React commit" and "Trace" filters. Use "Load history" for time-series.
22
22
23
23
See `@examples/benchmark-react/README.md` for methodology, adding a new library, and interpreting results.
Copy file name to clipboardExpand all lines: examples/benchmark-react/README.md
+21-19Lines changed: 21 additions & 19 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -27,9 +27,9 @@ The repo has two benchmark suites:
27
27
28
28
**Hot path (CI)**
29
29
30
-
-**Get list** (`getlist-100`, `getlist-500`) — Time to show a ListView component that auto-fetches 100 or 500 issues from the list endpoint, then renders (unit: ms). Exercises the full fetch + normalization + render pipeline.
30
+
-**Get list** (`getlist-100`, `getlist-500`) — Time to show a ListView component that auto-fetches 100 or 500 issues from the list endpoint, then renders (unit: ops/s). Exercises the full fetch + normalization + render pipeline.
31
31
-**Get list sorted** (`getlist-500-sorted`) — Mount 500 issues through a sorted/derived view. data-client uses `useQuery(sortedIssuesQuery)` with `Query` schema memoization; competitors use `useMemo` + sort.
32
-
-**Update entity** (`update-entity`) — Time to update one issue and propagate to the UI (unit: ms).
32
+
-**Update entity** (`update-entity`) — Time to update one issue and propagate to the UI (unit: ops/s).
33
33
-**Update entity sorted** (`update-entity-sorted`) — After mounting a sorted view, update one entity. data-client's `Query` memoization avoids re-sorting when sort keys are unchanged.
34
34
-**Update entity multi-view** (`update-entity-multi-view`) — Update one issue that appears simultaneously in a list, a detail panel, and a pinned-cards strip. Exercises cross-query entity propagation: normalized cache updates once and all three views reflect the change; non-normalized libraries must invalidate and refetch each query independently.
35
35
-**Update user (scaling)** (`update-user`, `update-user-10000`) — Update one shared user with 1,000 or 10,000 mounted issues to test subscriber scaling. Normalized cache: one store update, all views of that user update.
@@ -51,12 +51,12 @@ The repo has two benchmark suites:
51
51
52
52
## Expected results
53
53
54
-
Illustrative **relative** results with **SWR = 100%** (baseline). For **duration** rows, each value is (library median ms ÷ SWR median ms) × 100 — **lower is faster**. For **ref-stability** rows, the same idea uses the “refs changed” count — **lower is fewer components that saw a new object reference**. Figures are rounded from the **Latest measured results** table below (network simulation on); absolute milliseconds will vary by machine, but **library-to-library ratios** are usually similar.
54
+
Illustrative **relative** results with **SWR = 100%** (baseline). For **duration** rows, each value is (library wall-clock time ÷ SWR wall-clock time) × 100 — **lower is faster**. For **ref-stability** rows, the same idea uses the “refs changed” count — **lower is fewer components that saw a new object reference**. Figures are rounded from the **Latest measured results** table below (network simulation on); absolute ops/s will vary by machine, but **library-to-library ratios** are usually similar.
[Measured on a Ryzen 9 7950X; 64 GB RAM; Ubuntu (WSL2); Node 24.12.0; Chromium (Playwright)]
84
86
85
87
## Expected variance
86
88
@@ -94,7 +96,7 @@ Regressions >5% on stable scenarios or >15% on volatile scenarios are worth inve
94
96
95
97
## Interpreting results
96
98
97
-
-**Lower is better** for duration (ms), ref-stability counts, and heap delta (bytes).
99
+
-**Higher is better** for throughput (ops/s). **Lower is better** for ref-stability counts and heap delta (bytes).
98
100
-**Ref-stability:** data-client's normalized cache keeps referential equality for unchanged entities, so `issueRefChanged` and `userRefChanged` should stay low. Non-normalized libs typically show higher counts because they create new object references for every cache write.
99
101
-**React commit:** Reported as `(react commit)` suffix entries. These measure React Profiler `actualDuration` and isolate React reconciliation cost from layout/paint.
100
102
-**Report viewer:** Toggle the "Base metrics", "React commit", and "Trace" checkboxes to filter the comparison table. Use "Load history" to compare multiple runs over time.
@@ -186,14 +188,14 @@ Regressions >5% on stable scenarios or >15% on volatile scenarios are worth inve
186
188
Scenarios are classified as `small` or `large` based on their cost:
-**Memory** (opt-in, 1 warmup + 3 measurement): `memory-mount-unmount-cycle` — run with `--action memory`
191
193
192
194
When running all scenarios (`yarn bench`), each group runs with its own warmup/measurement count. Use `--size` to run only one group.
193
195
194
196
## Output
195
197
196
-
The runner prints a JSON array in `customSmallerIsBetter` format (name, unit, value, range) to stdout. In CI this is written to `react-bench-output.json` and sent to the benchmark action.
198
+
The runner prints a JSON array in `customBiggerIsBetter` format (name, unit, value, range) to stdout. In CI this is written to `react-bench-output.json` and sent to the benchmark action.
197
199
198
200
To view results locally, open `bench/report-viewer.html` in a browser and paste the JSON (or upload `react-bench-output.json`) to see a comparison table and bar chart.
Copy file name to clipboardExpand all lines: examples/benchmark-react/src/shared/types.ts
+2-2Lines changed: 2 additions & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -43,8 +43,8 @@ export interface BenchAPI {
43
43
initDoubleList?(count: number): void;
44
44
/** Move an issue from one state-filtered list to another. Exercises Collection.move (data-client) vs invalidate+refetch (others). */
45
45
moveItem?(id: number): void;
46
-
/** Switch between sorted list view and individual issue detail views 10 times (20 renders). Exercises normalized cache lookup (data-client) vs per-navigation fetch (others). */
47
-
listDetailSwitch?(count: number): void;
46
+
/** Switch between sorted list view and individual issue detail views. Exercises normalized cache lookup (data-client) vs per-navigation fetch (others). */
0 commit comments