Skip to content

Deliver invoked snapshots directly - #45

Merged
SandroMaglione merged 1 commit into
mainfrom
codex/direct-invoke-snapshots
Aug 8, 2026
Merged

Deliver invoked snapshots directly#45
SandroMaglione merged 1 commit into
mainfrom
codex/direct-invoke-snapshots

Conversation

@SandroMaglione

@SandroMaglione SandroMaglione commented Aug 8, 2026

Copy link
Copy Markdown
Member

Summary

  • deliver invoked child active snapshots directly from the child runtime
  • remove the replay PubSub, subscription, watcher fiber, and watcher teardown retained by snapshot-mapped invokes
  • keep the observer internal and lazy while preserving stale-session checks, ordered delivery, and callback isolation
  • update the runtime memory profile to describe the direct observation path

The previous stream-based implementation retained approximately 16 KiB above an otherwise identical parent-child family. Four order-balanced local process pairs reduced snapshot-observed family heap by 28.5%, from 57.5 KiB to 41.1 KiB, with unrelated throughput remaining neutral within local variability.

Changeset

  • Added or updated for a library or package-metadata change
  • Not required because this PR does not change src/ or package.json

Validation

  • pnpm check
  • Relevant example checks, when examples changed (not applicable)
  • Reviewed the automated type-performance report, when the public TypeScript API or inference changed; local budgets are unchanged and no public API changed
  • Reviewed the automated runtime-performance report, when runtime behavior changed

@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Type performance

Measured with TypeScript 6.0.3 and skipLibCheck=true.

Scenario Base PR Difference
Effect only 55 55 0 (0.0%)
Import effect-machine 55 55 0 (0.0%)
Machine.defineStates (3 states) 2,965 2,965 0 (0.0%)
Machine.make (3 states, 2 events) 8,715 8,715 0 (0.0%)
machine.handle (3 states, 2 transitions) 23,492 23,492 0 (0.0%)
machine.handle (depth 8) 117,075 117,075 0 (0.0%)
machine.handle (depth 12) 129,713 129,713 0 (0.0%)
machine.handle (depth 16) 145,055 145,055 0 (0.0%)
machine.handle (depth 24) 183,851 183,851 0 (0.0%)
machine.handle (wide depth 16) 214,189 214,189 0 (0.0%)
machine.handle (parallel/history/choice) 132,667 132,667 0 (0.0%)
machine.handle (4 successive calls) 128,674 128,674 0 (0.0%)
machine exact input/output/error/services 110,584 110,584 0 (0.0%)
execution adapter readiness 127,854 127,854 0 (0.0%)

Marginal instantiations are measured against the matching setup without that API call:

Scenario Base PR Difference
Import effect-machine 0 0 0
Machine.defineStates (3 states) 2,910 2,910 0 (0.0%)
Machine.make (3 states, 2 events) 5,742 5,742 0 (0.0%)
machine.handle (3 states, 2 transitions) 14,777 14,777 0 (0.0%)
machine.handle (depth 8) 109,601 109,601 0 (0.0%)
machine.handle (depth 12) 121,039 121,039 0 (0.0%)
machine.handle (depth 16) 135,181 135,181 0 (0.0%)
machine.handle (depth 24) 171,577 171,577 0 (0.0%)
machine.handle (wide depth 16) 202,224 202,224 0 (0.0%)
machine.handle (parallel/history/choice) 114,331 114,331 0 (0.0%)
machine.handle (4 successive calls) 113,703 113,703 0 (0.0%)
machine exact input/output/error/services 100,670 100,670 0 (0.0%)
execution adapter readiness 102,092 102,092 0 (0.0%)
Check times (informational)
Scenario Base PR
Effect only 0.02s 0.02s
Import effect-machine 0.02s 0.02s
Machine.defineStates (3 states) 0.07s 0.07s
Machine.make (3 states, 2 events) 0.11s 0.11s
machine.handle (3 states, 2 transitions) 0.16s 0.18s
machine.handle (depth 8) 0.37s 0.38s
machine.handle (depth 12) 0.41s 0.41s
machine.handle (depth 16) 0.44s 0.43s
machine.handle (depth 24) 0.49s 0.50s
machine.handle (wide depth 16) 0.54s 0.54s
machine.handle (parallel/history/choice) 0.46s 0.45s
machine.handle (4 successive calls) 0.43s 0.41s
machine exact input/output/error/services 0.37s 0.38s
execution adapter readiness 0.42s 0.42s

