Skip to content

Commit 6d286ac

Browse files
authored
Bench: Restore Default Signals And Amplify Short Metrics (#190)
1 parent 0395d0e commit 6d286ac

16 files changed

Lines changed: 152 additions & 159 deletions

packages/compiler/bench/tachometer/bench-compiler-micros.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -151,12 +151,12 @@ const kitchenSinkTemplate = `<article class="card">
151151
{
152152
const astWalkAST = new TemplateCompiler(kitchenSinkTemplate).compile();
153153

154-
// purpose: Walks a kitchen-sink AST through optimizeAST 5000 times. Merge, hoist, and recurse pass.
155-
performance.mark(startMark('ast-walk-5k'));
156-
for (let i = 0; i < 5_000; i++) {
154+
// purpose: Walks a kitchen-sink AST through optimizeAST 15000 times. Merge, hoist, and recurse pass.
155+
performance.mark(startMark('ast-walk-15k'));
156+
for (let i = 0; i < 15_000; i++) {
157157
TemplateCompiler.optimizeAST(astWalkAST);
158158
}
159-
performance.measure('ast-walk-5k', startMark('ast-walk-5k'));
159+
performance.measure('ast-walk-15k', startMark('ast-walk-15k'));
160160
}
161161

162162
/*******************************

packages/compiler/bench/tachometer/tachometer-ci-compiler-micros.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"measurement": [
1313
{ "mode": "performance", "entryName": "parse-cold-normal-500" },
1414
{ "mode": "performance", "entryName": "parse-cold-complex-200" },
15-
{ "mode": "performance", "entryName": "ast-walk-5k" },
15+
{ "mode": "performance", "entryName": "ast-walk-15k" },
1616
{ "mode": "performance", "entryName": "snippet-args-5k" }
1717
]
1818
},
@@ -23,7 +23,7 @@
2323
"measurement": [
2424
{ "mode": "performance", "entryName": "parse-cold-normal-500" },
2525
{ "mode": "performance", "entryName": "parse-cold-complex-200" },
26-
{ "mode": "performance", "entryName": "ast-walk-5k" },
26+
{ "mode": "performance", "entryName": "ast-walk-15k" },
2727
{ "mode": "performance", "entryName": "snippet-args-5k" }
2828
]
2929
}

packages/component/bench/tachometer/bench-hydrate.js

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ defineComponent({
3131
</ul>
3232
`,
3333
defaultState: {
34-
items: { value: [], options: { allowClone: false, safety: 'reference' } },
34+
items: [],
3535
},
3636
createComponent({ state }) {
3737
return {
@@ -146,8 +146,8 @@ defineComponent({
146146
</ul>
147147
`,
148148
defaultState: {
149-
activeID: { value: null, options: { allowClone: false, safety: 'reference' } },
150-
items: { value: [], options: { allowClone: false, safety: 'reference' } },
149+
activeID: null,
150+
items: [],
151151
},
152152
createComponent({ self, state }) {
153153
return {
@@ -201,14 +201,15 @@ const elHelper = container.firstElementChild;
201201
// Mutating a state signal that per-item helpers close over fires
202202
// helper invocations + setAttribute calls. Confirms per-item Reactions
203203
// wired at hydrate are reactive to external state, not just to
204-
// itemSignal mutations. 10 cycles amplifies the work above the σ-floor.
205-
// purpose: Cycles the shared activeID through 10 different items in a hydrated 1000-item list so two items repaint per cycle.
206-
performance.mark(startMark('helper-100-state-change'));
207-
for (let i = 0; i < 10; i++) {
208-
elHelper.component.setActive(`id-${i * 100}`);
204+
// itemSignal mutations. 1000 cycles walking every item once so the
205+
// per-cycle two-item repaint pattern accumulates measurable work.
206+
// purpose: Walks the shared activeID across every item in a hydrated 1000-item list so two items repaint per cycle.
207+
performance.mark(startMark('helper-100-state-change-1k'));
208+
for (let i = 0; i < 1000; i++) {
209+
elHelper.component.setActive(`id-${i}`);
209210
flushWork();
210211
}
211-
performance.measure('helper-100-state-change', startMark('helper-100-state-change'));
212+
performance.measure('helper-100-state-change-1k', startMark('helper-100-state-change-1k'));
212213
container.innerHTML = '';
213214

214215
/*******************************

packages/component/bench/tachometer/bench-krausest.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -268,13 +268,13 @@ destroy();
268268
const el5 = await mount();
269269
el5.component.run(1000);
270270
await flush();
271-
// purpose: Updates the label on every tenth row of a 1000-row table, looped ten times to lift the work above noise.
272-
performance.mark(startMark('update-10th-10'));
273-
for (let i = 0; i < 10; i++) {
271+
// purpose: Updates the label on every tenth row of a 1000-row table, looped 50 times to lift the work above noise.
272+
performance.mark(startMark('update-10th-50'));
273+
for (let i = 0; i < 50; i++) {
274274
el5.component.update();
275275
flushWork();
276276
}
277-
performance.measure('update-10th-10', startMark('update-10th-10'));
277+
performance.measure('update-10th-50', startMark('update-10th-50'));
278278
destroy();
279279

280280
/*******************************
@@ -355,14 +355,14 @@ destroy();
355355
const el10 = await mount();
356356
el10.component.run(1000);
357357
await flush();
358-
// purpose: Removes the last row 10 times from a 1000-row table, with no other rows needing to move.
359-
performance.mark(startMark('remove-row-back-10'));
360-
for (let i = 0; i < 10; i++) {
358+
// purpose: Removes the last row 100 times from a 1000-row table, with no other rows needing to move.
359+
performance.mark(startMark('remove-row-back-100'));
360+
for (let i = 0; i < 100; i++) {
361361
const rows = getRows(el10);
362362
el10.component.removeRow(rows[rows.length - 1].id);
363363
flushWork();
364364
}
365-
performance.measure('remove-row-back-10', startMark('remove-row-back-10'));
365+
performance.measure('remove-row-back-100', startMark('remove-row-back-100'));
366366
destroy();
367367

368368
/*******************************

packages/component/bench/tachometer/bench-template.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -438,13 +438,13 @@ destroy();
438438
*******************************/
439439

440440
const el8 = await mount('bench-snippet-in-subtemplate');
441-
// purpose: Mutates one subtemplate prop's source across 25 cards each invoking 4 inner snippets. Snippet bodies should stay quiet.
442-
performance.mark(startMark('snippet-in-subtemplate-100'));
443-
for (let i = 0; i < 50; i++) {
441+
// purpose: Mutates one subtemplate prop's source across 25 cards each invoking 4 inner snippets, 1000 cycles. Snippet bodies should stay quiet.
442+
performance.mark(startMark('snippet-in-subtemplate-100x1k'));
443+
for (let i = 0; i < 1000; i++) {
444444
el8.template.state.titleVal.set(`v${i}`);
445445
flushWork();
446446
}
447-
performance.measure('snippet-in-subtemplate-100', startMark('snippet-in-subtemplate-100'));
447+
performance.measure('snippet-in-subtemplate-100x1k', startMark('snippet-in-subtemplate-100x1k'));
448448
destroy();
449449

450450
/*******************************

packages/component/bench/tachometer/bench-todo.js

Lines changed: 64 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -63,14 +63,7 @@ defineComponent({
6363
`,
6464
subTemplates: { todoItem },
6565
defaultState: {
66-
// Pinned to safety: 'reference' so the bench tracks the reference fast
67-
// path regardless of Signal.defaultSafety. Dual-key shape (allowClone +
68-
// safety) keeps the in-flight signal-API refactor compatible without
69-
// touching the bench. Mutations use the SUI-canonical helpers below
70-
// (push/replaceItem/removeItem/setProperty/filter/setArrayProperty),
71-
// which bypass equality or produce new refs — no equalityFunction
72-
// override needed.
73-
todos: { value: [], options: { allowClone: false, safety: 'reference' } },
66+
todos: [],
7467
filter: 'all',
7568
editingId: null,
7669
},
@@ -237,39 +230,39 @@ destroy();
237230
(one user click)
238231
*******************************/
239232

240-
// 10× loop per index; same id every iter so signal alternates true/false.
241-
// Metric averages toggle-on + toggle-off cost — if those diverge (class
242-
// adds vs removes may do different DOM work), the number mixes two
243-
// workloads. Both legs run every iter so regression detection is sound,
244-
// but this is not a pure "single toggle" measurement.
233+
// Same id every iter so the signal alternates true/false; metric averages
234+
// toggle-on + toggle-off cost — if those diverge (class adds vs removes
235+
// may do different DOM work), the number mixes two workloads. Both legs
236+
// run every iter so regression detection is sound, but this is not a
237+
// pure "single toggle" measurement.
245238
const el4 = await setup(100);
246-
// purpose: Toggles the first item in a 100-item list ten times, alternating completed on and off.
247-
performance.mark(startMark('toggle-first-10'));
248-
for (let i = 0; i < 10; i++) {
239+
// purpose: Toggles the first item in a 100-item list 100 times, alternating completed on and off.
240+
performance.mark(startMark('toggle-first-100'));
241+
for (let i = 0; i < 100; i++) {
249242
el4.component.toggleTodo(getTodos(el4)[0].id);
250243
flushWork();
251244
}
252-
performance.measure('toggle-first-10', startMark('toggle-first-10'));
245+
performance.measure('toggle-first-100', startMark('toggle-first-100'));
253246
destroy();
254247

255248
const el5 = await setup(100);
256-
// purpose: Toggles the last item in a 100-item list ten times, alternating completed on and off.
257-
performance.mark(startMark('toggle-last-10'));
258-
for (let i = 0; i < 10; i++) {
249+
// purpose: Toggles the last item in a 100-item list 100 times, alternating completed on and off.
250+
performance.mark(startMark('toggle-last-100'));
251+
for (let i = 0; i < 100; i++) {
259252
el5.component.toggleTodo(getTodos(el5)[99].id);
260253
flushWork();
261254
}
262-
performance.measure('toggle-last-10', startMark('toggle-last-10'));
255+
performance.measure('toggle-last-100', startMark('toggle-last-100'));
263256
destroy();
264257

265258
const el6 = await setup(100);
266-
// purpose: Toggles a middle item in a 100-item list ten times, alternating completed on and off.
267-
performance.mark(startMark('toggle-middle-10'));
268-
for (let i = 0; i < 10; i++) {
259+
// purpose: Toggles a middle item in a 100-item list 100 times, alternating completed on and off.
260+
performance.mark(startMark('toggle-middle-100'));
261+
for (let i = 0; i < 100; i++) {
269262
el6.component.toggleTodo(getTodos(el6)[49].id);
270263
flushWork();
271264
}
272-
performance.measure('toggle-middle-10', startMark('toggle-middle-10'));
265+
performance.measure('toggle-middle-100', startMark('toggle-middle-100'));
273266
destroy();
274267

275268
/*******************************
@@ -278,107 +271,106 @@ destroy();
278271
*******************************/
279272

280273
const el7 = await setup(100);
281-
// purpose: Checks off the first 10 items one by one, like a user working down a list.
282-
performance.mark(startMark('toggle-10'));
283-
for (let i = 0; i < 10; i++) {
284-
el7.component.toggleTodo(getTodos(el7)[i].id);
274+
// purpose: Cycles through the first 10 items 10 times each, like a user toggling items repeatedly down a list.
275+
performance.mark(startMark('toggle-100'));
276+
for (let i = 0; i < 100; i++) {
277+
el7.component.toggleTodo(getTodos(el7)[i % 10].id);
285278
flushWork();
286279
}
287-
performance.measure('toggle-10', startMark('toggle-10'));
280+
performance.measure('toggle-100', startMark('toggle-100'));
288281
destroy();
289282

290283
/*******************************
291284
Bulk Updates
292285
(one user action, all items)
293286
*******************************/
294287

295-
// 20 alternating toggle-all invocations on a 100-item list — amplified
296-
// so the measurement clears the σ≈2ms per-sample noise floor on CI.
288+
// 200 alternating toggle-all invocations on a 100-item list. Each call
289+
// touches every item, so the 200× sustains a measurable workload above
290+
// the σ≈2ms per-sample noise floor on CI.
297291
const el8 = await setup(100);
298-
// purpose: Toggles all 100 items completed and back across 20 cycles via the master checkbox.
299-
performance.mark(startMark('toggle-all-20'));
300-
for (let i = 0; i < 20; i++) {
292+
// purpose: Toggles all 100 items completed and back across 200 cycles via the master checkbox.
293+
performance.mark(startMark('toggle-all-200'));
294+
for (let i = 0; i < 200; i++) {
301295
el8.component.toggleAll();
302296
flushWork();
303297
}
304-
performance.measure('toggle-all-20', startMark('toggle-all-20'));
298+
performance.measure('toggle-all-200', startMark('toggle-all-200'));
305299
destroy();
306300

307301
/*******************************
308302
Single Removal
309303
*******************************/
310304

311-
// 10× loop per position; re-fetch each iter since the list shrinks.
312-
// Each position's ~10ms per-delete workload clears the σ≈2ms floor.
313-
const el9 = await setup(100);
314-
// purpose: Deletes the first item 10 times from a 100-item list, with remaining items moving up each time.
315-
performance.mark(startMark('remove-first-10'));
316-
for (let i = 0; i < 10; i++) {
305+
// 100× loop per position on a 200-item list — re-fetch each iter since
306+
// the list shrinks. Setup of 200 leaves comfortable headroom past the
307+
// 100-iter loop (list ends at 100 items, never empty).
308+
const el9 = await setup(200);
309+
// purpose: Deletes the first item 100 times from a 200-item list, with remaining items moving up each time.
310+
performance.mark(startMark('remove-first-100'));
311+
for (let i = 0; i < 100; i++) {
317312
el9.component.deleteTodo(getTodos(el9)[0].id);
318313
flushWork();
319314
}
320-
performance.measure('remove-first-10', startMark('remove-first-10'));
315+
performance.measure('remove-first-100', startMark('remove-first-100'));
321316
destroy();
322317

323-
const el10 = await setup(100);
324-
// purpose: Deletes the middle item 10 times from a 100-item list, walking halfway through to find each target.
325-
performance.mark(startMark('remove-middle-10'));
326-
for (let i = 0; i < 10; i++) {
318+
const el10 = await setup(200);
319+
// purpose: Deletes the middle item 100 times from a 200-item list, walking halfway through to find each target.
320+
performance.mark(startMark('remove-middle-100'));
321+
for (let i = 0; i < 100; i++) {
327322
const todos = getTodos(el10);
328323
el10.component.deleteTodo(todos[Math.floor(todos.length / 2)].id);
329324
flushWork();
330325
}
331-
performance.measure('remove-middle-10', startMark('remove-middle-10'));
326+
performance.measure('remove-middle-100', startMark('remove-middle-100'));
332327
destroy();
333328

334-
const el10b = await setup(100);
335-
// purpose: Deletes the last item 10 times from a 100-item list, with no other items needing to move.
336-
performance.mark(startMark('remove-last-10'));
337-
for (let i = 0; i < 10; i++) {
329+
const el10b = await setup(200);
330+
// purpose: Deletes the last item 100 times from a 200-item list, with no other items needing to move.
331+
performance.mark(startMark('remove-last-100'));
332+
for (let i = 0; i < 100; i++) {
338333
const todos = getTodos(el10b);
339334
el10b.component.deleteTodo(todos[todos.length - 1].id);
340335
flushWork();
341336
}
342-
performance.measure('remove-last-10', startMark('remove-last-10'));
337+
performance.measure('remove-last-100', startMark('remove-last-100'));
343338
destroy();
344339

345340
/*******************************
346341
Incremental Removal
347342
*******************************/
348343

349344
const el11 = await setup(100);
350-
// purpose: Deletes 5 items from the front of a 100-item list, one click at a time.
351-
performance.mark(startMark('remove-5-front'));
352-
for (let i = 0; i < 5; i++) {
345+
// purpose: Deletes 50 items from the front of a 100-item list, one click at a time.
346+
performance.mark(startMark('remove-50-front'));
347+
for (let i = 0; i < 50; i++) {
353348
el11.component.deleteTodo(getTodos(el11)[0].id);
354349
flushWork();
355350
}
356-
performance.measure('remove-5-front', startMark('remove-5-front'));
351+
performance.measure('remove-50-front', startMark('remove-50-front'));
357352
destroy();
358353

359-
// 10× loop (vs 5× for the front/back variants) — middle removal's
360-
// O(N/2) scan has wider per-sample variance, so 5× landed at ~74ms
361-
// with observed CI straddling ±2%. 10× brings it to ~148ms / ±1%.
362354
const el11b = await setup(100);
363-
// purpose: Deletes 10 items from the middle of a 100-item list, one click at a time.
364-
performance.mark(startMark('remove-10-middle'));
365-
for (let i = 0; i < 10; i++) {
355+
// purpose: Deletes 50 items from the middle of a 100-item list, one click at a time.
356+
performance.mark(startMark('remove-50-middle'));
357+
for (let i = 0; i < 50; i++) {
366358
const todos = getTodos(el11b);
367359
el11b.component.deleteTodo(todos[Math.floor(todos.length / 2)].id);
368360
flushWork();
369361
}
370-
performance.measure('remove-10-middle', startMark('remove-10-middle'));
362+
performance.measure('remove-50-middle', startMark('remove-50-middle'));
371363
destroy();
372364

373365
const el11c = await setup(100);
374-
// purpose: Deletes 5 items from the end of a 100-item list, one click at a time.
375-
performance.mark(startMark('remove-5-back'));
376-
for (let i = 0; i < 5; i++) {
366+
// purpose: Deletes 50 items from the end of a 100-item list, one click at a time.
367+
performance.mark(startMark('remove-50-back'));
368+
for (let i = 0; i < 50; i++) {
377369
const todos = getTodos(el11c);
378370
el11c.component.deleteTodo(todos[todos.length - 1].id);
379371
flushWork();
380372
}
381-
performance.measure('remove-5-back', startMark('remove-5-back'));
373+
performance.measure('remove-50-back', startMark('remove-50-back'));
382374
destroy();
383375

384376
/*******************************
@@ -462,14 +454,14 @@ destroy();
462454
// `toggle-*` (which uses replaceItem) and `edit-cycle-5` (which mixes
463455
// in an editingId flip per cycle).
464456
const el16 = await setup(100);
465-
// purpose: Renames 50 different items in a 100-item list via single-field setProperty without editingId co-fires.
466-
performance.mark(startMark('rename-50'));
467-
for (let i = 0; i < 50; i++) {
457+
// purpose: Renames items in a 100-item list 500 times via single-field setProperty without editingId co-fires.
458+
performance.mark(startMark('rename-500'));
459+
for (let i = 0; i < 500; i++) {
468460
const todos = getTodos(el16);
469461
el16.component.renameTodo(todos[i % todos.length].id, `Renamed ${i}`);
470462
flushWork();
471463
}
472-
performance.measure('rename-50', startMark('rename-50'));
464+
performance.measure('rename-500', startMark('rename-500'));
473465
destroy();
474466

475467
/*******************************

packages/component/bench/tachometer/tachometer-ci-hydrate.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
{ "mode": "performance", "entryName": "each-100-mount" },
1414
{ "mode": "performance", "entryName": "each-100" },
1515
{ "mode": "performance", "entryName": "helper-100-mount" },
16-
{ "mode": "performance", "entryName": "helper-100-state-change" }
16+
{ "mode": "performance", "entryName": "helper-100-state-change-1k" }
1717
]
1818
},
1919
{
@@ -24,7 +24,7 @@
2424
{ "mode": "performance", "entryName": "each-100-mount" },
2525
{ "mode": "performance", "entryName": "each-100" },
2626
{ "mode": "performance", "entryName": "helper-100-mount" },
27-
{ "mode": "performance", "entryName": "helper-100-state-change" }
27+
{ "mode": "performance", "entryName": "helper-100-state-change-1k" }
2828
]
2929
}
3030
]

0 commit comments

Comments
 (0)