Skip to content

Compact child lifecycle - #58

Merged
SandroMaglione merged 1 commit into
mainfrom
codex/compact-lifecycle-termination
Aug 9, 2026
Merged

Compact child lifecycle#58
SandroMaglione merged 1 commit into
mainfrom
codex/compact-lifecycle-termination

Conversation

@SandroMaglione

@SandroMaglione SandroMaglione commented Aug 9, 2026

Copy link
Copy Markdown
Member

Summary

  • reserve child starts and create their shared scope in one atomic runtime step
  • close child scopes atomically and execute zero- or one-item cleanup directly
  • specialize invoke start/stop traversal while retaining unbounded parallelism for multiple invokes and real finalizers
  • cover concurrent child interruption and scoped-resource finalization explicitly

Why

The common parent-with-one-child lifecycle paid general collection construction and unbounded traversal machinery during both invoke startup and shutdown. It also split child scope creation and registry reservation across separate Effect boundaries.

Impact

The public API, type inference, ordering, interruption, and finalization contracts are unchanged. The full local three-process comparison improves parent-with-one-child lifecycle throughput from 16,271 to 17,699 families/s (+8.8%) and slightly reduces retained family heap from 17.0 to 16.8 KiB.

Changeset

  • Added a patch changeset for the runtime lifecycle improvement.

Validation

  • pnpm check
  • pnpm perf:types
  • 15-pair focused lifecycle comparison
  • Three independent full base/candidate runtime benchmark processes
  • Relevant example checks are covered by pnpm check
  • Reviewed the independent CI runtime performance report

@github-actions

github-actions Bot commented Aug 9, 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.03s 0.03s
Import effect-machine 0.03s 0.03s
Machine.defineStates (3 states) 0.10s 0.11s
Machine.make (3 states, 2 events) 0.16s 0.16s
machine.handle (3 states, 2 transitions) 0.23s 0.25s
machine.handle (depth 8) 0.51s 0.51s
machine.handle (depth 12) 0.55s 0.58s
machine.handle (depth 16) 0.61s 0.62s
machine.handle (depth 24) 0.71s 0.71s
machine.handle (wide depth 16) 0.78s 0.78s
machine.handle (parallel/history/choice) 0.63s 0.63s
machine.handle (4 successive calls) 0.60s 0.61s
machine exact input/output/error/services 0.52s 0.52s
execution adapter readiness 0.58s 0.60s

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

@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Runtime performance

Median of 5 independent benchmark processes on AMD EPYC 7763 64-Core Processor with Node v24.18.0.

Pull request baseline

Scenario Effect Machine XState 5 XState 6 alpha
Plan counter transitions 114,605 transitions/s 137,896 transitions/s 125,651 transitions/s
Drain burst with terminal fence 92,137 increments/s 419,052 increments/s 115,124 increments/s
Drain burst with a change observer 67,875 increments/s 414,492 increments/s 114,810 increments/s
Lookup and send to one child 85,211 increments/s 411,431 increments/s 109,587 increments/s
Start and stop a machine 18,769 machines/s 193,087 machines/s 74,377 machines/s
Start and stop a parent with one child 7,680 families/s 70,741 families/s 27,383 families/s

Effect runtime reference points

Scenario Effect Machine Effect runtime primitives
Start and stop a raw compiled process 30,357 processes/s
Start and interrupt a suspended fiber 167,168 fibers/s
Start and stop a queue worker 115,128 workers/s
Start and stop an actor shell 106,180 actors/s
Start and stop two actor shells 66,587 families/s
Update an owner-only mutable snapshot 317,863,954 updates/s
Update a synchronized snapshot 1,546,865 updates/s
Create, resolve, and await a terminal latch 1,435,416 latches/s
Memory profile Effect Machine XState 5 XState 6 alpha Effect runtime primitives
Idle machine 7.5 KiB 3.8 KiB 6.1 KiB
Raw generic managed process 12.3 KiB
Raw compiled process 7.6 KiB
Two independent idle machines 14.5 KiB 7.3 KiB 11.8 KiB
Idle parent with one child 16.8 KiB 5.5 KiB 8.8 KiB
Parent with observed child registry 21.0 KiB
Parent with observed invoked child snapshots 17.0 KiB
Suspended Effect fiber 0.6 KiB
Effect queue with waiting fiber 2.8 KiB
Effect mailbox actor shell 3.2 KiB
Two Effect actor shells 6.9 KiB

Effect Machine change from base

Metric Base Base variability PR PR variability Difference
Plan counter transitions 114,796 transitions/s 1.6% MAD 114,605 transitions/s 1.9% MAD -0.2%
Drain burst with terminal fence 92,886 increments/s 2.2% MAD 92,137 increments/s 3.1% MAD -0.8%
Drain burst with a change observer 67,992 increments/s 1.7% MAD 67,875 increments/s 1.3% MAD -0.2%
Lookup and send to one child 86,421 increments/s 2.2% MAD 85,211 increments/s 3.5% MAD -1.4%
Start and stop a machine 18,653 machines/s 2.0% MAD 18,769 machines/s 4.2% MAD +0.6%
Start and stop a parent with one child 7,062 families/s 5.6% MAD 7,680 families/s 4.9% MAD +8.7%
Idle machine heap per unit 7.5 KiB 0.0% MAD 7.5 KiB 0.0% MAD -0.0%
Raw generic managed process heap per unit 12.5 KiB 0.0% MAD 12.3 KiB 0.0% MAD -1.4%
Raw compiled process heap per unit 7.8 KiB 0.1% MAD 7.6 KiB 0.1% MAD -1.5%
Two independent idle machines heap per unit 14.5 KiB 0.0% MAD 14.5 KiB 0.0% MAD -0.0%
Idle parent with one child heap per unit 17.0 KiB 0.0% MAD 16.8 KiB 0.0% MAD -1.2%
Parent with observed child registry heap per unit 21.2 KiB 0.0% MAD 21.0 KiB 0.0% MAD -0.9%
Parent with observed invoked child snapshots heap per unit 17.2 KiB 0.0% MAD 17.0 KiB 0.0% MAD -1.2%

Effect runtime reference change from base

Metric Base Base variability PR PR variability Difference
Start and stop a raw compiled process 30,845 processes/s 1.4% MAD 30,357 processes/s 0.3% MAD -1.6%
Start and interrupt a suspended fiber 168,039 fibers/s 1.2% MAD 167,168 fibers/s 0.8% MAD -0.5%
Start and stop a queue worker 117,014 workers/s 0.0% MAD 115,128 workers/s 1.4% MAD -1.6%
Start and stop an actor shell 106,078 actors/s 0.5% MAD 106,180 actors/s 2.1% MAD +0.1%
Start and stop two actor shells 66,765 families/s 1.5% MAD 66,587 families/s 1.7% MAD -0.3%
Update an owner-only mutable snapshot 317,863,954 updates/s 0.0% MAD 317,863,954 updates/s 0.0% MAD 0.0%
Update a synchronized snapshot 1,525,937 updates/s 3.0% MAD 1,546,865 updates/s 1.4% MAD +1.4%
Create, resolve, and await a terminal latch 1,433,273 latches/s 2.1% MAD 1,435,416 latches/s 1.1% MAD +0.1%
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 f550ac0 into main Aug 9, 2026
9 checks passed
@SandroMaglione
SandroMaglione deleted the codex/compact-lifecycle-termination branch August 9, 2026 09:31
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