Type instantiations are the comparison metric. Check time varies with runner load and is informational only.

@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Runtime performance

Median of 5 independent benchmark processes on AMD EPYC 9V74 80-Core Processor with Node v24.18.0.

Pull request baseline

Scenario Effect Machine XState 5 XState 6 alpha
Plan counter transitions 108,818 transitions/s 140,861 transitions/s 116,979 transitions/s
Drain burst with terminal fence 66,852 increments/s 392,497 increments/s 107,768 increments/s
Drain burst with a change observer 55,728 increments/s 388,780 increments/s 108,557 increments/s
Lookup and send to one child 61,447 increments/s 388,731 increments/s 105,697 increments/s
Start and stop a machine 16,847 machines/s 183,891 machines/s 74,738 machines/s
Start and stop a parent with one child 5,417 families/s 72,886 families/s 30,704 families/s
Memory profile Effect Machine XState 5 XState 6 alpha Effect runtime primitives
Idle machine 17.8 KiB 3.8 KiB 6.1 KiB
Raw managed process 13.1 KiB
Two independent idle machines 34.9 KiB 7.3 KiB 11.8 KiB
Idle parent with one child 41.0 KiB 5.5 KiB 8.8 KiB
Parent with observed child registry 52.4 KiB
Parent with observed invoked child snapshots 41.2 KiB
Suspended Effect fiber 0.7 KiB
Effect queue with waiting fiber 2.8 KiB
Effect mailbox actor shell 3.2 KiB

Effect Machine change from base

Metric Base Base variability PR PR variability Difference
Plan counter transitions 109,912 transitions/s 0.4% MAD 108,818 transitions/s 0.9% MAD -1.0%
Drain burst with terminal fence 67,064 increments/s 0.8% MAD 66,852 increments/s 0.8% MAD -0.3%
Drain burst with a change observer 55,648 increments/s 0.4% MAD 55,728 increments/s 0.2% MAD +0.1%
Lookup and send to one child 61,506 increments/s 0.5% MAD 61,447 increments/s 0.3% MAD -0.1%
Start and stop a machine 16,961 machines/s 1.7% MAD 16,847 machines/s 1.3% MAD -0.7%
Start and stop a parent with one child 5,390 families/s 0.6% MAD 5,417 families/s 1.5% MAD +0.5%
Idle machine heap per unit 17.8 KiB 0.0% MAD 17.8 KiB 0.0% MAD +0.1%
Raw managed process heap per unit 13.1 KiB 0.0% MAD 13.1 KiB 0.0% MAD +0.1%
Two independent idle machines heap per unit 34.9 KiB 0.0% MAD 34.9 KiB 0.0% MAD +0.0%
Idle parent with one child heap per unit 41.6 KiB 0.0% MAD 41.0 KiB 0.0% MAD -1.5%
Parent with observed child registry heap per unit 53.0 KiB 0.0% MAD 52.4 KiB 0.0% MAD -1.2%
Parent with observed invoked child snapshots heap per unit 57.5 KiB 0.0% MAD 41.2 KiB 0.0% MAD -28.3%
Versions and interpretation
  • Effect Machine: 0.3.0
  • XState 5: 5.32.5
  • XState 6 alpha: 6.0.0-alpha.27
  • Effect runtime primitives: 4.0.0-beta.105

Higher throughput is better; lower heap is better. Variability is the median absolute deviation across independent processes, relative to their median. Runtime measurements on shared GitHub-hosted hardware remain informational, so small differences should be confirmed across multiple workflow runs.

@SandroMaglione
SandroMaglione merged commit 1aa746c into main Aug 8, 2026
9 checks passed
@SandroMaglione
SandroMaglione deleted the codex/direct-invoke-snapshots branch August 8, 2026 14:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant