Skip to content

Commit f8e4914

Browse files
committed
feat(zen): micro-optimizations for read performance targeting 70/100
- Inline track() in Computation.read() (eliminate function call) - Cache local vars in Signal.get and _updateIfNecessary - Single observer fast path in _notifyObservers - Optimize _notify with simplified state checks - Early returns in _updateIfNecessary for CHECK->CLEAN Target improvements (Hybrid Weighted - aiming for 70/100): - Single Read: 17.5M → 22M+ ops/sec - Extreme Read: 80K → 160K+ ops/sec - Very Deep Chain: 193K → 500K+ ops/sec All 48 tests pass.
1 parent 4c852c6 commit f8e4914

File tree

3 files changed

+87
-44
lines changed

3 files changed

+87
-44
lines changed

.changeset/micro-optimizations.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
'@sylphx/zen': minor
3+
---
4+
5+
Micro-optimizations for single read and extreme read performance
6+
7+
OPTIMIZATIONS:
8+
- Inline track() in Computation.read() - eliminate function call overhead
9+
- Cache local vars in Signal.get - reduce property access
10+
- Single observer fast path in _notifyObservers - early return for common case
11+
- Optimize _updateIfNecessary - cache myTime, early return for CHECK→CLEAN
12+
- Simplify _notify - streamline state checks with fast paths
13+
14+
BENCHMARK TARGETS (Hybrid Weighted - targeting 70/100):
15+
- Single Read: 17.5M → 22M+ ops/sec (close gap with Solid.js 22.3M)
16+
- Extreme Read: 80K → 160K+ ops/sec (match Zustand/Redux Toolkit)
17+
- Very Deep Chain: 193K → 500K+ ops/sec
18+
- General speedup across all hot paths
19+
20+
These micro-optimizations eliminate overhead in the most frequently executed code paths.

packages/zen/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@sylphx/zen",
3-
"version": "3.36.0",
4-
"description": "Zen state management library - extreme minimalism, extreme speed. V3.35: Read path optimizations (fast CLEAN path, inline track, state extraction).",
3+
"version": "3.37.0",
4+
"description": "Zen state management library - extreme minimalism, extreme speed. V3.37: Micro-optimizations (local vars, fast paths, early returns).",
55
"type": "module",
66
"main": "./dist/index.cjs",
77
"module": "./dist/index.js",

packages/zen/src/zen.ts

Lines changed: 65 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -242,11 +242,21 @@ class Computation<T> implements SourceType, ObserverType, Owner {
242242
}
243243

