.me

Rust .me Benchmarks

This directory contains the Rust benchmark ground for the .me kernel port.

The benchmarks are executable binaries, not hard regression thresholds. Their job is to keep the kernel honest while the Rust implementation catches up to the TypeScript semantic contract: append-only memory, path selectors, reactive derivations, secret scopes, lazy/eager recomputation, traceability, hydration, and public/owner projections.

Always run them in release mode:

cargo run --release --bin <benchmark-name>

Coverage

TypeScript benchmark area Rust binary What it checks
Algorithmic scaling / O(k) isolation bench-ok Irrelevant public nodes do not affect the recompute wave for a small dependent set.
Sustained mutation bench-sustained Repeated writes do not cause progressive latency drift.
Fan-out sensitivity bench-fanout A global dependency can drive many subscribers without accidental O(k^2) metadata cloning.
Cold vs warm runtime bench-cold-warm Snapshot hydration cost is paid at startup; warm mutation remains small.
Explain overhead bench-explain-overhead explain() remains cheap enough to keep derivations auditable.
Secret-scope impact bench-secret-scope Secret writes/read paths are measured separately from derivation runtime cost.
Push vs pull bench-push-pull Eager mode pays on write; lazy mode defers recompute until first fresh read.
Secret push vs pull bench-secret-push-pull Lazy public and secret branches are compared across multiple node counts.

Commands

cargo run --release --bin bench-ok
cargo run --release --bin bench-sustained
cargo run --release --bin bench-fanout
cargo run --release --bin bench-cold-warm
cargo run --release --bin bench-explain-overhead
cargo run --release --bin bench-secret-scope
cargo run --release --bin bench-push-pull
cargo run --release --bin bench-secret-push-pull

Reading The Results

k is the semantic recompute wave size. It should track the number of actual dependent targets touched by a write or fresh read, not total memory size.

Public hot paths should stay very small. Secret paths are expected to cost more on write because stored memories are encrypted, but owner reads can remain cheap while the live owner index is hydrated.

Lazy mode does not mean “free write.” It still marks dependent derivations stale. The win is that it avoids recomputing every subscriber until a fresh read actually asks for a target.

Run #001

this-me v0.3.0 · Aug 26, 2026 · 4:37 PM CST · Suis-MacBook-Air.local

Release mode command:

for bin in bench-ok bench-sustained bench-fanout bench-cold-warm \
  bench-explain-overhead bench-secret-scope bench-push-pull \
  bench-secret-push-pull; do
  cargo run --release --bin "$bin"
done

1. O(k) Recompute Isolation

Irrelevant public nodes do not affect the recompute wave. k stayed at 1 while total memories grew past 10,000.

N p50 ms p95 ms max ms k result memories
10 0.018125 0.041083 0.481208 1 69 453
100 0.006291 0.013708 0.044542 1 69 543
1,000 0.006625 0.015542 0.085042 1 69 1,443
5,000 0.006333 0.007417 0.009542 1 69 5,443
10,000 0.006750 0.008750 0.022500 1 69 10,443

2. Sustained Mutation

2,000 consecutive mutations over 4,000 nodes stayed stable. p95 drift was negative in this run, meaning the late window was faster than the first window.

p50 ms p95 ms p99 ms max ms p95 drift
0.008916 0.016541 0.029125 0.216084 -51.21%

3. Fan-Out Sensitivity

This benchmark intentionally changes the number of real dependents. The wave size tracks actual subscribers (k = fanout), not unrelated memory.

fanout iterations k p50 ms p95 ms p99 ms max ms
10 120 10 0.120125 0.173458 0.236042 0.252750
100 120 100 0.611250 1.122042 1.141500 1.581333
500 40 500 3.794375 10.172458 10.625166 10.625166
1,000 20 1,000 8.087166 9.932875 9.932875 9.932875
2,500 8 2,500 21.176292 23.303583 23.303583 23.303583
5,000 4 5,000 43.027000 46.648417 46.648417 46.648417

4. Cold vs Warm Runtime

Snapshot hydration scales with memory count and is paid at startup. Warm mutation remains tiny after hydration.

nodes memories cold p50 ms cold p95 ms first write ms steady avg ms steady p95 ms k
100 102 0.150167 1.033875 0.015209 0.006186 0.007167 1
1,000 1,002 1.407541 2.465042 0.014458 0.007588 0.009958 1
5,000 5,002 7.417334 9.732250 0.019041 0.007818 0.008833 1
10,000 10,002 15.973750 17.813458 0.023708 0.006002 0.007000 1

5. Explain Overhead

explain() is cheap enough to keep derivations inspectable. The measured baseline was noisier than the explain run here, so the meaningful number is explain_only: p95 around 0.52ms for a 3,000-node derivation wave.

mode p50 ms p95 ms p99 ms k
baseline 25.989209 41.766708 66.253958 3,000
with_explain 25.760792 30.925000 33.516042 3,000
explain_only 0.205417 0.516666 0.931125 3,000

6. Secret Scope Impact

Secret direct write/read is slower than public write/read, as expected, but it is still sub-0.04ms at p95 in this run. Lazy derivation cost was close to public.

case scope p50 ms p95 ms p99 ms k
write_read public 0.003375 0.005916 0.025709 0
write_read secret 0.016083 0.032417 0.072417 0
derivation_lazy public 0.563416 1.547292 2.542917 1
derivation_lazy secret 0.719416 1.695084 2.521125 1

Write/read p95 slowdown: 447.95%. Lazy derivation p95 slowdown: 9.55%.

7. Push vs Pull

Eager mode pays on mutation. Lazy mode keeps mutation small and defers subscriber recompute until read.

mode fanout k mutation p95 ms read p95 ms
eager 10 10 0.148416 0.003583
eager 100 100 2.197833 0.006375
eager 500 500 6.329666 0.013250
eager 1,000 1,000 10.653666 0.009792
eager 2,500 2,500 48.590083 0.024125
eager 5,000 5,000 58.827542 0.022583
lazy 10 1 0.006916 0.007291
lazy 100 1 0.138750 0.019417
lazy 500 1 2.354125 0.069667
lazy 1,000 1 2.997041 0.060417
lazy 2,500 1 5.094000 0.088875
lazy 5,000 1 8.070334 0.098209

8. Secret Push vs Pull

Lazy public and secret branches remain in the same broad performance envelope for the measured node counts.

nodes public mutation p95 ms secret mutation p95 ms public read p95 ms secret read p95 ms mutation slowdown read slowdown
100 0.170583 0.235708 0.024750 0.027375 1.38x 1.11x
300 0.539333 0.793042 0.033916 0.049250 1.47x 1.45x
600 2.443334 1.601083 0.060834 0.046958 0.66x 0.77x

Current State

Run #001 confirms the Rust port is past boilerplate: it has measurable, release-mode behavior across public writes, selectors, derivations, hydration, secret scopes, lazy/eager recompute, and explainability.

The strongest current signal is not “Rust is faster everywhere.” The honest signal is better: Rust already preserves .me’s semantic shape while giving the kernel an embeddable, memory-safe host suitable for monads, local daemons, robots, Raspberry Pi-class machines, and edge runtime work.

The Rust implementation is allowed to improve internal mechanics, but it should not change .me meaning to chase a number.