Skip to content

Commit e432527

Browse files
committed
create adds to list; larger high end case
1 parent e724439 commit e432527

File tree

9 files changed

+78
-81
lines changed

9 files changed

+78
-81
lines changed

examples/benchmark-react/bench/runner.ts

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,16 @@ async function main() {
253253
const browser = await chromium.launch({ headless: true });
254254
const libraries = process.env.CI ? ['data-client'] : [...LIBRARIES];
255255

256+
const scenarioCount = SCENARIOS_TO_RUN.length;
256257
for (let round = 0; round < TOTAL_RUNS; round++) {
258+
const phase = round < WARMUP_RUNS ? 'warmup' : 'measure';
259+
const phaseRound =
260+
round < WARMUP_RUNS ? round + 1 : round - WARMUP_RUNS + 1;
261+
const phaseTotal = round < WARMUP_RUNS ? WARMUP_RUNS : MEASUREMENT_RUNS;
262+
process.stderr.write(
263+
`\n── Round ${round + 1}/${TOTAL_RUNS} (${phase} ${phaseRound}/${phaseTotal}) ──\n`,
264+
);
265+
let scenarioDone = 0;
257266
for (const lib of shuffle(libraries)) {
258267
const context = await browser.newContext();
259268
const page = await context.newPage();
@@ -265,9 +274,22 @@ async function main() {
265274
results[scenario.name].push(result.value);
266275
reactCommitResults[scenario.name].push(result.reactCommit ?? NaN);
267276
traceResults[scenario.name].push(result.traceDuration ?? NaN);
277+
scenarioDone++;
278+
const unit =
279+
scenario.resultMetric === 'heapDelta' ? 'bytes'
280+
: (
281+
scenario.resultMetric === 'itemRefChanged' ||
282+
scenario.resultMetric === 'authorRefChanged'
283+
) ?
284+
'count'
285+
: 'ms';
286+
process.stderr.write(
287+
` [${scenarioDone}/${scenarioCount}] ${scenario.name}: ${result.value.toFixed(2)} ${unit}${result.reactCommit != null ? ` (commit ${result.reactCommit.toFixed(2)} ms)` : ''}\n`,
288+
);
268289
} catch (err) {
290+
scenarioDone++;
269291
console.error(
270-
`Scenario ${scenario.name} failed:`,
292+
` [${scenarioDone}/${scenarioCount}] ${scenario.name} FAILED:`,
271293
err instanceof Error ? err.message : err,
272294
);
273295
}
@@ -285,16 +307,22 @@ async function main() {
285307
}
286308
const STARTUP_RUNS = 5;
287309
for (let round = 0; round < STARTUP_RUNS; round++) {
310+
process.stderr.write(
311+
`\n── Startup round ${round + 1}/${STARTUP_RUNS} ──\n`,
312+
);
288313
for (const lib of shuffle([...LIBRARIES])) {
289314
const context = await browser.newContext();
290315
const page = await context.newPage();
291316
try {
292317
const m = await runStartupScenario(page, lib);
293318
startupResults[lib].fcp.push(m.fcp * 1000);
294319
startupResults[lib].tbt.push(m.taskDuration * 1000);
320+
process.stderr.write(
321+
` ${lib}: fcp ${(m.fcp * 1000).toFixed(2)} ms, task ${(m.taskDuration * 1000).toFixed(2)} ms\n`,
322+
);
295323
} catch (err) {
296324
console.error(
297-
`Startup ${lib} failed:`,
325+
` ${lib} startup FAILED:`,
298326
err instanceof Error ? err.message : err,
299327
);
300328
}
@@ -397,6 +425,13 @@ async function main() {
397425
entry.name += BENCH_LABEL;
398426
}
399427
}
428+
process.stderr.write(`\n── Results (${report.length} metrics) ──\n`);
429+
for (const entry of report) {
430+
process.stderr.write(
431+
` ${entry.name}: ${entry.value} ${entry.unit} ${entry.range}\n`,
432+
);
433+
}
434+
process.stderr.write('\n');
400435
process.stdout.write(formatReport(report));
401436
}
402437

examples/benchmark-react/bench/scenarios.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,11 +139,11 @@ const BASE_SCENARIOS: BaseScenario[] = [
139139
preMountAction: 'mountSortedView',
140140
},
141141
{
142-
nameSuffix: 'update-shared-author-10000-mounted',
142+
nameSuffix: 'update-shared-author-2000-mounted',
143143
action: 'updateAuthor',
144144
args: ['author-0'],
145145
category: 'hotPath',
146-
mountCount: 10000,
146+
mountCount: 2000,
147147
},
148148
{
149149
nameSuffix: 'invalidate-and-resolve',

examples/benchmark-react/src/baseline/index.tsx

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {
33
useBenchState,
44
waitForPaint,
55
} from '@shared/benchHarness';
6-
import { ITEM_HEIGHT, ItemRow, LIST_STYLE } from '@shared/components';
6+
import { ITEM_HEIGHT, ItemRow, ItemsRow, LIST_STYLE } from '@shared/components';
77
import {
88
FIXTURE_AUTHORS,
99
FIXTURE_AUTHORS_BY_ID,
@@ -40,18 +40,6 @@ function ItemView({ id }: { id: string }) {
4040
return <ItemRow item={item} />;
4141
}
4242

43-
function SortedRow({
44-
index,
45-
style,
46-
items,
47-
}: RowComponentProps<{ items: Item[] }>) {
48-
return (
49-
<div style={style}>
50-
<ItemRow item={items[index]} />
51-
</div>
52-
);
53-
}
54-
5543
function SortedListView() {
5644
const { items } = useContext(ItemsContext);
5745
const sorted = useMemo(() => sortByLabel(items), [items]);
@@ -61,7 +49,7 @@ function SortedListView() {
6149
style={LIST_STYLE}
6250
rowHeight={ITEM_HEIGHT}
6351
rowCount={sorted.length}
64-
rowComponent={SortedRow}
52+
rowComponent={ItemsRow}
6553
rowProps={{ items: sorted }}
6654
/>
6755
</div>
@@ -147,8 +135,8 @@ function BenchmarkHarness() {
147135
const author = FIXTURE_AUTHORS[0];
148136
measureUpdate(() => {
149137
createItem({ label: 'New Item', author }).then(created => {
150-
setItems(prev => [...prev, created]);
151-
setIds(prev => [...prev, created.id]);
138+
setItems(prev => [created, ...prev]);
139+
setIds(prev => [created.id, ...prev]);
152140
});
153141
});
154142
}, [measureUpdate, setIds]);

examples/benchmark-react/src/data-client/index.tsx

Lines changed: 4 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
} from '@data-client/react';
77
import { mockInitialState } from '@data-client/react/mock';
88
import { onProfilerRender, useBenchState } from '@shared/benchHarness';
9-
import { ITEM_HEIGHT, ItemRow, LIST_STYLE } from '@shared/components';
9+
import { ITEM_HEIGHT, ItemRow, ItemsRow, LIST_STYLE } from '@shared/components';
1010
import {
1111
FIXTURE_AUTHORS,
1212
FIXTURE_AUTHORS_BY_ID,
@@ -54,18 +54,6 @@ function ItemView({ id }: { id: string }) {
5454
return <ItemRow item={item as Item} />;
5555
}
5656

57-
function ListViewRow({
58-
index,
59-
style,
60-
items,
61-
}: RowComponentProps<{ items: Item[] }>) {
62-
return (
63-
<div style={style}>
64-
<ItemRow item={items[index]} />
65-
</div>
66-
);
67-
}
68-
6957
/** Renders items from the list endpoint (models rendering a list fetch response). */
7058
function ListView() {
7159
const items = useCache(getItemList);
@@ -76,24 +64,12 @@ function ListView() {
7664
style={LIST_STYLE}
7765
rowHeight={ITEM_HEIGHT}
7866
rowCount={list.length}
79-
rowComponent={ListViewRow}
67+
rowComponent={ItemsRow}
8068
rowProps={{ items: list }}
8169
/>
8270
);
8371
}
8472

85-
function SortedRow({
86-
index,
87-
style,
88-
items,
89-
}: RowComponentProps<{ items: Item[] }>) {
90-
return (
91-
<div style={style}>
92-
<ItemRow item={items[index]} />
93-
</div>
94-
);
95-
}
96-
9773
/** Renders items sorted by label via Query schema (memoized by MemoCache). */
9874
function SortedListView({ count }: { count?: number }) {
9975
const items = useQuery(sortedItemsQuery, { limit: count });
@@ -104,7 +80,7 @@ function SortedListView({ count }: { count?: number }) {
10480
style={LIST_STYLE}
10581
rowHeight={ITEM_HEIGHT}
10682
rowCount={items.length}
107-
rowComponent={SortedRow}
83+
rowComponent={ItemsRow}
10884
rowProps={{ items: items as Item[] }}
10985
/>
11086
</div>
@@ -178,7 +154,7 @@ function BenchmarkHarness() {
178154
author,
179155
})
180156
.then((created: any) => {
181-
setIds(prev => [...prev, created.id]);
157+
setIds(prev => [created.id, ...prev]);
182158
});
183159
});
184160
}, [measureUpdate, controller, setIds]);

examples/benchmark-react/src/data-client/resources.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
All,
55
Query,
66
Invalidate,
7+
Collection,
78
} from '@data-client/endpoint';
89
import { sortByLabel } from '@shared/data';
910
import {
@@ -58,15 +59,15 @@ export const getItem = new Endpoint(serverFetchItem, {
5859
});
5960

6061
export const getItemList = new Endpoint(serverFetchItemList, {
61-
schema: [ItemEntity],
62+
schema: new Collection([ItemEntity]),
6263
key: () => 'item:list',
6364
dataExpiryLength: Infinity,
6465
});
6566

6667
// ── CREATE ──────────────────────────────────────────────────────────────
6768

6869
export const createItemEndpoint = new Endpoint(serverCreateItem, {
69-
schema: ItemEntity,
70+
schema: getItemList.schema.unshift,
7071
sideEffect: true,
7172
key: () => 'item:create',
7273
});

examples/benchmark-react/src/shared/components.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import React from 'react';
2+
import type { RowComponentProps } from 'react-window';
23

34
import type { Item } from './types';
45

@@ -18,3 +19,16 @@ export function ItemRow({ item }: { item: Item }) {
1819
</div>
1920
);
2021
}
22+
23+
/** Generic react-window row that renders an ItemRow from an items array. */
24+
export function ItemsRow({
25+
index,
26+
style,
27+
items,
28+
}: RowComponentProps<{ items: Item[] }>) {
29+
return (
30+
<div style={style}>
31+
<ItemRow item={items[index]} />
32+
</div>
33+
);
34+
}

examples/benchmark-react/src/shared/server.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ export function createItem(body: {
4545
const item: Item = { id, label: body.label, author: body.author };
4646
const json = JSON.stringify(item);
4747
jsonStore.set(`item:${id}`, json);
48+
// Prepend to item:list so refetching the list returns the new item first
49+
const listJson = jsonStore.get('item:list');
50+
const list: Item[] = listJson ? JSON.parse(listJson) : [];
51+
list.unshift(item);
52+
jsonStore.set('item:list', JSON.stringify(list));
4853
return Promise.resolve(JSON.parse(json));
4954
}
5055

examples/benchmark-react/src/swr/index.tsx

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { onProfilerRender, useBenchState } from '@shared/benchHarness';
2-
import { ITEM_HEIGHT, ItemRow, LIST_STYLE } from '@shared/components';
2+
import { ITEM_HEIGHT, ItemRow, ItemsRow, LIST_STYLE } from '@shared/components';
33
import {
44
FIXTURE_AUTHORS,
55
FIXTURE_AUTHORS_BY_ID,
@@ -61,18 +61,6 @@ function ItemView({ id }: { id: string }) {
6161
return <ItemRow item={item} />;
6262
}
6363

64-
function SortedRow({
65-
index,
66-
style,
67-
items,
68-
}: RowComponentProps<{ items: Item[] }>) {
69-
return (
70-
<div style={style}>
71-
<ItemRow item={items[index]} />
72-
</div>
73-
);
74-
}
75-
7664
function SortedListView() {
7765
const { data: items } = useSWR<Item[]>('items:all', fetcher);
7866
const sorted = useMemo(() => (items ? sortByLabel(items) : []), [items]);
@@ -82,7 +70,7 @@ function SortedListView() {
8270
style={LIST_STYLE}
8371
rowHeight={ITEM_HEIGHT}
8472
rowCount={sorted.length}
85-
rowComponent={SortedRow}
73+
rowComponent={ItemsRow}
8674
rowProps={{ items: sorted }}
8775
/>
8876
</div>
@@ -154,10 +142,11 @@ function BenchmarkHarness() {
154142
measureUpdate(() => {
155143
createItem({ label: 'New Item', author }).then(created => {
156144
cache.set(`item:${created.id}`, makeCacheEntry(created));
157-
setIds(prev => [...prev, created.id]);
145+
void mutate('items:all');
146+
setIds(prev => [created.id, ...prev]);
158147
});
159148
});
160-
}, [measureUpdate, setIds]);
149+
}, [measureUpdate, mutate, setIds]);
161150

162151
const deleteEntity = useCallback(
163152
(id: string) => {

examples/benchmark-react/src/tanstack-query/index.tsx

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { onProfilerRender, useBenchState } from '@shared/benchHarness';
2-
import { ITEM_HEIGHT, ItemRow, LIST_STYLE } from '@shared/components';
2+
import { ITEM_HEIGHT, ItemRow, ItemsRow, LIST_STYLE } from '@shared/components';
33
import {
44
FIXTURE_AUTHORS,
55
FIXTURE_AUTHORS_BY_ID,
@@ -70,18 +70,6 @@ function ItemView({ id }: { id: string }) {
7070
return <ItemRow item={itemAsItem} />;
7171
}
7272

73-
function SortedRow({
74-
index,
75-
style,
76-
items,
77-
}: RowComponentProps<{ items: Item[] }>) {
78-
return (
79-
<div style={style}>
80-
<ItemRow item={items[index]} />
81-
</div>
82-
);
83-
}
84-
8573
function SortedListView() {
8674
const { data: items } = useQuery({
8775
queryKey: ['items', 'all'],
@@ -97,7 +85,7 @@ function SortedListView() {
9785
style={LIST_STYLE}
9886
rowHeight={ITEM_HEIGHT}
9987
rowCount={sorted.length}
100-
rowComponent={SortedRow}
88+
rowComponent={ItemsRow}
10189
rowProps={{ items: sorted }}
10290
/>
10391
</div>
@@ -169,7 +157,8 @@ function BenchmarkHarness() {
169157
measureUpdate(() => {
170158
createItem({ label: 'New Item', author }).then(created => {
171159
client.setQueryData(['item', created.id], created);
172-
setIds(prev => [...prev, created.id]);
160+
void client.invalidateQueries({ queryKey: ['items', 'all'] });
161+
setIds(prev => [created.id, ...prev]);
173162
});
174163
});
175164
}, [measureUpdate, client, setIds]);

0 commit comments

Comments
 (0)