Skip to content

Lifetimes

Preview — Ranvier is pre-release; its APIs may change.

CI instruction counts

The Library comparison tab compares retired instructions per operation across engines for the latest CI measurement; the Trends tab follows each scenario across commits. The tab last chosen opens on every benchmark page, and the runtime and metric carry over between tabs. Choose a runtime, metric or recorded commit, filter scenarios by name, and toggle libraries in the legend.

The trend panels follow each scenario across every recorded commit, one panel per Ranvier variant. By default each line shows its change since its first record; libraries other than Ranvier are pinned versions, so their lines mark the run-to-run noise floor. A change since the first record of 5 % or more is set in bold. The Metric control switches between instructions, cycles, allocated bytes, branch misses and CPU time on x64. The shaded band spans the lowest and highest of the five processes behind each median, and a ▲ under the axis marks a commit at which the Ranvier variant’s library counters changed; the readout lists those counters.

Loading recorded measurements…

Construction and teardown are not the hottest path, but they are the path a UI takes on every mount and unmount, and the one where an owner that only grows would show up as a leak rather than as a slowdown. See Benchmarks for configuration, environment and caveats.

ConstructionBenchmarks

MethodWhat it measures
CreateSignalBaseline. Constructing a signal.
CreateAndDisposeMemoConstructing and disposing a memo that reads nothing.
CreateAndDisposeEffectConstructing and disposing an effect that reads nothing.

CreateAndDisposeSeededMemo constructs and disposes a memo through the seeded constructor, Memo (graph, seed, compute), which adds one adapter closure over the seed and the compute. It postdates the table below and has no published figure yet; it is in the suite for local runs (dotnet run --project bench/Ranvier.Benchmarks -c Release -- --filter "*ConstructionBenchmarks*").

There is deliberately no create-without-dispose case for memos. A memo attaches itself to its enclosing owner, so one that is never disposed is retained for the life of the graph by design; measuring that would measure garbage collection over a growing child list rather than construction.

Recorded 2026-09-28. Source: Ranvier.Benchmarks.Lifetimes.ConstructionBenchmarks at commit d87920f.

MethodMeanErrorStdDevOp/sRatioRatioSDGen0AllocatedAlloc Ratio
CreateSignal8.552 ns0.1997 ns0.2219 ns116,926,213.1baseline0.005388 B
CreateAndDisposeMemo25.348 ns0.4896 ns0.4580 ns39,451,210.82.97x slower0.09x0.0148248 B2.82x more
CreateAndDisposeEffect35.357 ns0.7312 ns0.8980 ns28,282,776.94.14x slower0.15x0.0114192 B2.18x more

ReadingNodeBenchmarks

The same lifecycle for nodes that read a source, so the dependency edge is part of the cost: linked on the first run, unlinked on disposal.

MethodWhat it measures
CreateAndDisposeReadingEffectAn effect that reads one signal, created and disposed.
CreateAndDisposeReadingMemoA memo that reads one signal, created and disposed.

Recorded 2026-09-28. Source: Ranvier.Benchmarks.Lifetimes.ReadingNodeBenchmarks at commit d87920f.

MethodMeanErrorStdDevOp/sGen0Allocated
CreateAndDisposeReadingEffect39.67 ns0.811 ns0.719 ns25,208,600.50.0129216 B
CreateAndDisposeReadingMemo40.46 ns0.800 ns0.821 ns24,716,778.60.0162272 B

FanOutLifecycleBenchmarks

Nodes computations (1, 64 or 1024) on one source, created in a scope and torn down with it. At d87920f, the larger cases crossed the observer list's indexing threshold, so the table includes building and draining that index; #98 removed the index. Divide by Nodes for the cost per node.

MethodWhat it measures
EffectsOnOneSourceNodes effects reading one signal, created and disposed as a unit.
MemosOnOneSourceNodes memos reading one signal, created and disposed as a unit.

Recorded 2026-09-28. Source: Ranvier.Benchmarks.Lifetimes.FanOutLifecycleBenchmarks at commit d87920f.

