Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions packages/compiler/bench/tachometer/bench-compiler-micros.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,12 +151,12 @@ const kitchenSinkTemplate = `<article class="card">
{
const astWalkAST = new TemplateCompiler(kitchenSinkTemplate).compile();

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

/*******************************
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"measurement": [
{ "mode": "performance", "entryName": "parse-cold-normal-500" },
{ "mode": "performance", "entryName": "parse-cold-complex-200" },
{ "mode": "performance", "entryName": "ast-walk-5k" },
{ "mode": "performance", "entryName": "ast-walk-15k" },
{ "mode": "performance", "entryName": "snippet-args-5k" }
]
},
Expand All @@ -23,7 +23,7 @@
"measurement": [
{ "mode": "performance", "entryName": "parse-cold-normal-500" },
{ "mode": "performance", "entryName": "parse-cold-complex-200" },
{ "mode": "performance", "entryName": "ast-walk-5k" },
{ "mode": "performance", "entryName": "ast-walk-15k" },
{ "mode": "performance", "entryName": "snippet-args-5k" }
]
}
Expand Down
19 changes: 10 additions & 9 deletions packages/component/bench/tachometer/bench-hydrate.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ defineComponent({
</ul>
`,
defaultState: {
items: { value: [], options: { allowClone: false, safety: 'reference' } },
items: [],
},
createComponent({ state }) {
return {
Expand Down Expand Up @@ -146,8 +146,8 @@ defineComponent({
</ul>
`,
defaultState: {
activeID: { value: null, options: { allowClone: false, safety: 'reference' } },
items: { value: [], options: { allowClone: false, safety: 'reference' } },
activeID: null,
items: [],
},
createComponent({ self, state }) {
return {
Expand Down Expand Up @@ -201,14 +201,15 @@ const elHelper = container.firstElementChild;
// Mutating a state signal that per-item helpers close over fires
// helper invocations + setAttribute calls. Confirms per-item Reactions
// wired at hydrate are reactive to external state, not just to
// itemSignal mutations. 10 cycles amplifies the work above the σ-floor.
// purpose: Cycles the shared activeID through 10 different items in a hydrated 1000-item list so two items repaint per cycle.
performance.mark(startMark('helper-100-state-change'));
for (let i = 0; i < 10; i++) {
elHelper.component.setActive(`id-${i * 100}`);
// itemSignal mutations. 1000 cycles walking every item once so the
// per-cycle two-item repaint pattern accumulates measurable work.
// purpose: Walks the shared activeID across every item in a hydrated 1000-item list so two items repaint per cycle.
performance.mark(startMark('helper-100-state-change-1k'));
for (let i = 0; i < 1000; i++) {
elHelper.component.setActive(`id-${i}`);
flushWork();
}
performance.measure('helper-100-state-change', startMark('helper-100-state-change'));
performance.measure('helper-100-state-change-1k', startMark('helper-100-state-change-1k'));
container.innerHTML = '';

/*******************************
Expand Down
16 changes: 8 additions & 8 deletions packages/component/bench/tachometer/bench-krausest.js
Original file line number Diff line number Diff line change
Expand Up @@ -268,13 +268,13 @@ destroy();
const el5 = await mount();
el5.component.run(1000);
await flush();
// purpose: Updates the label on every tenth row of a 1000-row table, looped ten times to lift the work above noise.
performance.mark(startMark('update-10th-10'));
for (let i = 0; i < 10; i++) {
// purpose: Updates the label on every tenth row of a 1000-row table, looped 50 times to lift the work above noise.
performance.mark(startMark('update-10th-50'));
for (let i = 0; i < 50; i++) {
el5.component.update();
flushWork();
}
performance.measure('update-10th-10', startMark('update-10th-10'));
performance.measure('update-10th-50', startMark('update-10th-50'));
destroy();

/*******************************
Expand Down Expand Up @@ -355,14 +355,14 @@ destroy();
const el10 = await mount();
el10.component.run(1000);
await flush();
// purpose: Removes the last row 10 times from a 1000-row table, with no other rows needing to move.
performance.mark(startMark('remove-row-back-10'));
for (let i = 0; i < 10; i++) {
// purpose: Removes the last row 100 times from a 1000-row table, with no other rows needing to move.
performance.mark(startMark('remove-row-back-100'));
for (let i = 0; i < 100; i++) {
const rows = getRows(el10);
el10.component.removeRow(rows[rows.length - 1].id);
flushWork();
}
performance.measure('remove-row-back-10', startMark('remove-row-back-10'));
performance.measure('remove-row-back-100', startMark('remove-row-back-100'));
destroy();

/*******************************
Expand Down
8 changes: 4 additions & 4 deletions packages/component/bench/tachometer/bench-template.js
Original file line number Diff line number Diff line change
Expand Up @@ -438,13 +438,13 @@ destroy();
*******************************/

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

/*******************************
Expand Down
136 changes: 64 additions & 72 deletions packages/component/bench/tachometer/bench-todo.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,7 @@ defineComponent({
`,
subTemplates: { todoItem },
defaultState: {
// Pinned to safety: 'reference' so the bench tracks the reference fast
// path regardless of Signal.defaultSafety. Dual-key shape (allowClone +
// safety) keeps the in-flight signal-API refactor compatible without
// touching the bench. Mutations use the SUI-canonical helpers below
// (push/replaceItem/removeItem/setProperty/filter/setArrayProperty),
// which bypass equality or produce new refs — no equalityFunction
// override needed.
todos: { value: [], options: { allowClone: false, safety: 'reference' } },
todos: [],
filter: 'all',
editingId: null,
},
Expand Down Expand Up @@ -237,39 +230,39 @@ destroy();
(one user click)
*******************************/

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

const el5 = await setup(100);
// purpose: Toggles the last item in a 100-item list ten times, alternating completed on and off.
performance.mark(startMark('toggle-last-10'));
for (let i = 0; i < 10; i++) {
// purpose: Toggles the last item in a 100-item list 100 times, alternating completed on and off.
performance.mark(startMark('toggle-last-100'));
for (let i = 0; i < 100; i++) {
el5.component.toggleTodo(getTodos(el5)[99].id);
flushWork();
}
performance.measure('toggle-last-10', startMark('toggle-last-10'));
performance.measure('toggle-last-100', startMark('toggle-last-100'));
destroy();

const el6 = await setup(100);
// purpose: Toggles a middle item in a 100-item list ten times, alternating completed on and off.
performance.mark(startMark('toggle-middle-10'));
for (let i = 0; i < 10; i++) {
// purpose: Toggles a middle item in a 100-item list 100 times, alternating completed on and off.
performance.mark(startMark('toggle-middle-100'));
for (let i = 0; i < 100; i++) {
el6.component.toggleTodo(getTodos(el6)[49].id);
flushWork();
}
performance.measure('toggle-middle-10', startMark('toggle-middle-10'));
performance.measure('toggle-middle-100', startMark('toggle-middle-100'));
destroy();

/*******************************
Expand All @@ -278,107 +271,106 @@ destroy();
*******************************/

const el7 = await setup(100);
// purpose: Checks off the first 10 items one by one, like a user working down a list.
performance.mark(startMark('toggle-10'));
for (let i = 0; i < 10; i++) {
el7.component.toggleTodo(getTodos(el7)[i].id);
// purpose: Cycles through the first 10 items 10 times each, like a user toggling items repeatedly down a list.
performance.mark(startMark('toggle-100'));
for (let i = 0; i < 100; i++) {
el7.component.toggleTodo(getTodos(el7)[i % 10].id);
flushWork();
}
performance.measure('toggle-10', startMark('toggle-10'));
performance.measure('toggle-100', startMark('toggle-100'));
destroy();

/*******************************
Bulk Updates
(one user action, all items)
*******************************/

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

/*******************************
Single Removal
*******************************/

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

const el10 = await setup(100);
// purpose: Deletes the middle item 10 times from a 100-item list, walking halfway through to find each target.
performance.mark(startMark('remove-middle-10'));
for (let i = 0; i < 10; i++) {
const el10 = await setup(200);
// purpose: Deletes the middle item 100 times from a 200-item list, walking halfway through to find each target.
performance.mark(startMark('remove-middle-100'));
for (let i = 0; i < 100; i++) {
const todos = getTodos(el10);
el10.component.deleteTodo(todos[Math.floor(todos.length / 2)].id);
flushWork();
}
performance.measure('remove-middle-10', startMark('remove-middle-10'));
performance.measure('remove-middle-100', startMark('remove-middle-100'));
destroy();

const el10b = await setup(100);
// purpose: Deletes the last item 10 times from a 100-item list, with no other items needing to move.
performance.mark(startMark('remove-last-10'));
for (let i = 0; i < 10; i++) {
const el10b = await setup(200);
// purpose: Deletes the last item 100 times from a 200-item list, with no other items needing to move.
performance.mark(startMark('remove-last-100'));
for (let i = 0; i < 100; i++) {
const todos = getTodos(el10b);
el10b.component.deleteTodo(todos[todos.length - 1].id);
flushWork();
}
performance.measure('remove-last-10', startMark('remove-last-10'));
performance.measure('remove-last-100', startMark('remove-last-100'));
destroy();

/*******************************
Incremental Removal
*******************************/

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

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

const el11c = await setup(100);
// purpose: Deletes 5 items from the end of a 100-item list, one click at a time.
performance.mark(startMark('remove-5-back'));
for (let i = 0; i < 5; i++) {
// purpose: Deletes 50 items from the end of a 100-item list, one click at a time.
performance.mark(startMark('remove-50-back'));
for (let i = 0; i < 50; i++) {
const todos = getTodos(el11c);
el11c.component.deleteTodo(todos[todos.length - 1].id);
flushWork();
}
performance.measure('remove-5-back', startMark('remove-5-back'));
performance.measure('remove-50-back', startMark('remove-50-back'));
destroy();

/*******************************
Expand Down Expand Up @@ -462,14 +454,14 @@ destroy();
// `toggle-*` (which uses replaceItem) and `edit-cycle-5` (which mixes
// in an editingId flip per cycle).
const el16 = await setup(100);
// purpose: Renames 50 different items in a 100-item list via single-field setProperty without editingId co-fires.
performance.mark(startMark('rename-50'));
for (let i = 0; i < 50; i++) {
// purpose: Renames items in a 100-item list 500 times via single-field setProperty without editingId co-fires.
performance.mark(startMark('rename-500'));
for (let i = 0; i < 500; i++) {
const todos = getTodos(el16);
el16.component.renameTodo(todos[i % todos.length].id, `Renamed ${i}`);
flushWork();
}
performance.measure('rename-50', startMark('rename-50'));
performance.measure('rename-500', startMark('rename-500'));
destroy();

/*******************************
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
{ "mode": "performance", "entryName": "each-100-mount" },
{ "mode": "performance", "entryName": "each-100" },
{ "mode": "performance", "entryName": "helper-100-mount" },
{ "mode": "performance", "entryName": "helper-100-state-change" }
{ "mode": "performance", "entryName": "helper-100-state-change-1k" }
]
},
{
Expand All @@ -24,7 +24,7 @@
{ "mode": "performance", "entryName": "each-100-mount" },
{ "mode": "performance", "entryName": "each-100" },
{ "mode": "performance", "entryName": "helper-100-mount" },
{ "mode": "performance", "entryName": "helper-100-state-change" }
{ "mode": "performance", "entryName": "helper-100-state-change-1k" }
]
}
]
Expand Down
Loading
Loading