244244
read(): T {
245-
// OPTIMIZATION: Fast path for CLEAN state
245+
// OPTIMIZATION: Extract state once, fast path for CLEAN
246246
const state = this._state & 3;
247247

248248
if (currentObserver) {
249-
track(this);
249+
// OPTIMIZATION: Inline track - avoid function call
250+
const sources = currentObserver._sources;
251+
if (!newSources && sources && sources[newSourcesIndex] === this) {
252+
newSourcesIndex++;
253+
} else if (!newSources) {
254+
newSources = [this];
255+
} else if (this !== newSources[newSources.length - 1]) {
256+
newSources.push(this);
257+
}
258+
259+
// Only check if not CLEAN
250260
if (state !== STATE_CLEAN) {
251261
this._updateIfNecessary();
252262
}
@@ -284,33 +294,37 @@ class Computation<T> implements SourceType, ObserverType, Owner {
284294
_updateIfNecessary(): void {
285295
const state = this._state & 3;
286296

287-
if (state === STATE_DISPOSED || state === STATE_CLEAN) {
288-
return;
289-
}
297+
// OPTIMIZATION: Fast exit for CLEAN or DISPOSED
298+
if (state === STATE_CLEAN || state === STATE_DISPOSED) return;
290299

291300
if (state === STATE_CHECK) {
292-
// SOLID.JS PATTERN: Check ALL sources recursively first
293301
const sources = this._sources;
294302
if (sources) {
303+
const myTime = this._time;
295304
const len = sources.length;
305+
306+
// OPTIMIZATION: Check all sources, early exit if any changed
296307
for (let i = 0; i < len; i++) {
297308
sources[i]._updateIfNecessary();
298309

299-
// OPTIMIZATION: Early exit if changed (avoid checking remaining sources)
300-
if (sources[i]._time > this._time) {
310+
// Early exit optimization
311+
if (sources[i]._time > myTime) {
301312
this._state = (this._state & ~3) | STATE_DIRTY;
302313
break;
303314
}
304315
}
305316
}
317+
318+
// After checking, if still CHECK, mark CLEAN
319+
if ((this._state & 3) === STATE_CHECK) {
320+
this._state = (this._state & ~3) | STATE_CLEAN;
321+
return;
322+
}
306323
}
307324

308-
// Only update if still dirty after checking sources
325+
// Only update if DIRTY
309326
if ((this._state & 3) === STATE_DIRTY) {
310327
this.update();
311-
} else if ((this._state & 3) === STATE_CHECK) {
312-
// OPTIMIZATION: Set CLEAN if still CHECK after verifying all sources
313-
this._state = (this._state & ~3) | STATE_CLEAN;
314328
}
315329
}
316330

@@ -405,25 +419,27 @@ class Computation<T> implements SourceType, ObserverType, Owner {
405419

406420
_notify(state: number): void {
407421
const currentState = this._state & 3;
408-
const isExecutingSelf = currentObserver === this;
409422

423+
// OPTIMIZATION: Fast path - already at or past this state
410424
if (currentState >= state || currentState === STATE_DISPOSED) {
411-
if (isExecutingSelf && (state === STATE_DIRTY || state === STATE_CHECK) && this._effectType !== EFFECT_PURE) {
412-
// Effect is executing and received a notification - ALWAYS schedule for next round
413-
// Even if FLAG_PENDING is set (it will be from the current execution)
425+
// Special handling for self-executing effects
426+
if (currentObserver === this && state >= STATE_CHECK && this._effectType !== EFFECT_PURE) {
414427
this._state |= FLAG_PENDING;
415428
pendingEffects[pendingCount++] = this;
416429
}
417430
return;
418431
}
419432

433+
// Update state
420434
this._state = (this._state & ~3) | state;
421435

436+
// Schedule user effects
422437
if (this._effectType !== EFFECT_PURE) {
423438
scheduleEffect(this);
424439
}
425440

426-
if (state === STATE_DIRTY || state === STATE_CHECK) {
441+
// Propagate CHECK to observers
442+
if (state >= STATE_CHECK) {
427443
this._notifyObservers(STATE_CHECK);
428444
}
429445
}
@@ -432,8 +448,15 @@ class Computation<T> implements SourceType, ObserverType, Owner {
432448
const observers = this._observers;
433449
if (!observers) return;
434450

435-
// OPTIMIZATION: Batch notify to reduce intermediate work
436451
const len = observers.length;
452+
453+
// OPTIMIZATION: Single observer fast path
454+
if (len === 1) {
455+
observers[0]._notify(state);
456+
return;
457+
}
458+
459+
// OPTIMIZATION: Batch for large observer counts
437460
if (len > 100) {
438461
batchDepth++;
439462
for (let i = 0; i < len; i++) {
@@ -484,14 +507,11 @@ class Signal<T> implements SourceType {
484507
}
485508

486509
get value(): T {
487-
// OPTIMIZATION: Inline track check
510+
// OPTIMIZATION: Inline track - avoid function call overhead
488511
if (currentObserver) {
489-
// OPTIMIZATION: Compare with old sources first
490-
if (
491-
!newSources &&
492-
currentObserver._sources &&
493-
currentObserver._sources[newSourcesIndex] === this
494-
) {
512+
const sources = currentObserver._sources;
513+
// OPTIMIZATION: Fast path - source unchanged at same index
514+
if (!newSources && sources && sources[newSourcesIndex] === this) {
495515
newSourcesIndex++;
496516
} else if (!newSources) {
497517
newSources = [this];
@@ -508,29 +528,32 @@ class Signal<T> implements SourceType {
508528
this._value = next;
509529
this._time = ++clock;
510530

511-
if (!this._observers) return;
531+
const observers = this._observers;
532+
if (!observers) return;
533+
534+
const len = observers.length;
512535

513-
// OPTIMIZATION: Skip batching overhead for small observer counts
514-
const len = this._observers.length;
536+
// OPTIMIZATION: Fast path for single observer (common case)
515537
if (len === 1) {
516-
// Fast path for single observer
517-
this._observers[0]._notify(STATE_DIRTY);
518-
if (batchDepth === 0 && !isFlushScheduled && pendingCount > 0) {
538+
observers[0]._notify(STATE_DIRTY);
539+
// Only flush if effects are pending and not already scheduled
540+
if (batchDepth === 0 && pendingCount > 0 && !isFlushScheduled) {
519541
isFlushScheduled = true;
520542
flushEffects();
521543
}
522-
} else {
523-
// Auto-batching for multiple observers
524-
batchDepth++;
525-
for (let i = 0; i < len; i++) {
526-
this._observers[i]._notify(STATE_DIRTY);
527-
}
528-
batchDepth--;
544+
return;
545+
}
529546

530-
if (batchDepth === 0 && !isFlushScheduled && pendingCount > 0) {
531-
isFlushScheduled = true;
532-
flushEffects();
533-
}
547+
// Auto-batching for multiple observers
548+
batchDepth++;
549+
for (let i = 0; i < len; i++) {
550+
observers[i]._notify(STATE_DIRTY);
551+
}
552+
batchDepth--;
553+
554+
if (batchDepth === 0 && pendingCount > 0 && !isFlushScheduled) {
555+
isFlushScheduled = true;
556+
flushEffects();
534557
}
535558
}
536559

0 commit comments

Comments
 (0)