MethodNodesMeanErrorStdDevOp/sGen0Gen1Allocated
EffectsOnOneSource168.62 ns1.392 ns1.547 ns14,573,344.50.0257-432 B
MemosOnOneSource167.41 ns0.959 ns0.850 ns14,833,915.80.0291-488 B
EffectsOnOneSource644,008.59 ns53.988 ns47.859 ns249,464.30.92320.045815552 B
MemosOnOneSource643,992.81 ns77.870 ns72.840 ns250,450.31.14060.068719136 B
EffectsOnOneSource102469,184.00 ns1,100.919 ns1,029.800 ns14,454.214.64846.7139245952 B
MemosOnOneSource102468,837.85 ns1,084.798 ns961.645 ns14,526.918.06649.2773303296 B

ScopeBenchmarks

A scope with Children children (1, 8 or 64): the shape a component mount takes.

MethodWhat it measures
CreateAndDisposeScopeThe scope and its children, created and torn down as a unit.
DisposeChildrenIndividuallyThe same children, each disposed on its own rather than through the scope. This checks that an individually disposed child leaves its owner's child list.

Recorded 2026-09-28. Source: Ranvier.Benchmarks.Lifetimes.ScopeBenchmarks at commit d87920f.

MethodChildrenMeanErrorStdDevOp/sGen0Gen1Allocated
CreateAndDisposeScope167.45 ns0.841 ns0.703 ns14,826,300.90.0291-488 B
DisposeChildrenIndividually142.37 ns0.829 ns0.987 ns23,602,124.60.0196-328 B
CreateAndDisposeScope8380.10 ns6.883 ns6.438 ns2,630,910.60.15260.00102560 B
DisposeChildrenIndividually8391.09 ns4.925 ns4.607 ns2,556,979.70.14640.00102456 B
CreateAndDisposeScope643,961.65 ns38.597 ns34.215 ns252,420.31.14060.068719136 B
DisposeChildrenIndividually644,581.74 ns40.383 ns35.799 ns218,257.81.15970.061019480 B

Observer removal

Three classes in the ObserverRemoval category measure removing and relinking observers of one wide source, at Nodes or Sources 8, 64 or 1024. Divide by Nodes for the cost per node.

MethodWhat it measures
ObserverRemovalBenchmarks.DisposeRootNodes effects on one signal created under a root, then the root disposed.
ObserverRemovalBenchmarks.DisposeInCreationOrderNodes effects created, then disposed oldest first.
ObserverRemovalBenchmarks.DisposeScatteredNodes effects created, then disposed in one fixed shuffled order.
OutOfOrderReadBenchmarks.RotateReadsOne effect re-reading Sources signals in an order rotated by one from its previous run.
ObserverChurnBenchmarks.RelinkAllEvery one of Nodes effects drops its edge to the wide source, then links it again.
ObserverChurnBenchmarks.RelinkOneOne effect drops its edge and links it again, cycling through the effects.
ObserverChurnBenchmarks.WriteWideOne write notifying all Nodes effects, over an observer list with earlier removals from its middle.

These classes have no published figure. The observer-removal report records the runs behind #98. They are in the suite for local runs: dotnet run --project bench/Ranvier.Benchmarks -c Release -- --anyCategories ObserverRemoval.

SizeOfProbe

The shallow size of each node type: the Allocated column of an uninitialised instance, which counts the object's own fields and none of the objects they reference. It tracks how a change to a node's fields moves its footprint.

MethodType
MemoIntMemo<int>
AsyncMemoIntAsyncMemo<int>
BoundaryIntBoundary<int>
EffectEffect
AsyncSourceIntAsyncSource<int>
FailureFailure, the record a failed node holds.

SizeOfProbe has no counter scenario and no published figure yet. It is in the suite for local runs: dotnet run --project bench/Ranvier.Benchmarks -c Release -- --filter "*SizeOfProbe*".

The Ratio and Alloc Ratio columns, where present, compare each method with the baseline method of the same class on the same run. They describe the relative cost of two operations inside Ranvier, not a comparison with any other library.

Edit this page