onCrack

Basecamp's ONCE Campfire · the F# port, unchained

onCrack.

The same Campfire, pixel for pixel, on a server that is free to do less work: it keeps finished pages until a commit changes what they show, and commits concurrent posts together. Who may see a kept page is decided again on every request, as upstream asks. Two claims, each with its evidence one click away. Every number on this page links to the file it came from.

Claim one

Faster.

Ahead of current upstream Rust and C at the median in every workload of Basecamp's own harness, with the room being written to and without. Quote the range, not one number: the three sessions of each profile, pooled, read as below; each session on its own reads 2.11× to 4.74× over Rust (normal) and 3.00× to 6.33× (mixed), because 4 of the 6 sessions ran beside other projects' work.

  • 3.76×over Rust f9dca47
  • 2.40×over C cd0cbe4
  • 5.25×over the F# port
0×1×2×3×4×5×6×7×Rust is 1×Normalnormal-1: 2.11× Rust (quiet host)normal-2: 3.28× Rust (noisy host)normal-3: 4.74× Rust (noisy host)pooled, all three sessions: 3.76× RustMixedmixed-1: 6.33× Rust (quiet host)mixed-2: 3.12× Rust (noisy host)mixed-3: 3.00× Rust (noisy host)pooled, all three sessions: 3.76× Rust
a session on a quiet hosta session beside other workall three, pooled
  • Fresh authorization. The default re-checks the session and the room membership on every cache hit, as upstream's contract asks. The cached decision, opt-in, reads 4.19× over Rust.
  • Per room page, the CPU says the same: Rust spends 3.79× and C 2.93× of onCrack's CPU (3.75× and 2.68× on the quiet host).
  • Mixed reads: 3.76× over Rust and 2.26× over C while one writer posts into the room.

The evidence Not their machine: four of a VM's CPUs a side. Compare ratios.

Claim two

More runnable in production.

Fast is easy to buy by dropping what production needs. onCrack keeps the pixels, the durability and every connected client, and it says what that costs.

  • 0of 1,000 Cable clients cut in PR #6's heaviest profile, in 3 of 3 rounds. Rust cut 902 to 959 of them.
  • 944/944screenshots pixel-equal to Rails, on every seed, on the final code.
  • 13,571/13,571posted messages reached every client in the median round, and every posted message did in every round. Rust: 65 of 76,602.
  • Durability is Rails'. Every write commits before it is answered; nothing weaker ships. The last kill -9 runs (4 of them, round three) lost 0 and duplicated 0.
  • Cable's backlog is bounded. A shared log with a byte budget, 1 GiB for the whole hub; over it, the clients furthest behind are cut. Its known slack is in the report.
  • It holds the posters, not the readers. It takes 902 posts a second to Rust's 5,102, a 9 s p99 from a post to the slowest client, and about 996 MB of memory to Rust's 125. A different policy, not a free win.

The evidence The reliability tables

How it got here

One timeline, three lines.

  • onCrack, fresh authorization the default since round three
  • onCrack, cached decision opt-in; all there was in rounds one and two
  • the F# port's own climb the line onCrack forked from
  • Rust, pinned 1×
  • Rails stored baseline
Fri 9 Oct, 00:21 EDT · r2-mem · tier 3R2.5 guard: the rebuilt image, the five classic workloads at c=16 (2 reps), level with R2.4commit 64a714d · sha256:24c79d6462e5 build · overall 5.31× of Rust
16 connections1 connection
onCrack, cached decisionF# portRustRailsonCrack, cached decision/RustonCrack, cached decisionF# portRustRailsonCrack, cached decision/Rust
Room page176,90218 µs40,42294 µs28,623122 µs2396.18×4.38× F# port26,59019 µs7,617209 µs6,481142 µs1074.10×3.49× F# port
Messages page185,00616 µs37,836102 µs30,063114 µs3816.15×4.89× F# port27,18618 µs8,312199 µs6,822139 µs2183.98×3.27× F# port
Sidebar197,65515 µs37,555102 µs28,238123 µs5997.00×5.26× F# port27,78417 µs8,000181 µs6,196149 µs2874.48×3.47× F# port
Search193,46415 µs34,070107 µs26,606124 µs4087.27×5.68× F# port27,35118 µs6,055315 µs5,646158 µs1934.84×4.52× F# port
Post a message15,687178 µs8,905353 µs7,174386 µs3302.19×1.76× F# port5,172246 µs3,052629 µs2,779404 µs1671.86×1.69× F# port

What was done

  • 4eb87dc R2.5: bench/mem and bench/mem-sweep, boot timeline, GC log, start-up prewarm
  • 64a714d R2.5: read cache 16 MB, fast path 64 MB, libvips 16 MB cache and two workers, two malloc arenas
Requests per second, CPU µs per request beneath. Rust, the F# port and Rails are the stored medians of bench/results/phase7-final (one session, 3 reps each); onCrack's own runs are against them, never re-measured side by side. Greyed onCrack values were carried from an earlier run.
Thu 8 Oct, 19:42 EDT · r2-c1 · tier 3R2.4 realistic workloads on the rebuilt image (spread -6% against R2.3: pool workers do not spin)commit 4e12ec8 · sha256:c4942d0a4aa7 build · overall 5.28× of Rust
16 connections1 connection
onCrack, cached decisionF# portRustRailsonCrack, cached decision/RustonCrack, cached decisionF# portRustRailsonCrack, cached decision/Rust
Room page174,41218 µs40,42294 µs28,623122 µs2396.09×4.31× F# port26,08019 µs7,617209 µs6,481142 µs1074.02×3.42× F# port
Messages page184,72216 µs37,836102 µs30,063114 µs3816.14×4.88× F# port25,96319 µs8,312199 µs6,822139 µs2183.81×3.12× F# port
Sidebar197,20415 µs37,555102 µs28,238123 µs5996.98×5.25× F# port26,72318 µs8,000181 µs6,196149 µs2874.31×3.34× F# port
Search192,33215 µs34,070107 µs26,606124 µs4087.23×5.65× F# port27,50018 µs6,055315 µs5,646158 µs1934.87×4.54× F# port
Post a message15,559178 µs8,905353 µs7,174386 µs3302.17×1.75× F# port5,201247 µs3,052629 µs2,779404 µs1671.87×1.70× F# port

What was done

  • 82168d8 App requests on a solo event thread run in place; idle pool workers do not spin (R2.4)
  • 46deb83 The health check runs on the event thread whoever else it serves (R2.4)
  • ab4d6aa Pool workers do not spin in the AOT image either; the spin default needs the fast path (R2.4)
Requests per second, CPU µs per request beneath. Rust, the F# port and Rails are the stored medians of bench/results/phase7-final (one session, 3 reps each); onCrack's own runs are against them, never re-measured side by side. Greyed onCrack values were carried from an earlier run.
Thu 8 Oct, 19:42 EDT · r2-c1 · tier 3R2.4: app requests on a solo event thread run in place, idle pool workers do not spin, /up runs in placecommit 4e12ec8 · sha256:c4942d0a4aa7 build · overall 5.08× of Rust
16 connections1 connection
onCrack, cached decisionF# portRustRailsonCrack, cached decision/RustonCrack, cached decisionF# portRustRailsonCrack, cached decision/Rust
Room page176,18417 µs40,42294 µs28,623122 µs2396.16×4.36× F# port26,59019 µs7,617209 µs6,481142 µs1074.10×3.49× F# port
Messages page182,90616 µs37,836102 µs30,063114 µs3816.08×4.83× F# port27,18618 µs8,312199 µs6,822139 µs2183.98×3.27× F# port
Sidebar196,07715 µs37,555102 µs28,238123 µs5996.94×5.22× F# port27,78417 µs8,000181 µs6,196149 µs2874.48×3.47× F# port
Search194,73415 µs34,070107 µs26,606124 µs4087.32×5.72× F# port27,35118 µs6,055315 µs5,646158 µs1934.84×4.52× F# port
Post a message12,782175 µs8,905353 µs7,174386 µs3301.78×1.44× F# port5,172246 µs3,052629 µs2,779404 µs1671.86×1.69× F# port

What was done

R2.4 one connection: an app request that arrives on an event thread serving only its own connection runs there instead of hopping to the thread pool, idle pool workers no longer spin, the health check runs in place; a post at one connection costs 246 us of CPU on 1.27 cores (was 392 on 1.91)

Requests per second, CPU µs per request beneath. Rust, the F# port and Rails are the stored medians of bench/results/phase7-final (one session, 3 reps each); onCrack's own runs are against them, never re-measured side by side. Greyed onCrack values were carried from an earlier run.
Fri 9 Oct, 05:49 EDT · r2-final · tier 3Round 2 final: rebuilt image 155ea5d0e559 (f5352d0), 3 reps; the current-upstream review (verification harness) is in oncrack-r2-final.mdcommit f5352d0 · image build · overall 4.98× of Rust
16 connections1 connection
onCrack, cached decisionF# portRustRailsonCrack, cached decision/RustonCrack, cached decisionF# portRustRailsonCrack, cached decision/Rust
Room page177,27617 µs40,42294 µs28,623122 µs2396.19×4.39× F# port26,21519 µs7,617209 µs6,481142 µs1074.05×3.44× F# port
Messages page185,53816 µs37,836102 µs30,063114 µs3816.17×4.90× F# port26,19919 µs8,312199 µs6,822139 µs2183.84×3.15× F# port
Sidebar198,16115 µs37,555102 µs28,238123 µs5997.02×5.28× F# port26,82118 µs8,000181 µs6,196149 µs2874.33×3.35× F# port
Search192,73715 µs34,070107 µs26,606124 µs4087.24×5.66× F# port27,76517 µs6,055315 µs5,646158 µs1934.92×4.59× F# port
Post a message11,292178 µs8,905353 µs7,174386 µs3301.57×1.27× F# port5,112248 µs3,052629 µs2,779404 µs1671.84×1.68× F# port

What was done

Round 2 final re-baseline: current upstream Rust f9dca47 and C cd0cbe4 measured with upstream verification harness (3.25x Rust, 2.37x C, 3.93x the port over the five, same session); this dot is the project suite on the same image

Requests per second, CPU µs per request beneath. Rust, the F# port and Rails are the stored medians of bench/results/phase7-final (one session, 3 reps each); onCrack's own runs are against them, never re-measured side by side. Greyed onCrack values were carried from an earlier run.
Fri 9 Oct, 04:08 EDT · r2-verifier · tier 3R2 verifier fixes: rebuilt image 7e56d81cc90f (2ea9ae9), 3 reps; post c=16 reps stalled on the WAL restart (warm-up did not settle)commit 2ea9ae9 · image build · overall 4.96× of Rust
16 connections1 connection
onCrack, cached decisionF# portRustRailsonCrack, cached decision/RustonCrack, cached decisionF# portRustRailsonCrack, cached decision/Rust
Room page175,72018 µs40,42294 µs28,623122 µs2396.14×4.35× F# port26,42618 µs7,617209 µs6,481142 µs1074.08×3.47× F# port
Messages page185,18416 µs37,836102 µs30,063114 µs3816.16×4.89× F# port26,60718 µs8,312199 µs6,822139 µs2183.90×3.20× F# port
Sidebar196,90715 µs37,555102 µs28,238123 µs5996.97×5.24× F# port26,90418 µs8,000181 µs6,196149 µs2874.34×3.36× F# port
Search196,01215 µs34,070107 µs26,606124 µs4087.37×5.75× F# port28,11817 µs6,055315 µs5,646158 µs1934.98×4.64× F# port
Post a message11,050174 µs8,905353 µs7,174386 µs3301.54×1.24× F# port3,999246 µs3,052629 µs2,779404 µs1671.44×1.31× F# port

What was done

  • 1537475 Caches see commits by other connections: watch the WAL index (round 2 verifier, critical and major)
  • 1c87802 Fast path targets as hashes, a cache budget of 0 is off, Q= is a quality (round 2 verifier)
  • 2ea9ae9 The WAL index watch names libc per platform and never fails start-up
Requests per second, CPU µs per request beneath. Rust, the F# port and Rails are the stored medians of bench/results/phase7-final (one session, 3 reps each); onCrack's own runs are against them, never re-measured side by side. Greyed onCrack values were carried from an earlier run.
Tue 13 Oct, 04:43 EDT · r5-final-cached · tier 3Round 5 HEAD image (3e6a300), cached decision (CAMPFIRE_FRESH_AUTH=0), project suite, 3 repscommit 3e6a300 · image bfcbb4633485 (3e6a300; src identical… build · overall 4.90× of Rust
16 connections1 connection
onCrack, cached decisionF# portRustRailsonCrack, cached decision/RustonCrack, cached decisionF# portRustRailsonCrack, cached decision/Rust
Room page172,15018 µs40,42294 µs28,623122 µs2396.01×4.26× F# port24,14221 µs7,617209 µs6,481142 µs1073.73×3.17× F# port
Messages page184,58616 µs37,836102 µs30,063114 µs3816.14×4.88× F# port24,65520 µs8,312199 µs6,822139 µs2183.61×2.97× F# port
Sidebar194,37915 µs37,555102 µs28,238123 µs5996.88×5.18× F# port25,64819 µs8,000181 µs6,196149 µs2874.14×3.21× F# port
Search190,66416 µs34,070107 µs26,606124 µs4087.17×5.60× F# port24,64020 µs6,055315 µs5,646158 µs1934.36×4.07× F# port
Post a message11,121206 µs8,905353 µs7,174386 µs3301.55×1.25× F# port3,505258 µs3,052629 µs2,779404 µs1671.26×1.15× F# port

What was done

Round 5's final image on the project suite with the cached decision (CAMPFIRE_FRESH_AUTH=0, the opt-in), tier 3, 3 reps, scored over the stored pinned Rust ccece30 medians. Measured 2026-10-13, 10:26-10:58 EDT: the third attempt; the first two ran while other projects loaded the host (load average 40-100) and are kept unlogged in r5-cached-attempt1/ and r5-cached/ (rule fixed before attempt 3: the attempt with the fewest noisy-host flags, then the fewest unsettled warm-ups, is logged). 8 of 30 windows flagged, mildly (probe ratio 1.10-1.23). Post a message reads 11,121 req/s at 205.5 us against round 3's 8,057 at 180.9, a throughput the host explains and a CPU the fresh rows echo (see the round 5 fresh row). Reads in the cached mode are level with round 3's (c=16 within 3%), so the fresh row's gain over round 3 is fresh authorization getting cheaper, not the cached path getting faster. Raw data: bench/results/oncrack-r5-climb/r5-cached3/.

Requests per second, CPU µs per request beneath. Rust, the F# port and Rails are the stored medians of bench/results/phase7-final (one session, 3 reps each); onCrack's own runs are against them, never re-measured side by side. Greyed onCrack values were carried from an earlier run.
Thu 8 Oct, 16:02 EDT · r2-front · tier 3R2.3: front server fast path (replays before routing, kit and cookies), replays answered on the socket event thread, request ids without a syscallcommit 09415ba · sha256:390e390e43fa build · overall 4.89× of Rust
16 connections1 connection
onCrack, cached decisionF# portRustRailsonCrack, cached decision/RustonCrack, cached decisionF# portRustRailsonCrack, cached decision/Rust
Room page174,41218 µs40,42294 µs28,623122 µs2396.09×4.31× F# port26,08019 µs7,617209 µs6,481142 µs1074.02×3.42× F# port
Messages page184,72216 µs37,836102 µs30,063114 µs3816.14×4.88× F# port25,96319 µs8,312199 µs6,822139 µs2183.81×3.12× F# port
Sidebar197,20415 µs37,555102 µs28,238123 µs5996.98×5.25× F# port26,72318 µs8,000181 µs6,196149 µs2874.31×3.34× F# port
Search192,33215 µs34,070107 µs26,606124 µs4087.23×5.65× F# port27,50018 µs6,055315 µs5,646158 µs1934.87×4.54× F# port
Post a message10,664186 µs8,905353 µs7,174386 µs3301.49×1.20× F# port4,876392 µs3,052629 µs2,779404 µs1671.75×1.60× F# port

What was done

R2.3 front server fast path: a cached page replayed before routing, the kit adapter and cookie parsing, on the socket's event thread

Requests per second, CPU µs per request beneath. Rust, the F# port and Rails are the stored medians of bench/results/phase7-final (one session, 3 reps each); onCrack's own runs are against them, never re-measured side by side. Greyed onCrack values were carried from an earlier run.
Fri 9 Oct, 22:28 EDT · r3-final-cached · tier 3Round 3 final image (37c5988), cached decision (CAMPFIRE_FRESH_AUTH=0), project suite, 3 reps, logged in round 5commit 37c5988 · image e34e485ff87d (37c5988) build · overall 4.64× of Rust
16 connections1 connection
onCrack, cached decisionF# portRustRailsonCrack, cached decision/RustonCrack, cached decisionF# portRustRailsonCrack, cached decision/Rust
Room page176,89318 µs40,42294 µs28,623122 µs2396.18×4.38× F# port25,73219 µs7,617209 µs6,481142 µs1073.97×3.38× F# port
Messages page185,30316 µs37,836102 µs30,063114 µs3816.16×4.90× F# port25,12620 µs8,312199 µs6,822139 µs2183.68×3.02× F# port
Sidebar197,05515 µs37,555102 µs28,238123 µs5996.98×5.25× F# port25,57219 µs8,000181 µs6,196149 µs2874.13×3.20× F# port
Search191,40416 µs34,070107 µs26,606124 µs4087.19×5.62× F# port24,54220 µs6,055315 µs5,646158 µs1934.35×4.05× F# port
Post a message8,057181 µs8,905353 µs7,174386 µs3301.12×0.90× F# port3,533258 µs3,052629 µs2,779404 µs1671.27×1.16× F# port

What was done

Round 3's final image on the project suite with the cached decision (CAMPFIRE_FRESH_AUTH=0, the opt-in), tier 3, 3 reps, scored over the stored pinned Rust ccece30 medians. Measured 2026-10-13 (round 5), 10:58-11:28 EDT: the third attempt; the first two ran while other projects loaded the host (load average 40-100) and are kept unlogged in r3-cached-attempt1/ and r3-cached/ (rule fixed before attempt 3: the attempt with the fewest noisy-host flags is logged). 3 of 30 windows flagged. Post a message is host-sensitive here (8,057 req/s [7,626-10,891] at 180.9 us). Raw data: bench/results/oncrack-r5-climb/r3-cached3/.

Requests per second, CPU µs per request beneath. Rust, the F# port and Rails are the stored medians of bench/results/phase7-final (one session, 3 reps each); onCrack's own runs are against them, never re-measured side by side. Greyed onCrack values were carried from an earlier run.
Tue 13 Oct, 04:43 EDT · r5-final-fresh · tier 3Round 5 HEAD image (3e6a300), fresh authorization (the default), project suite, 3 repscommit 3e6a300 · image bfcbb4633485 (3e6a300; src identical… build · overall 4.63× of Rust
16 connections1 connection
onCrack, fresh authorizationF# portRustRailsonCrack, fresh authorization/RustonCrack, fresh authorizationF# portRustRailsonCrack, fresh authorization/Rust
Room page166,31619 µs40,42294 µs28,623122 µs2395.81×4.11× F# port24,56321 µs7,617209 µs6,481142 µs1073.79×3.22× F# port
Messages page173,51818 µs37,836102 µs30,063114 µs3815.77×4.59× F# port24,85421 µs8,312199 µs6,822139 µs2183.64×2.99× F# port
Sidebar187,73816 µs37,555102 µs28,238123 µs5996.65×5.00× F# port25,08620 µs8,000181 µs6,196149 µs2874.05×3.14× F# port
Search184,09417 µs34,070107 µs26,606124 µs4086.92×5.40× F# port24,58421 µs6,055315 µs5,646158 µs1934.35×4.06× F# port
Post a message9,911214 µs8,905353 µs7,174386 µs3301.38×1.11× F# port3,462270 µs3,052629 µs2,779404 µs1671.25×1.13× F# port

What was done

Round 5's final image on the project suite in the default mode (fresh authorization), tier 3, 3 reps, scored over the stored pinned Rust ccece30 medians. Measured 2026-10-13, 04:47-05:20 EDT, one session, quiet host (1 of 30 windows flagged). The image is campfire-oncrack:app, built at ee5a2e9; git diff ee5a2e9..3e6a300 over src, Dockerfile, global.json and the props files is empty. At c=16 reads are 1.12-1.14x round 3's; at c=1 within 4%. Post a message is the one row that went down: 9,911 req/s at 213.8 us of CPU per post against round 3's 11,463 at 188.4 (reps 9,004-11,270, 188-220 us; the cached-mode rows read the same way, 205.5 vs 180.9 us). Two post-only cross-checks do not settle it: in the quieter one round 5 read 188.8 us (11,860 req/s) and round 3 187.4 (8,808); in the other round 5 was disturbed by the host (519 us, 5,268) and round 3 read 184.9 (11,743). A small post-path cost from round 5's changes can be neither confirmed nor ruled out on this host. Raw data and cross-checks: bench/results/oncrack-r5-climb/.

Requests per second, CPU µs per request beneath. Rust, the F# port and Rails are the stored medians of bench/results/phase7-final (one session, 3 reps each); onCrack's own runs are against them, never re-measured side by side. Greyed onCrack values were carried from an earlier run.
Fri 9 Oct, 22:28 EDT · r3-final-fresh · tier 3Round 3 final image (37c5988), fresh authorization (the default), project suite, 3 reps, logged in round 5commit 37c5988 · image e34e485ff87d (37c5988) build · overall 4.32× of Rust
16 connections1 connection
onCrack, fresh authorizationF# portRustRailsonCrack, fresh authorization/RustonCrack, fresh authorizationF# portRustRailsonCrack, fresh authorization/Rust
Room page147,89921 µs40,42294 µs28,623122 µs2395.17×3.66× F# port23,70722 µs7,617209 µs6,481142 µs1073.66×3.11× F# port
Messages page154,72420 µs37,836102 µs30,063114 µs3815.15×4.09× F# port24,11422 µs8,312199 µs6,822139 µs2183.53×2.90× F# port
Sidebar166,07818 µs37,555102 µs28,238123 µs5995.88×4.42× F# port24,92021 µs8,000181 µs6,196149 µs2874.02×3.12× F# port
Search161,08119 µs34,070107 µs26,606124 µs4086.05×4.73× F# port24,66421 µs6,055315 µs5,646158 µs1934.37×4.07× F# port
Post a message11,463188 µs8,905353 µs7,174386 µs3301.60×1.29× F# port3,645260 µs3,052629 µs2,779404 µs1671.31×1.19× F# port

What was done

Round 3's final image on the project suite in the default mode (fresh authorization on every cache hit, upstream's contract), tier 3, 3 reps, scored over the stored pinned Rust ccece30 medians. Measured 2026-10-13 (round 5), 05:20-05:51 EDT, because round 3 logged no project-suite row. Image built from 37c5988 in a scratch worktree. One session, quiet host (2 of 30 windows flagged). Raw data: bench/results/oncrack-r5-climb/r3-fresh/.

Requests per second, CPU µs per request beneath. Rust, the F# port and Rails are the stored medians of bench/results/phase7-final (one session, 3 reps each); onCrack's own runs are against them, never re-measured side by side. Greyed onCrack values were carried from an earlier run.
Thu 8 Oct, 11:51 EDT · r2-post · tier 2 · reverted564a162 with CAMPFIRE_WRITE_INLINE=off, c=1 and c=64commit 564a162 · mounted build · overall 3.95× of Rust
16 connections1 connection
onCrack, cached decisionF# portRustRailsonCrack, cached decision/RustonCrack, cached decisionF# portRustRailsonCrack, cached decision/Rust
Room page123,94230 µs40,42294 µs28,623122 µs2394.33×3.07× F# port13,428144 µs7,617209 µs6,481142 µs1072.07×1.76× F# port
Messages page123,25230 µs37,836102 µs30,063114 µs3814.10×3.26× F# port13,623142 µs8,312199 µs6,822139 µs2182.00×1.64× F# port
Sidebar138,18227 µs37,555102 µs28,238123 µs5994.89×3.68× F# port14,987134 µs8,000181 µs6,196149 µs2872.42×1.87× F# port
Search136,03227 µs34,070107 µs26,606124 µs4085.11×3.99× F# port15,700127 µs6,055315 µs5,646158 µs1932.78×2.59× F# port
Post a message15,571213 µs8,905353 µs7,174386 µs3302.17×1.75× F# port3,503576 µs3,052629 µs2,779404 µs1671.26×1.15× F# port

What was done

  • 564a162 Post path: unread marks only where they change, one commit per post, writes on the caller's thread (R2.2)
Requests per second, CPU µs per request beneath. Rust, the F# port and Rails are the stored medians of bench/results/phase7-final (one session, 3 reps each); onCrack's own runs are against them, never re-measured side by side. Greyed onCrack values were carried from an earlier run.
Thu 8 Oct, 11:51 EDT · r2-post · tier 2mixed and spread_mixed on the gated build: spread_mixed posts 343 -> 733/s; mixed posts +26%, reads -21% (more posts, more invalidations)commit e73714c · mounted build · overall 3.90× of Rust
16 connections1 connection
onCrack, cached decisionF# portRustRailsonCrack, cached decision/RustonCrack, cached decisionF# portRustRailsonCrack, cached decision/Rust
Room page123,94230 µs40,42294 µs28,623122 µs2394.33×3.07× F# port13,428144 µs7,617209 µs6,481142 µs1072.07×1.76× F# port
Messages page123,25230 µs37,836102 µs30,063114 µs3814.10×3.26× F# port13,623142 µs8,312199 µs6,822139 µs2182.00×1.64× F# port
Sidebar138,18227 µs37,555102 µs28,238123 µs5994.89×3.68× F# port14,987134 µs8,000181 µs6,196149 µs2872.42×1.87× F# port
Search136,03227 µs34,070107 µs26,606124 µs4085.11×3.99× F# port15,700127 µs6,055315 µs5,646158 µs1932.78×2.59× F# port
Post a message14,493218 µs8,905353 µs7,174386 µs3302.02×1.63× F# port4,313437 µs3,052629 µs2,779404 µs1671.55×1.41× F# port

What was done

  • 564a162 Post path: unread marks only where they change, one commit per post, writes on the caller's thread (R2.2)
  • e73714c Inline writes only for a lone writing request; a request's thread never waits for a WAL restart (R2.2)
Requests per second, CPU µs per request beneath. Rust, the F# port and Rails are the stored medians of bench/results/phase7-final (one session, 3 reps each); onCrack's own runs are against them, never re-measured side by side. Greyed onCrack values were carried from an earlier run.
Wed 7 Oct, 13:10 EDT · search · tier 3C3 image: gzipped buffers and frozen pages sent with Content-Length instead of chunkedcommit 460e89d · mounted build · overall 3.84× of Rust
16 connections1 connection
onCrack, cached decisionF# portRustRailsonCrack, cached decision/RustonCrack, cached decisionF# portRustRailsonCrack, cached decision/Rust
Room page124,32830 µs40,42294 µs28,623122 µs2394.34×3.08× F# port13,548143 µs7,617209 µs6,481142 µs1072.09×1.78× F# port
Messages page124,32830 µs37,836102 µs30,063114 µs3814.14×3.29× F# port13,837142 µs8,312199 µs6,822139 µs2182.03×1.66× F# port
Sidebar138,27427 µs37,555102 µs28,238123 µs5994.90×3.68× F# port16,349123 µs8,000181 µs6,196149 µs2872.64×2.04× F# port
Search136,31327 µs34,070107 µs26,606124 µs4085.12×4.00× F# port14,677136 µs6,055315 µs5,646158 µs1932.60×2.42× F# port
Post a message13,249231 µs8,905353 µs7,174386 µs3301.85×1.49× F# port3,399581 µs3,052629 µs2,779404 µs1671.22×1.11× F# port

What was done

No code change since the previous dot (a measurement only).

Requests per second, CPU µs per request beneath. Rust, the F# port and Rails are the stored medians of bench/results/phase7-final (one session, 3 reps each); onCrack's own runs are against them, never re-measured side by side. Greyed onCrack values were carried from an earlier run.
Thu 8 Oct, 07:18 EDT · round1-final · tier 3four-way re-baseline: Rails, Rust, the F# port and onCrack measured in one session (bench/run, all suites, 3 reps); onCrack image da1e92f (src as 1598c5e)commit da1e92f · sha256:3fd0dd609e3c build · overall 3.82× of Rust
16 connections1 connection
onCrack, cached decisionF# portRustRailsonCrack, cached decision/RustonCrack, cached decisionF# portRustRailsonCrack, cached decision/Rust
Room page123,94230 µs40,42294 µs28,623122 µs2394.33×3.07× F# port13,428144 µs7,617209 µs6,481142 µs1072.07×1.76× F# port
Messages page123,25230 µs37,836102 µs30,063114 µs3814.10×3.26× F# port13,623142 µs8,312199 µs6,822139 µs2182.00×1.64× F# port
Sidebar138,18227 µs37,555102 µs28,238123 µs5994.89×3.68× F# port14,987134 µs8,000181 µs6,196149 µs2872.42×1.87× F# port
Search136,03227 µs34,070107 µs26,606124 µs4085.11×3.99× F# port15,700127 µs6,055315 µs5,646158 µs1932.78×2.59× F# port
Post a message13,215230 µs8,905353 µs7,174386 µs3301.84×1.48× F# port3,395585 µs3,052629 µs2,779404 µs1671.22×1.11× F# port

What was done

No code change since the previous dot (a measurement only).

Requests per second, CPU µs per request beneath. Rust, the F# port and Rails are the stored medians of bench/results/phase7-final (one session, 3 reps each); onCrack's own runs are against them, never re-measured side by side. Greyed onCrack values were carried from an earlier run.
Thu 8 Oct, 09:22 EDT · r2-cable · tier 2tier 2: direct writes + WakeBatch + line hold + compact Turbo Stream JSON (before the thread-static hoist)commit 52364b6 · mounted build · overall 3.82× of Rust
16 connections1 connection
onCrack, cached decisionF# portRustRailsonCrack, cached decision/RustonCrack, cached decisionF# portRustRailsonCrack, cached decision/Rust
Room page123,94230 µs40,42294 µs28,623122 µs2394.33×3.07× F# port13,428144 µs7,617209 µs6,481142 µs1072.07×1.76× F# port
Messages page123,25230 µs37,836102 µs30,063114 µs3814.10×3.26× F# port13,623142 µs8,312199 µs6,822139 µs2182.00×1.64× F# port
Sidebar138,18227 µs37,555102 µs28,238123 µs5994.89×3.68× F# port14,987134 µs8,000181 µs6,196149 µs2872.42×1.87× F# port
Search136,03227 µs34,070107 µs26,606124 µs4085.11×3.99× F# port15,700127 µs6,055315 µs5,646158 µs1932.78×2.59× F# port
Post a message13,215230 µs8,905353 µs7,174386 µs3301.84×1.48× F# port3,395585 µs3,052629 µs2,779404 µs1671.22×1.11× F# port

What was done

  • 52364b6 Cable: write to the socket itself, wake once per post line, compact Turbo Stream JSON (R2.1)
Requests per second, CPU µs per request beneath. Rust, the F# port and Rails are the stored medians of bench/results/phase7-final (one session, 3 reps each); onCrack's own runs are against them, never re-measured side by side. Greyed onCrack values were carried from an earlier run.
Wed 7 Oct, 18:04 EDT · verifier-fixes · tier 3image with the verifier fixes: page deps on the user read-at version, striped room counters, posts broadcast in commit order, kit HTTP differential accepts the gzip lengthcommit 1598c5e · image build · overall 3.80× of Rust
16 connections1 connection
onCrack, cached decisionF# portRustRailsonCrack, cached decision/RustonCrack, cached decisionF# portRustRailsonCrack, cached decision/Rust
Room page123,24830 µs40,42294 µs28,623122 µs2394.31×3.05× F# port13,342145 µs7,617209 µs6,481142 µs1072.06×1.75× F# port
Messages page123,15630 µs37,836102 µs30,063114 µs3814.10×3.25× F# port13,496144 µs8,312199 µs6,822139 µs2181.98×1.62× F# port
Sidebar137,50027 µs37,555102 µs28,238123 µs5994.87×3.66× F# port15,840127 µs8,000181 µs6,196149 µs2872.56×1.98× F# port
Search135,42527 µs34,070107 µs26,606124 µs4085.09×3.97× F# port14,669136 µs6,055315 µs5,646158 µs1932.60×2.42× F# port
Post a message12,991233 µs8,905353 µs7,174386 µs3301.81×1.46× F# port3,374587 µs3,052629 µs2,779404 µs1671.21×1.11× F# port

What was done

No code change since the previous dot (a measurement only).

Requests per second, CPU µs per request beneath. Rust, the F# port and Rails are the stored medians of bench/results/phase7-final (one session, 3 reps each); onCrack's own runs are against them, never re-measured side by side. Greyed onCrack values were carried from an earlier run.
Wed 7 Oct, 12:34 EDT · search · tier 2C3: gzipped buffers and frozen pages sent with Content-Length instead of chunkedcommit cbb1643 · mounted build · overall 3.80× of Rust
16 connections1 connection
onCrack, cached decisionF# portRustRailsonCrack, cached decision/RustonCrack, cached decisionF# portRustRailsonCrack, cached decision/Rust
Room page122,47731 µs40,42294 µs28,623122 µs2394.28×3.03× F# port13,179147 µs7,617209 µs6,481142 µs1072.03×1.73× F# port
Messages page122,35830 µs37,836102 µs30,063114 µs3814.07×3.23× F# port13,420145 µs8,312199 µs6,822139 µs2181.97×1.61× F# port
Sidebar137,12327 µs37,555102 µs28,238123 µs5994.86×3.65× F# port15,674127 µs8,000181 µs6,196149 µs2872.53×1.96× F# port
Search136,80527 µs34,070107 µs26,606124 µs4085.14×4.02× F# port14,071140 µs6,055315 µs5,646158 µs1932.49×2.32× F# port
Post a message13,049234 µs8,905353 µs7,174386 µs3301.82×1.47× F# port3,100614 µs3,052629 µs2,779404 µs1671.12×1.02× F# port

What was done

  • cbb1643 onCrack C3: gzipped buffers and frozen pages go out with a Content-Length
Requests per second, CPU µs per request beneath. Rust, the F# port and Rails are the stored medians of bench/results/phase7-final (one session, 3 reps each); onCrack's own runs are against them, never re-measured side by side. Greyed onCrack values were carried from an earlier run.
Thu 8 Oct, 12:51 EDT · r2-post · tier 2R2.2 baseline in session: mixed and spread_mixed on the R2.1 imagecommit 72ddf9f · sha256:449b485c8a0e build · overall 3.79× of Rust
16 connections1 connection
onCrack, cached decisionF# portRustRailsonCrack, cached decision/RustonCrack, cached decisionF# portRustRailsonCrack, cached decision/Rust
Room page123,94230 µs40,42294 µs28,623122 µs2394.33×3.07× F# port13,428144 µs7,617209 µs6,481142 µs1072.07×1.76× F# port
Messages page123,25230 µs37,836102 µs30,063114 µs3814.10×3.26× F# port13,623142 µs8,312199 µs6,822139 µs2182.00×1.64× F# port
Sidebar138,18227 µs37,555102 µs28,238123 µs5994.89×3.68× F# port14,987134 µs8,000181 µs6,196149 µs2872.42×1.87× F# port
Search136,03227 µs34,070107 µs26,606124 µs4085.11×3.99× F# port15,700127 µs6,055315 µs5,646158 µs1932.78×2.59× F# port
Post a message12,602233 µs8,905353 µs7,174386 µs3301.76×1.42× F# port3,362592 µs3,052629 µs2,779404 µs1671.21×1.10× F# port

What was done

No code change since the previous dot (a measurement only).

Requests per second, CPU µs per request beneath. Rust, the F# port and Rails are the stored medians of bench/results/phase7-final (one session, 3 reps each); onCrack's own runs are against them, never re-measured side by side. Greyed onCrack values were carried from an earlier run.
Thu 8 Oct, 16:02 EDT · r2-front · tier 3R2.3 realistic workloads on the rebuilt imagecommit 09415ba · sha256:390e390e43fa build · overall 3.77× of Rust
16 connections1 connection
onCrack, cached decisionF# portRustRailsonCrack, cached decision/RustonCrack, cached decisionF# portRustRailsonCrack, cached decision/Rust
Room page124,99630 µs40,42294 µs28,623122 µs2394.37×3.09× F# port13,428144 µs7,617209 µs6,481142 µs1072.07×1.76× F# port
Messages page123,25230 µs37,836102 µs30,063114 µs3814.10×3.26× F# port13,623142 µs8,312199 µs6,822139 µs2182.00×1.64× F# port
Sidebar137,76827 µs37,555102 µs28,238123 µs5994.88×3.67× F# port14,987134 µs8,000181 µs6,196149 µs2872.42×1.87× F# port
Search136,03227 µs34,070107 µs26,606124 µs4085.11×3.99× F# port15,700127 µs6,055315 µs5,646158 µs1932.78×2.59× F# port
Post a message12,176186 µs8,905353 µs7,174386 µs3301.70×1.37× F# port4,518396 µs3,052629 µs2,779404 µs1671.63×1.48× F# port

What was done

  • c48baef An inline write that was never answered fails with WriterGone; README lists R2.2's differences
  • 09415ba Front server fast path: replay a cached page before routing, the kit adapter and cookie parsing (R2.3)
Requests per second, CPU µs per request beneath. Rust, the F# port and Rails are the stored medians of bench/results/phase7-final (one session, 3 reps each); onCrack's own runs are against them, never re-measured side by side. Greyed onCrack values were carried from an earlier run.
Wed 7 Oct, 17:32 EDT · verifier-fixes · tier 2verifier fixes: page deps on the user read-at version, striped room counters, posts broadcast in commit ordercommit 7f08f77 · mounted build · overall 3.77× of Rust
16 connections1 connection
onCrack, cached decisionF# portRustRailsonCrack, cached decision/RustonCrack, cached decisionF# portRustRailsonCrack, cached decision/Rust
Room page122,32431 µs40,42294 µs28,623122 µs2394.27×3.03× F# port13,279147 µs7,617209 µs6,481142 µs1072.05×1.74× F# port
Messages page120,31231 µs37,836102 µs30,063114 µs3814.00×3.18× F# port13,657145 µs8,312199 µs6,822139 µs2182.00×1.64× F# port
Sidebar135,99927 µs37,555102 µs28,238123 µs5994.82×3.62× F# port15,803128 µs8,000181 µs6,196149 µs2872.55×1.98× F# port
Search136,80427 µs34,070107 µs26,606124 µs4085.14×4.02× F# port13,993140 µs6,055315 µs5,646158 µs1932.48×2.31× F# port
Post a message12,829236 µs8,905353 µs7,174386 µs3301.79×1.44× F# port3,276600 µs3,052629 µs2,779404 µs1671.18×1.07× F# port

What was done

  • 2f75677 onCrack C4: Native AOT as an opt-in image build, bench/boot, and a memory line in bench/paths
  • 6ec598f onCrack fix: a cached page depends on the global version its user was read under
  • 0ce3b21 onCrack fix: room version counters striped by id, bounded whatever ids requests name
  • 5d91978 onCrack fix: posts' broadcasts go out in commit order
Requests per second, CPU µs per request beneath. Rust, the F# port and Rails are the stored medians of bench/results/phase7-final (one session, 3 reps each); onCrack's own runs are against them, never re-measured side by side. Greyed onCrack values were carried from an earlier run.
Thu 8 Oct, 13:29 EDT · r2-post · tier 3R2.2 image: room page and sidebar c=16, 1 rep (regression check)commit eae5beb · sha256:12969a1861f3 build · overall 3.76× of Rust
16 connections1 connection
onCrack, cached decisionF# portRustRailsonCrack, cached decision/RustonCrack, cached decisionF# portRustRailsonCrack, cached decision/Rust
Room page124,99630 µs40,42294 µs28,623122 µs2394.37×3.09× F# port13,428144 µs7,617209 µs6,481142 µs1072.07×1.76× F# port
Messages page123,25230 µs37,836102 µs30,063114 µs3814.10×3.26× F# port13,623142 µs8,312199 µs6,822139 µs2182.00×1.64× F# port
Sidebar137,76827 µs37,555102 µs28,238123 µs5994.88×3.67× F# port14,987134 µs8,000181 µs6,196149 µs2872.42×1.87× F# port
Search136,03227 µs34,070107 µs26,606124 µs4085.11×3.99× F# port15,700127 µs6,055315 µs5,646158 µs1932.78×2.59× F# port
Post a message12,010185 µs8,905353 µs7,174386 µs3301.67×1.35× F# port4,626391 µs3,052629 µs2,779404 µs1671.66×1.52× F# port

What was done

  • aee6f2c Count the writer's WAL restarts and log the slow ones; post-micro reports slow answers (R2.2)
Requests per second, CPU µs per request beneath. Rust, the F# port and Rails are the stored medians of bench/results/phase7-final (one session, 3 reps each); onCrack's own runs are against them, never re-measured side by side. Greyed onCrack values were carried from an earlier run.
Thu 8 Oct, 12:03 EDT · r2-post · tier 2push job's read on its own thread when a connection is freecommit 33500f4 · mounted build · overall 3.75× of Rust
16 connections1 connection
onCrack, cached decisionF# portRustRailsonCrack, cached decision/RustonCrack, cached decisionF# portRustRailsonCrack, cached decision/Rust
Room page123,94230 µs40,42294 µs28,623122 µs2394.33×3.07× F# port13,428144 µs7,617209 µs6,481142 µs1072.07×1.76× F# port
Messages page123,25230 µs37,836102 µs30,063114 µs3814.10×3.26× F# port13,623142 µs8,312199 µs6,822139 µs2182.00×1.64× F# port
Sidebar138,18227 µs37,555102 µs28,238123 µs5994.89×3.68× F# port14,987134 µs8,000181 µs6,196149 µs2872.42×1.87× F# port
Search136,03227 µs34,070107 µs26,606124 µs4085.11×3.99× F# port15,700127 µs6,055315 µs5,646158 µs1932.78×2.59× F# port
Post a message12,049198 µs8,905353 µs7,174386 µs3301.68×1.35× F# port4,243412 µs3,052629 µs2,779404 µs1671.53×1.39× F# port

What was done

  • 33500f4 The push job reads on its own thread when a reader connection is free (R2.2)
Requests per second, CPU µs per request beneath. Rust, the F# port and Rails are the stored medians of bench/results/phase7-final (one session, 3 reps each); onCrack's own runs are against them, never re-measured side by side. Greyed onCrack values were carried from an earlier run.
Wed 7 Oct, 17:32 EDT · verifier-fixes · tier 2 · revertedbefore the verifier fixes (C4 head), same session as the A/Bcommit f03b62a · mounted build · overall 3.75× of Rust
16 connections1 connection
onCrack, cached decisionF# portRustRailsonCrack, cached decision/RustonCrack, cached decisionF# portRustRailsonCrack, cached decision/Rust
Room page116,84131 µs40,42294 µs28,623122 µs2394.08×2.89× F# port14,007138 µs7,617209 µs6,481142 µs1072.16×1.84× F# port
Messages page121,80930 µs37,836102 µs30,063114 µs3814.05×3.22× F# port13,374146 µs8,312199 µs6,822139 µs2181.96×1.61× F# port
Sidebar137,14027 µs37,555102 µs28,238123 µs5994.86×3.65× F# port14,627136 µs8,000181 µs6,196149 µs2872.36×1.83× F# port
Search135,89527 µs34,070107 µs26,606124 µs4085.11×3.99× F# port14,420138 µs6,055315 µs5,646158 µs1932.55×2.38× F# port
Post a message13,026235 µs8,905353 µs7,174386 µs3301.82×1.46× F# port3,178607 µs3,052629 µs2,779404 µs1671.14×1.04× F# port

What was done

  • 2f75677 onCrack C4: Native AOT as an opt-in image build, bench/boot, and a memory line in bench/paths
Requests per second, CPU µs per request beneath. Rust, the F# port and Rails are the stored medians of bench/results/phase7-final (one session, 3 reps each); onCrack's own runs are against them, never re-measured side by side. Greyed onCrack values were carried from an earlier run.
Thu 8 Oct, 12:51 EDT · r2-post · tier 2 · revertedthe same, logs: restarts 0.3-2.4 scommit aee6f2c · mounted build · overall 3.75× of Rust
16 connections1 connection
onCrack, cached decisionF# portRustRailsonCrack, cached decision/RustonCrack, cached decisionF# portRustRailsonCrack, cached decision/Rust
Room page123,94230 µs40,42294 µs28,623122 µs2394.33×3.07× F# port13,428144 µs7,617209 µs6,481142 µs1072.07×1.76× F# port
Messages page123,25230 µs37,836102 µs30,063114 µs3814.10×3.26× F# port13,623142 µs8,312199 µs6,822139 µs2182.00×1.64× F# port
Sidebar138,18227 µs37,555102 µs28,238123 µs5994.89×3.68× F# port14,987134 µs8,000181 µs6,196149 µs2872.42×1.87× F# port
Search136,03227 µs34,070107 µs26,606124 µs4085.11×3.99× F# port15,700127 µs6,055315 µs5,646158 µs1932.78×2.59× F# port
Post a message11,950184 µs8,905353 µs7,174386 µs3301.67×1.34× F# port4,732380 µs3,052629 µs2,779404 µs1671.70×1.55× F# port

What was done

  • aee6f2c Count the writer's WAL restarts and log the slow ones; post-micro reports slow answers (R2.2)
Requests per second, CPU µs per request beneath. Rust, the F# port and Rails are the stored medians of bench/results/phase7-final (one session, 3 reps each); onCrack's own runs are against them, never re-measured side by side. Greyed onCrack values were carried from an earlier run.
Thu 8 Oct, 11:51 EDT · r2-post · tier 2gzip with libdeflate, a compressor per threadcommit 09ad8ca · mounted build · overall 3.72× of Rust
16 connections1 connection
onCrack, cached decisionF# portRustRailsonCrack, cached decision/RustonCrack, cached decisionF# portRustRailsonCrack, cached decision/Rust
Room page123,94230 µs40,42294 µs28,623122 µs2394.33×3.07× F# port13,428144 µs7,617209 µs6,481142 µs1072.07×1.76× F# port
Messages page123,25230 µs37,836102 µs30,063114 µs3814.10×3.26× F# port13,623142 µs8,312199 µs6,822139 µs2182.00×1.64× F# port
Sidebar138,18227 µs37,555102 µs28,238123 µs5994.89×3.68× F# port14,987134 µs8,000181 µs6,196149 µs2872.42×1.87× F# port
Search136,03227 µs34,070107 µs26,606124 µs4085.11×3.99× F# port15,700127 µs6,055315 µs5,646158 µs1932.78×2.59× F# port
Post a message11,552215 µs8,905353 µs7,174386 µs3301.61×1.30× F# port4,342432 µs3,052629 µs2,779404 µs1671.56×1.42× F# port

What was done

  • 09ad8ca Gzip whole bodies with libdeflate and a compressor kept per thread (R2.2)
Requests per second, CPU µs per request beneath. Rust, the F# port and Rails are the stored medians of bench/results/phase7-final (one session, 3 reps each); onCrack's own runs are against them, never re-measured side by side. Greyed onCrack values were carried from an earlier run.
Thu 8 Oct, 12:50 EDT · r2-post · tier 2a non-GET answer skips the gzip cache and is gzipped once at libdeflate level 1commit 25485bc · mounted build · overall 3.63× of Rust
16 connections1 connection
onCrack, cached decisionF# portRustRailsonCrack, cached decision/RustonCrack, cached decisionF# portRustRailsonCrack, cached decision/Rust
Room page123,94230 µs40,42294 µs28,623122 µs2394.33×3.07× F# port13,428144 µs7,617209 µs6,481142 µs1072.07×1.76× F# port
Messages page123,25230 µs37,836102 µs30,063114 µs3814.10×3.26× F# port13,623142 µs8,312199 µs6,822139 µs2182.00×1.64× F# port
Sidebar138,18227 µs37,555102 µs28,238123 µs5994.89×3.68× F# port14,987134 µs8,000181 µs6,196149 µs2872.42×1.87× F# port
Search136,03227 µs34,070107 µs26,606124 µs4085.11×3.99× F# port15,700127 µs6,055315 µs5,646158 µs1932.78×2.59× F# port
Post a message10,233181 µs8,905353 µs7,174386 µs3301.43×1.15× F# port4,791379 µs3,052629 µs2,779404 µs1671.72×1.57× F# port

What was done

  • 25485bc A post's answer is gzipped once, at libdeflate's level 1, outside the gzip cache (R2.2)
Requests per second, CPU µs per request beneath. Rust, the F# port and Rails are the stored medians of bench/results/phase7-final (one session, 3 reps each); onCrack's own runs are against them, never re-measured side by side. Greyed onCrack values were carried from an earlier run.
Wed 7 Oct, 15:34 EDT · runtime · tier 3 · revertedC4 Native AOT image (campfire-oncrack:aot, NATIVE_AOT=true), opt-in: c=1 +14%, c=16 -10% against the C3 JIT image; cold start and idle memory about halvedcommit 2f75677 · image build · overall 3.47× of Rust
16 connections1 connection
onCrack, cached decisionF# portRustRailsonCrack, cached decision/RustonCrack, cached decisionF# portRustRailsonCrack, cached decision/Rust
Room page108,63535 µs40,42294 µs28,623122 µs2393.80×2.69× F# port15,957161 µs7,617209 µs6,481142 µs1072.46×2.10× F# port
Messages page107,25634 µs37,836102 µs30,063114 µs3813.57×2.83× F# port16,655155 µs8,312199 µs6,822139 µs2182.44×2.00× F# port
Sidebar121,67431 µs37,555102 µs28,238123 µs5994.31×3.24× F# port18,008147 µs8,000181 µs6,196149 µs2872.91×2.25× F# port
Search120,22431 µs34,070107 µs26,606124 µs4084.52×3.53× F# port17,184154 µs6,055315 µs5,646158 µs1933.04×2.84× F# port
Post a message13,614239 µs8,905353 µs7,174386 µs3301.90×1.53× F# port3,513657 µs3,052629 µs2,779404 µs1671.26×1.15× F# port

What was done

  • 2f75677 onCrack C4: Native AOT as an opt-in image build, bench/boot, and a memory line in bench/paths
Requests per second, CPU µs per request beneath. Rust, the F# port and Rails are the stored medians of bench/results/phase7-final (one session, 3 reps each); onCrack's own runs are against them, never re-measured side by side. Greyed onCrack values were carried from an earlier run.
Wed 7 Oct, 10:16 EDT · groupcommit · tier 2broadcast of a message encoded only when its stream has a subscriber (bench post has none)commit 25ea87e · mounted build · overall 2.99× of Rust
16 connections1 connection
onCrack, cached decisionF# portRustRailsonCrack, cached decision/RustonCrack, cached decisionF# portRustRailsonCrack, cached decision/Rust
Room page102,72232 µs40,42294 µs28,623122 µs2393.59×2.54× F# port12,004151 µs7,617209 µs6,481142 µs1071.85×1.58× F# port
Messages page101,68230 µs37,836102 µs30,063114 µs3813.38×2.69× F# port12,032154 µs8,312199 µs6,822139 µs2181.76×1.45× F# port
Sidebar112,82727 µs37,555102 µs28,238123 µs5994.00×3.00× F# port13,600138 µs8,000181 µs6,196149 µs2872.19×1.70× F# port
Search72,31131 µs34,070107 µs26,606124 µs4082.72×2.12× F# port12,885145 µs6,055315 µs5,646158 µs1932.28×2.13× F# port
Post a message12,963234 µs8,905353 µs7,174386 µs3301.81×1.46× F# port2,984639 µs3,052629 µs2,779404 µs1671.07×0.98× F# port

What was done

  • 25ea87e onCrack C2: encode a message's broadcast only when its stream has a subscriber
Requests per second, CPU µs per request beneath. Rust, the F# port and Rails are the stored medians of bench/results/phase7-final (one session, 3 reps each); onCrack's own runs are against them, never re-measured side by side. Greyed onCrack values were carried from an earlier run.
Wed 7 Oct, 10:13 EDT · groupcommit · tier 2post: broadcast, webhook candidates and answer from one readcommit af9d66c · mounted build · overall 2.96× of Rust
16 connections1 connection
onCrack, cached decisionF# portRustRailsonCrack, cached decision/RustonCrack, cached decisionF# portRustRailsonCrack, cached decision/Rust
Room page102,72232 µs40,42294 µs28,623122 µs2393.59×2.54× F# port12,004151 µs7,617209 µs6,481142 µs1071.85×1.58× F# port
Messages page101,68230 µs37,836102 µs30,063114 µs3813.38×2.69× F# port12,032154 µs8,312199 µs6,822139 µs2181.76×1.45× F# port
Sidebar112,82727 µs37,555102 µs28,238123 µs5994.00×3.00× F# port13,600138 µs8,000181 µs6,196149 µs2872.19×1.70× F# port
Search72,31131 µs34,070107 µs26,606124 µs4082.72×2.12× F# port12,885145 µs6,055315 µs5,646158 µs1932.28×2.13× F# port
Post a message12,439248 µs8,905353 µs7,174386 µs3301.73×1.40× F# port2,984639 µs3,052629 µs2,779404 µs1671.07×0.98× F# port

What was done

  • af9d66c onCrack C2: a post's broadcast, webhook candidates and answer from one read
Requests per second, CPU µs per request beneath. Rust, the F# port and Rails are the stored medians of bench/results/phase7-final (one session, 3 reps each); onCrack's own runs are against them, never re-measured side by side. Greyed onCrack values were carried from an earlier run.
Wed 7 Oct, 11:05 EDT · groupcommit · tier 3C2 image: group commit, one read after a post, broadcast encoded only for subscriberscommit 0f3e120 · sha256:56c3c35f8fd5 build · overall 2.95× of Rust
16 connections1 connection
onCrack, cached decisionF# portRustRailsonCrack, cached decision/RustonCrack, cached decisionF# portRustRailsonCrack, cached decision/Rust
Room page98,14632 µs40,42294 µs28,623122 µs2393.43×2.43× F# port11,821152 µs7,617209 µs6,481142 µs1071.82×1.55× F# port
Messages page101,73230 µs37,836102 µs30,063114 µs3813.38×2.69× F# port12,527148 µs8,312199 µs6,822139 µs2181.84×1.51× F# port
Sidebar108,13227 µs37,555102 µs28,238123 µs5993.83×2.88× F# port13,491138 µs8,000181 µs6,196149 µs2872.18×1.69× F# port
Search74,06131 µs34,070107 µs26,606124 µs4082.78×2.17× F# port12,595145 µs6,055315 µs5,646158 µs1932.23×2.08× F# port
Post a message12,953237 µs8,905353 µs7,174386 µs3301.81×1.45× F# port3,123622 µs3,052629 µs2,779404 µs1671.12×1.02× F# port

What was done

No code change since the previous dot (a measurement only).

Requests per second, CPU µs per request beneath. Rust, the F# port and Rails are the stored medians of bench/results/phase7-final (one session, 3 reps each); onCrack's own runs are against them, never re-measured side by side. Greyed onCrack values were carried from an earlier run.
Wed 7 Oct, 09:45 EDT · groupcommit · tier 2group commit: queued writes in one transaction, savepoint each, one COMMIT, after-commit work in one morecommit d3a7a23 · mounted build · overall 2.94× of Rust
16 connections1 connection
onCrack, cached decisionF# portRustRailsonCrack, cached decision/RustonCrack, cached decisionF# portRustRailsonCrack, cached decision/Rust
Room page102,72232 µs40,42294 µs28,623122 µs2393.59×2.54× F# port12,004151 µs7,617209 µs6,481142 µs1071.85×1.58× F# port
Messages page101,68230 µs37,836102 µs30,063114 µs3813.38×2.69× F# port12,032154 µs8,312199 µs6,822139 µs2181.76×1.45× F# port
Sidebar112,82727 µs37,555102 µs28,238123 µs5994.00×3.00× F# port13,600138 µs8,000181 µs6,196149 µs2872.19×1.70× F# port
Search72,31131 µs34,070107 µs26,606124 µs4082.72×2.12× F# port12,885145 µs6,055315 µs5,646158 µs1932.28×2.13× F# port
Post a message11,947257 µs8,905353 µs7,174386 µs3301.67×1.34× F# port2,984639 µs3,052629 µs2,779404 µs1671.07×0.98× F# port

What was done

  • d3a7a23 onCrack C2: group commit on the writer
Requests per second, CPU µs per request beneath. Rust, the F# port and Rails are the stored medians of bench/results/phase7-final (one session, 3 reps each); onCrack's own runs are against them, never re-measured side by side. Greyed onCrack values were carried from an earlier run.
Wed 7 Oct, 09:24 EDT · C1 · tier 3versioned read cache: version counters through TEMP triggers, frozen page bodies per user and request shape, sessions and users for authenticationcommit 23cf334 · sha256:75caf211cc37 build · overall 2.75× of Rust
16 connections1 connection
onCrack, cached decisionF# portRustRailsonCrack, cached decision/RustonCrack, cached decisionF# portRustRailsonCrack, cached decision/Rust
Room page102,72232 µs40,42294 µs28,623122 µs2393.59×2.54× F# port12,004151 µs7,617209 µs6,481142 µs1071.85×1.58× F# port
Messages page101,68230 µs37,836102 µs30,063114 µs3813.38×2.69× F# port12,032154 µs8,312199 µs6,822139 µs2181.76×1.45× F# port
Sidebar112,82727 µs37,555102 µs28,238123 µs5994.00×3.00× F# port13,600138 µs8,000181 µs6,196149 µs2872.19×1.70× F# port
Search72,31131 µs34,070107 µs26,606124 µs4082.72×2.12× F# port12,885145 µs6,055315 µs5,646158 µs1932.28×2.13× F# port
Post a message8,631357 µs8,905353 µs7,174386 µs3301.20×0.97× F# port3,026635 µs3,052629 µs2,779404 µs1671.09×0.99× F# port

What was done

  • a7bdc1b onCrack C1: version counters the writer bumps through TEMP triggers, odd while a write is in flight
  • 651c5f5 onCrack C1: versioned read cache for the room, messages, sidebar and search pages
  • 23cf334 onCrack C1: sessions and users for authentication through the read cache
Requests per second, CPU µs per request beneath. Rust, the F# port and Rails are the stored medians of bench/results/phase7-final (one session, 3 reps each); onCrack's own runs are against them, never re-measured side by side. Greyed onCrack values were carried from an earlier run.
Wed 7 Oct, 04:46 EDT · threadpool · tier 3DOTNET_HillClimbing_Disable=1 in the image (59ee9ae), 3 reps, F# onlycommit 2e6c08e · sha256:421f335c3ff8 build · overall 1.32× of Rust
16 connections1 connection
F#RustRailsF#/RustF#RustRailsF#/Rust
Room page39,14491 µs28,720122 µs2271.36×172× Rails7,391209 µs6,500142 µs1111.14×67× Rails
Messages page42,14484 µs30,230114 µs3901.39×108× Rails8,115202 µs6,981136 µs2091.16×39× Rails
Sidebar37,81495 µs28,378123 µs5811.33×65× Rails7,752185 µs6,366146 µs2681.22×29× Rails
Search34,002108 µs26,606124 µs4101.28×83× Rails5,841326 µs5,638158 µs1891.04×31× Rails
Post a message8,738358 µs7,140389 µs3101.22×28× Rails2,976645 µs2,814399 µs1601.06×19× Rails

What was done

  • 59ee9ae Unit 7.5: disable thread-pool hill climbing in the image
Requests per second, CPU µs per request beneath. Rust is the stored Phase 7 starting point. Rails is the 5b baseline (3 reps), the last time it ran; it doesn't change. Greyed F# values were carried from an earlier run.
Wed 7 Oct, 08:14 EDT · c0 · tier 3The fork, unchanged: campfire-oncrack:app rebuilt from HEAD, no source changecommit 2de7519 · image build · overall 1.31× of Rust
16 connections1 connection
onCrack, cached decisionF# portRustRailsonCrack, cached decision/RustonCrack, cached decisionF# portRustRailsonCrack, cached decision/Rust
Room page38,99492 µs40,42294 µs28,623122 µs2391.36×0.96× F# port7,450211 µs7,617209 µs6,481142 µs1071.15×0.98× F# port
Messages page41,85985 µs37,836102 µs30,063114 µs3811.39×1.11× F# port8,148203 µs8,312199 µs6,822139 µs2181.19×0.98× F# port
Sidebar37,89495 µs37,555102 µs28,238123 µs5991.34×1.01× F# port7,620190 µs8,000181 µs6,196149 µs2871.23×0.95× F# port
Search33,931108 µs34,070107 µs26,606124 µs4081.28×1.00× F# port5,669328 µs6,055315 µs5,646158 µs1931.00×0.94× F# port
Post a message8,566360 µs8,905353 µs7,174386 µs3301.19×0.96× F# port2,970642 µs3,052629 µs2,779404 µs1671.07×0.97× F# port

What was done

First measured onCrack dot: the F# port as forked, built as campfire-oncrack:app, 3 reps of all five workloads at 1 and 16 connections, server on CPUs 0-3 and load generator on 4-7. It carries one change the port made after its final measurement: unit 7.5 turned thread-pool hill climbing off in the image (59ee9ae), so c=1 reads 2-6% under the stored port numbers, as the port's own unit 7.5 tier 3 did. Nothing onCrack-specific has been changed yet.

Requests per second, CPU µs per request beneath. Rust, the F# port and Rails are the stored medians of bench/results/phase7-final (one session, 3 reps each); onCrack's own runs are against them, never re-measured side by side. Greyed onCrack values were carried from an earlier run.
Tue 6 Oct, 22:06 EDT · port final · tier 3The F# port's final result: onCrack's starting pointcommit c3e0eca · image, 3 reps (the port) build · overall 1.30× of Rust
16 connections1 connection
F#RustRailsF#/RustF#RustRailsF#/Rust
Room page40,42294 µs28,623122 µs2271.41×178× Rails7,617209 µs6,481142 µs1111.18×69× Rails
Messages page37,836102 µs30,063114 µs3901.26×97× Rails8,312199 µs6,822139 µs2091.22×40× Rails
Sidebar37,555102 µs28,238123 µs5811.33×65× Rails8,000181 µs6,196149 µs2681.29×30× Rails
Search34,070107 µs26,606124 µs4101.28×83× Rails6,055315 µs5,646158 µs1891.07×32× Rails
Post a message8,905353 µs7,174386 µs3101.24×29× Rails3,052629 µs2,779404 µs1601.10×19× Rails

What was done

onCrack was forked from the published F# port, so its line starts where the port finished: the Phase 7 re-baseline (bench/results/phase7-final), three reps of the port with Rust and Rails measured in the same session, same harness, same seed, server on CPUs 0-3 and load generator on 4-7. The port matched Rust's work per request and beat it 1.18-1.41x at 16 connections. Everything onCrack does is scored from here, against Rust and against this result.

Requests per second, CPU µs per request beneath. Rust was measured in the same run. Rails is the 5b baseline (3 reps), the last time it ran; it doesn't change. Greyed F# values were carried from an earlier run.
Tue 6 Oct, 20:02 EDT · post · tier 2message partial broadcast as UTF-8 (no string), unread ping encoded once, no body parse for mentions when there is no attachment (mean of 3 alternating runs, c=16; allocation 183.6 to 154.1 KB per post)commit 571d25a · mounted build · overall 1.28× of Rust
16 connections1 connection
F#RustRailsF#/RustF#RustRailsF#/Rust
Room page38,60698 µs28,720122 µs2271.34×170× Rails7,524210 µs6,500142 µs1111.16×68× Rails
Messages page37,933102 µs30,230114 µs3901.25×97× Rails8,112200 µs6,981136 µs2091.16×39× Rails
Sidebar36,659104 µs28,378123 µs5811.29×63× Rails7,690188 µs6,366146 µs2681.21×29× Rails
Search33,798108 µs26,606124 µs4101.27×82× Rails5,837322 µs5,638158 µs1891.04×31× Rails
Post a message9,034349 µs7,140389 µs3101.27×29× Rails2,949647 µs2,814399 µs1601.05×18× Rails

What was done

  • 571d25a Post path: broadcast the message partial as UTF-8, encode the unread ping once, skip parsing bodies with no attachments for mentions
Requests per second, CPU µs per request beneath. Rust is the stored Phase 7 starting point. Rails is the 5b baseline (3 reps), the last time it ran; it doesn't change. Greyed F# values were carried from an earlier run.
Tue 6 Oct, 21:52 EDT · post · tier 2verifier fixes: long binds keep the GC transition, mention parse skipped only for bodies of <=800 units, console never coloured (mean of 2 alternating runs; control below)commit 69dc486 · mounted build · overall 1.28× of Rust
16 connections1 connection
F#RustRailsF#/RustF#RustRailsF#/Rust
Room page37,726101 µs28,720122 µs2271.31×166× Rails7,462211 µs6,500142 µs1111.15×67× Rails
Messages page38,174100 µs30,230114 µs3901.26×98× Rails8,238199 µs6,981136 µs2091.18×39× Rails
Sidebar37,900101 µs28,378123 µs5811.34×65× Rails7,822186 µs6,366146 µs2681.23×29× Rails
Search34,017108 µs26,606124 µs4101.28×83× Rails5,906322 µs5,638158 µs1891.05×31× Rails
Post a message8,784354 µs7,140389 µs3101.23×28× Rails3,006637 µs2,814399 µs1601.07×19× Rails

What was done

  • 69dc486 Phase 7 verifier fixes: no console colour, mention parse skipped only for bodies that cannot fail, long binds keep the GC transition
Requests per second, CPU µs per request beneath. Rust is the stored Phase 7 starting point. Rails is the 5b baseline (3 reps), the last time it ran; it doesn't change. Greyed F# values were carried from an earlier run.
Tue 6 Oct, 20:49 EDT · post · tier 3unit 7.4 post and remaining paths: image rebuilt from HEAD with file watching off and the post-path cuts (UTF-8 message broadcast, one unread ping encoding, no mention parse without attachments), five workloads at c=1 and c=16, 3 repscommit 3e321ac · sha256:052d89880648 build · overall 1.28× of Rust
16 connections1 connection
F#RustRailsF#/RustF#RustRailsF#/Rust
Room page37,726101 µs28,720122 µs2271.31×166× Rails7,462211 µs6,500142 µs1111.15×67× Rails
Messages page38,174100 µs30,230114 µs3901.26×98× Rails8,238199 µs6,981136 µs2091.18×39× Rails
Sidebar37,900101 µs28,378123 µs5811.34×65× Rails7,822186 µs6,366146 µs2681.23×29× Rails
Search33,565109 µs26,606124 µs4101.26×82× Rails5,814325 µs5,638158 µs1891.03×31× Rails
Post a message8,892353 µs7,140389 µs3101.25×29× Rails3,060631 µs2,814399 µs1601.09×19× Rails

What was done

No code change since the previous dot (a measurement only).

Requests per second, CPU µs per request beneath. Rust is the stored Phase 7 starting point. Rails is the 5b baseline (3 reps), the last time it ran; it doesn't change. Greyed F# values were carried from an earlier run.
Tue 6 Oct, 19:14 EDT · post · tier 2 · revertedgzip a post answer (9 KB of HTML) and splice pieces through the zlib shim with a window that fits, no dictionary for a short tail: no gain beyond noise, revertedcommit 5c23899 · mounted build · overall 1.28× of Rust
16 connections1 connection
F#RustRailsF#/RustF#RustRailsF#/Rust
Room page38,60698 µs28,720122 µs2271.34×170× Rails7,524210 µs6,500142 µs1111.16×68× Rails
Messages page37,933102 µs30,230114 µs3901.25×97× Rails8,112200 µs6,981136 µs2091.16×39× Rails
Sidebar36,659104 µs28,378123 µs5811.29×63× Rails7,690188 µs6,366146 µs2681.21×29× Rails
Search33,798108 µs26,606124 µs4101.27×82× Rails5,837322 µs5,638158 µs1891.04×31× Rails
Post a message8,852356 µs7,140389 µs3101.24×29× Rails2,985644 µs2,814399 µs1601.06×19× Rails

What was done

  • 5c23899 Deflate small gzip bodies and splice pieces through the zlib shim; no dictionary for a short tail after a fragment
Requests per second, CPU µs per request beneath. Rust is the stored Phase 7 starting point. Rails is the 5b baseline (3 reps), the last time it ran; it doesn't change. Greyed F# values were carried from an earlier run.
Tue 6 Oct, 18:51 EDT · post · tier 2default host no longer watches the content root for appsettings changes (File Watch thread and lstat), post c=16 and c=1, 1 repcommit bc80d28 · mounted build · overall 1.28× of Rust
16 connections1 connection
F#RustRailsF#/RustF#RustRailsF#/Rust
Room page38,60698 µs28,720122 µs2271.34×170× Rails7,524210 µs6,500142 µs1111.16×68× Rails
Messages page37,933102 µs30,230114 µs3901.25×97× Rails8,112200 µs6,981136 µs2091.16×39× Rails
Sidebar36,659104 µs28,378123 µs5811.29×63× Rails7,690188 µs6,366146 µs2681.21×29× Rails
Search33,798108 µs26,606124 µs4101.27×82× Rails5,837322 µs5,638158 µs1891.04×31× Rails
Post a message8,796358 µs7,140389 µs3101.23×28× Rails2,949647 µs2,814399 µs1601.05×18× Rails

What was done

  • bc80d28 Front: do not watch the content root for appsettings changes
Requests per second, CPU µs per request beneath. Rust is the stored Phase 7 starting point. Rails is the 5b baseline (3 reps), the last time it ran; it doesn't change. Greyed F# values were carried from an earlier run.
Tue 6 Oct, 19:17 EDT · post · tier 2control for the identity body work: the 416 KB room page with Accept-Encoding: identity at c=16 on the unchanged build (identity numbers are logged under room_show_identity; the chart does not show them)commit 5bb1dd5 · mounted build · overall 1.28× of Rust
16 connections1 connection
F#RustRailsF#/RustF#RustRailsF#/Rust
Room page38,60698 µs28,720122 µs2271.34×170× Rails7,524210 µs6,500142 µs1111.16×68× Rails
Messages page37,933102 µs30,230114 µs3901.25×97× Rails8,112200 µs6,981136 µs2091.16×39× Rails
Sidebar36,659104 µs28,378123 µs5811.29×63× Rails7,690188 µs6,366146 µs2681.21×29× Rails
Search33,798108 µs26,606124 µs4101.27×82× Rails5,837322 µs5,638158 µs1891.04×31× Rails
Post a message8,796358 µs7,140389 µs3101.23×28× Rails2,949647 µs2,814399 µs1601.05×18× Rails

What was done

  • 5c23899 Deflate small gzip bodies and splice pieces through the zlib shim; no dictionary for a short tail after a fragment
  • f18616d Revert "Deflate small gzip bodies and splice pieces through the zlib shim"
Requests per second, CPU µs per request beneath. Rust is the stored Phase 7 starting point. Rails is the 5b baseline (3 reps), the last time it ran; it doesn't change. Greyed F# values were carried from an earlier run.
Tue 6 Oct, 19:40 EDT · post · tier 2A/B in one build: Kestrel's own 4 KB blocks (CAMPFIRE_NO_CONN_POOL, mean of 2), identity room page c=16commit dcb5ffa · mounted build · overall 1.28× of Rust
16 connections1 connection
F#RustRailsF#/RustF#RustRailsF#/Rust
Room page38,60698 µs28,720122 µs2271.34×170× Rails7,524210 µs6,500142 µs1111.16×68× Rails
Messages page37,933102 µs30,230114 µs3901.25×97× Rails8,112200 µs6,981136 µs2091.16×39× Rails
Sidebar36,659104 µs28,378123 µs5811.29×63× Rails7,690188 µs6,366146 µs2681.21×29× Rails
Search33,798108 µs26,606124 µs4101.27×82× Rails5,837322 µs5,638158 µs1891.04×31× Rails
Post a message8,796358 µs7,140389 µs3101.23×28× Rails2,949647 µs2,814399 µs1601.05×18× Rails

What was done

  • dcb5ffa Kestrel connection pipes get 64 KB segments for large bodies
Requests per second, CPU µs per request beneath. Rust is the stored Phase 7 starting point. Rails is the 5b baseline (3 reps), the last time it ran; it doesn't change. Greyed F# values were carried from an earlier run.
Tue 6 Oct, 20:02 EDT · post · tier 2control for the post path A/B: file watching off, nothing else (mean of 3 alternating runs, c=16)commit 3b88200 · mounted build · overall 1.28× of Rust
16 connections1 connection
F#RustRailsF#/RustF#RustRailsF#/Rust
Room page38,60698 µs28,720122 µs2271.34×170× Rails7,524210 µs6,500142 µs1111.16×68× Rails
Messages page37,933102 µs30,230114 µs3901.25×97× Rails8,112200 µs6,981136 µs2091.16×39× Rails
Sidebar36,659104 µs28,378123 µs5811.29×63× Rails7,690188 µs6,366146 µs2681.21×29× Rails
Search33,798108 µs26,606124 µs4101.27×82× Rails5,837322 µs5,638158 µs1891.04×31× Rails
Post a message8,747357 µs7,140389 µs3101.22×28× Rails2,949647 µs2,814399 µs1601.05×18× Rails

What was done

  • f849119 Revert "Kestrel connection pipes get 64 KB segments for large bodies"
Requests per second, CPU µs per request beneath. Rust is the stored Phase 7 starting point. Rails is the 5b baseline (3 reps), the last time it ran; it doesn't change. Greyed F# values were carried from an earlier run.
Tue 6 Oct, 18:42 EDT · crypto-logging · tier 3unit 7.3 crypto-logging: image rebuilt from HEAD with keyed HMAC/AES state, hand parsers, token memo and the batched request log, five workloads at c=1 and c=16, 3 repscommit b1d55bf · sha256:53ce6520c2c2 build · overall 1.26× of Rust
16 connections1 connection
F#RustRailsF#/RustF#RustRailsF#/Rust
Room page38,60698 µs28,720122 µs2271.34×170× Rails7,524210 µs6,500142 µs1111.16×68× Rails
Messages page37,933102 µs30,230114 µs3901.25×97× Rails8,112200 µs6,981136 µs2091.16×39× Rails
Sidebar36,659104 µs28,378123 µs5811.29×63× Rails7,690188 µs6,366146 µs2681.21×29× Rails
Search33,798108 µs26,606124 µs4101.27×82× Rails5,837322 µs5,638158 µs1891.04×31× Rails
Post a message8,108396 µs7,140389 µs3101.14×26× Rails2,727697 µs2,814399 µs1600.97×17× Rails

What was done

No code change since the previous dot (a measurement only).

Requests per second, CPU µs per request beneath. Rust is the stored Phase 7 starting point. Rails is the 5b baseline (3 reps), the last time it ran; it doesn't change. Greyed F# values were carried from an earlier run.
Tue 6 Oct, 17:55 EDT · crypto-logging · tier 2both halves at one connection (c=1)commit 0b67670 · mounted build · overall 1.20× of Rust
16 connections1 connection
F#RustRailsF#/RustF#RustRailsF#/Rust
Room page39,42496 µs28,720122 µs2271.37×174× Rails7,405213 µs6,500142 µs1111.14×67× Rails
Messages page33,229116 µs30,230114 µs3901.10×85× Rails6,293229 µs6,981136 µs2090.90×30× Rails
Sidebar38,35999 µs28,378123 µs5811.35×66× Rails7,612192 µs6,366146 µs2681.20×28× Rails
Search32,737114 µs26,606124 µs4101.23×80× Rails5,820327 µs5,638158 µs1891.03×31× Rails
Post a message7,186441 µs7,140389 µs3101.01×23× Rails2,275809 µs2,814399 µs1600.81×14× Rails

What was done

  • 0b67670 Write the request log line as UTF-8 into a batch instead of through ILogger
Requests per second, CPU µs per request beneath. Rust is the stored Phase 7 starting point. Rails is the 5b baseline (3 reps), the last time it ran; it doesn't change. Greyed F# values were carried from an earlier run.
Tue 6 Oct, 17:54 EDT · crypto-logging · tier 2keyed HMAC and AES state per thread, hand parsers for the expiry and the cookie envelope, remembered avatar tokens and stream names (crypto half, c=16)commit a696844 · mounted build · overall 1.11× of Rust
16 connections1 connection
F#RustRailsF#/RustF#RustRailsF#/Rust
Room page33,436112 µs28,720122 µs2271.16×147× Rails5,654252 µs6,500142 µs1110.87×51× Rails
Messages page33,229116 µs30,230114 µs3901.10×85× Rails6,293229 µs6,981136 µs2090.90×30× Rails
Sidebar33,614114 µs28,378123 µs5811.18×58× Rails5,336266 µs6,366146 µs2680.84×20× Rails
Search29,413129 µs26,606124 µs4101.11×72× Rails4,695375 µs5,638158 µs1890.83×25× Rails
Post a message7,186441 µs7,140389 µs3101.01×23× Rails2,275809 µs2,814399 µs1600.81×14× Rails

What was done

  • af0ced4 Stamp each logged run with the commit its build came from
  • a696844 Cache keyed HMAC and AES state per thread, parse envelopes without the regex or JSON parser, remember avatar tokens
Requests per second, CPU µs per request beneath. Rust is the stored Phase 7 starting point. Rails is the 5b baseline (3 reps), the last time it ran; it doesn't change. Greyed F# values were carried from an earlier run.
Tue 6 Oct, 16:50 EDT · runtime · tier 3unit 7.2 runtime: image rebuilt from HEAD with the 64MB gen0 budget and the allocation cuts, five workloads at c=1 and c=16, 3 repscommit 1d0f3b2 · sha256:e316ad01e8ed build · overall 1.05× of Rust
16 connections1 connection
F#RustRailsF#/RustF#RustRailsF#/Rust
Room page30,672124 µs28,720122 µs2271.07×135× Rails5,654252 µs6,500142 µs1110.87×51× Rails
Messages page33,229116 µs30,230114 µs3901.10×85× Rails6,293229 µs6,981136 µs2090.90×30× Rails
Sidebar28,192135 µs28,378123 µs5810.99×48× Rails5,336266 µs6,366146 µs2680.84×20× Rails
Search28,713128 µs26,606124 µs4101.08×70× Rails4,695375 µs5,638158 µs1890.83×25× Rails
Post a message7,186441 µs7,140389 µs3101.01×23× Rails2,275809 µs2,814399 µs1600.81×14× Rails

What was done

  • b31452b Do not ship DOTNET_ThreadPool_UnfairSemaphoreSpinLimit=0: it costs messages and search 10-14% at c=16
  • 1d0f3b2 Dockerfile: say only what was measured about the gen0 budget
Requests per second, CPU µs per request beneath. Rust is the stored Phase 7 starting point. Rails is the 5b baseline (3 reps), the last time it ran; it doesn't change. Greyed F# values were carried from an earlier run.
Tue 6 Oct, 16:11 EDT · runtime · tier 2A/B: default spin limit on the new image, run Bcommit 0e564f3 · sha256:9e87cfde74c3 build · overall 1.03× of Rust
16 connections1 connection
F#RustRailsF#/RustF#RustRailsF#/Rust
Room page28,701117 µs28,720122 µs2271.00×126× Rails5,589258 µs6,500142 µs1110.86×50× Rails
Messages page33,771113 µs30,230114 µs3901.12×87× Rails6,096243 µs6,981136 µs2090.87×29× Rails
Sidebar27,012129 µs28,378123 µs5810.95×46× Rails5,177278 µs6,366146 µs2680.81×19× Rails
Search29,233131 µs26,606124 µs4101.10×71× Rails4,855364 µs5,638158 µs1890.86×26× Rails
Post a message7,004452 µs7,140389 µs3100.98×23× Rails2,328783 µs2,814399 µs1600.83×15× Rails

What was done

  • dcb8032 Ship the runtime settings of unit 7.2: no thread-pool spinning, a 64 MiB gen0 budget; hoist sanitizeTags' allowlist
Requests per second, CPU µs per request beneath. Rust is the stored Phase 7 starting point. Rails is the 5b baseline (3 reps), the last time it ran; it doesn't change. Greyed F# values were carried from an earlier run.
Tue 6 Oct, 13:17 EDT · database · tier 3unit 7.1 database path: image rebuilt from HEAD, five workloads at c=1 and c=16, 3 repscommit df6ffd9 · sha256:5b3be84342fe build · overall 1.00× of Rust
16 connections1 connection
F#RustRailsF#/RustF#RustRailsF#/Rust
Room page28,328136 µs28,720122 µs2270.99×125× Rails5,589258 µs6,500142 µs1110.86×50× Rails
Messages page31,066124 µs30,230114 µs3901.03×80× Rails6,096243 µs6,981136 µs2090.87×29× Rails
Sidebar27,356142 µs28,378123 µs5810.96×47× Rails5,177278 µs6,366146 µs2680.81×19× Rails
Search27,801134 µs26,606124 µs4101.04×68× Rails4,855364 µs5,638158 µs1890.86×26× Rails
Post a message7,004452 µs7,140389 µs3100.98×23× Rails2,328783 µs2,814399 µs1600.83×15× Rails

What was done

  • c9964b3 Db: find a cached statement by a hash of its length and sixteen characters, and build the row list without an enumerator
  • d7ce54c Db: say why a read no longer yields
Requests per second, CPU µs per request beneath. Rust is the stored Phase 7 starting point. Rails is the 5b baseline (3 reps), the last time it ran; it doesn't change. Greyed F# values were carried from an earlier run.
Tue 6 Oct, 15:18 EDT · runtime · tier 2allocation cuts: gzip written into the pipe, to_i fast path, key buffer reuse, assetPath and preload-link memo (room 146 to 113 KB per request)commit 2e0f663 · mounted build · overall 0.98× of Rust
16 connections1 connection
F#RustRailsF#/RustF#RustRailsF#/Rust
Room page28,701117 µs28,720122 µs2271.00×126× Rails5,589258 µs6,500142 µs1110.86×50× Rails
Messages page30,267110 µs30,230114 µs3901.00×78× Rails6,096243 µs6,981136 µs2090.87×29× Rails
Sidebar27,012129 µs28,378123 µs5810.95×46× Rails5,177278 µs6,366146 µs2680.81×19× Rails
Search25,864129 µs26,606124 µs4100.97×63× Rails4,855364 µs5,638158 µs1890.86×26× Rails
Post a message7,004452 µs7,140389 µs3100.98×23× Rails2,328783 µs2,814399 µs1600.83×15× Rails

What was done

  • 2e0f663 Cut per-request allocation on the page paths (146 to 113 KB room, 121 to 82 KB messages)
Requests per second, CPU µs per request beneath. Rust is the stored Phase 7 starting point. Rails is the 5b baseline (3 reps), the last time it ran; it doesn't change. Greyed F# values were carried from an earlier run.
Tue 6 Oct, 12:24 EDT · database · tier 2a read that found a free connection returns without Task.Yield (no cross-thread hand-off per read)commit 15b1376 · mounted build · overall 0.96× of Rust
16 connections1 connection
F#RustRailsF#/RustF#RustRailsF#/Rust
Room page27,240141 µs28,720122 µs2270.95×120× Rails5,405264 µs6,500142 µs1110.83×49× Rails
Messages page28,704126 µs30,230114 µs3900.95×74× Rails4,227449 µs6,981136 µs2090.61×20× Rails
Sidebar26,888143 µs28,378123 µs5810.95×46× Rails5,175275 µs6,366146 µs2680.81×19× Rails
Search26,034146 µs26,606124 µs4100.98×63× Rails4,158454 µs5,638158 µs1890.74×22× Rails
Post a message6,940467 µs7,140389 µs3100.97×22× Rails1,933990 µs2,814399 µs1600.69×12× Rails

What was done

  • 15b1376 Db: a read that found a free connection returns its result without yielding (experiment)
Requests per second, CPU µs per request beneath. Rust is the stored Phase 7 starting point. Rails is the 5b baseline (3 reps), the last time it ran; it doesn't change. Greyed F# values were carried from an earlier run.
Tue 6 Oct, 12:18 EDT · database · tier 2no per-connection or memstatus mutex, direct C-API calls for rows and binds, timestamps parsed from UTF-8 bytescommit b7f020f · mounted build · overall 0.94× of Rust
16 connections1 connection
F#RustRailsF#/RustF#RustRailsF#/Rust
Room page25,851141 µs28,720122 µs2270.90×114× Rails3,885453 µs6,500142 µs1110.60×35× Rails
Messages page28,704126 µs30,230114 µs3900.95×74× Rails4,227449 µs6,981136 µs2090.61×20× Rails
Sidebar24,993151 µs28,378123 µs5810.88×43× Rails3,909449 µs6,366146 µs2680.61×15× Rails
Search26,034146 µs26,606124 µs4100.98×63× Rails4,158454 µs5,638158 µs1890.74×22× Rails
Post a message6,940467 µs7,140389 µs3100.97×22× Rails1,933990 µs2,814399 µs1600.69×12× Rails

What was done

  • 286c2ca Db: SQLite without the per-connection and memory-statistics mutexes
  • b7f020f Db: call the hot SQLite functions directly, and read timestamps from the bytes SQLite holds
Requests per second, CPU µs per request beneath. Rust is the stored Phase 7 starting point. Rails is the 5b baseline (3 reps), the last time it ran; it doesn't change. Greyed F# values were carried from an earlier run.
Tue 6 Oct, 11:58 EDT · database · tier 2statements through SQLitePCLRaw (prepare once, bind by index, columns by ordinal) instead of Microsoft.Data.Sqlite commandscommit 5d2a8aa · mounted build · overall 0.81× of Rust
16 connections1 connection
F#RustRailsF#/RustF#RustRailsF#/Rust
Room page21,892173 µs28,720122 µs2270.76×96× Rails3,885453 µs6,500142 µs1110.60×35× Rails
Messages page23,346161 µs30,230114 µs3900.77×60× Rails4,227449 µs6,981136 µs2090.61×20× Rails
Sidebar23,107162 µs28,378123 µs5810.81×40× Rails3,909449 µs6,366146 µs2680.61×15× Rails
Search23,082159 µs26,606124 µs4100.87×56× Rails4,158454 µs5,638158 µs1890.74×22× Rails
Post a message6,046549 µs7,140389 µs3100.85×19× Rails1,958998 µs2,814399 µs1600.70×12× Rails

What was done

  • 5d2a8aa Db: run statements through SQLitePCLRaw instead of Microsoft.Data.Sqlite commands
Requests per second, CPU µs per request beneath. Rust is the stored Phase 7 starting point. Rails is the 5b baseline (3 reps), the last time it ran; it doesn't change. Greyed F# values were carried from an earlier run.
Tue 6 Oct, 03:16 EDT · baseline · tier 5bWhole-app baseline: bench/run, Rails vs Rust vs F#, 3 repscommit 794dc8b · image e111a4e (2 s warm-up) build · overall 0.79× of Rust
16 connections1 connection
F#RustRailsF#/RustF#RustRailsF#/Rust
Room page21,003– µs28,135– µs2270.75×92× Rails3,329– µs6,310– µs1110.53×30× Rails
Messages page23,097– µs29,406– µs3900.79×59× Rails4,044– µs6,625– µs2090.61×19× Rails
Sidebar19,115– µs27,938– µs5810.68×33× Rails3,738– µs6,116– µs2680.61×14× Rails
Search19,411– µs26,049– µs4100.75×47× Rails3,922– µs5,491– µs1890.71×21× Rails
Post a message6,186– µs6,082– µs3101.02×20× Rails1,909– µs2,727– µs1600.70×12× Rails

What was done

Plan step 5b, before any tuning. bench/run in the colima VM with the server pinned to CPUs 0-3 and the load generator to 4-7, host networking, 3 reps per app, every response checked (all 200), every post's row counted, decoded bytes identical to Rust's. A skeptical Opus review re-ran it and trimmed F#'s c=16 ratios slightly (room 0.71, messages 0.74) and flagged the 2 s warm-up, which the Phase 7 harness then lengthened. Falco measured at about 29 ns a request.

Requests per second, CPU µs per request beneath. Rust was measured in the same run. Rails is the 5b baseline (3 reps), the last time it ran; it doesn't change. Greyed F# values were carried from an earlier run.
Tue 6 Oct, 01:00 EDT · phase 5 · tier quickFirst whole-app run: the F# port boots and serves all five workloadscommit 72b938e · image (Docker port, wrk) build · overall 0.76× of Rust
16 connections1 connection
F#RustRailsF#/RustF#RustRailsF#/Rust
Room page9,130– µs11,285– µs2270.81×40× Rails1,665– µs2,487– µs1110.67×15× Rails
Messages page9,350– µs12,452– µs3900.75×24× Rails2,079– µs2,673– µs2090.78×10× Rails
Sidebar10,404– µs14,237– µs5810.73×18× Rails2,263– µs2,879– µs2680.79×8× Rails
Search4,321– µs5,650– µs4100.76×11× Rails1,722– µs2,095– µs1890.82×9× Rails
Post a message427– µs554– µs3100.77×1× Rails311– µs449– µs1600.69×2× Rails

What was done

Unit 5.3 ported the room, message, boost, bot API and search controllers, wired to the fragment cache and gzip-spliced page parts as in Rust. A quick wrk check, 6 s per path, through Docker's published port on the Mac (so it includes the port proxy and is not the benchmark method), F# then Rust, each on a fresh default seed. Rough, but the first time the real port faced Rust end to end.

Requests per second, CPU µs per request beneath. Rust was measured in the same run. Rails is the 5b baseline (3 reps), the last time it ran; it doesn't change. Greyed F# values were carried from an earlier run.
Tue 6 Oct, 10:25 EDT · phase 7 start · tier 3Phase 7 starting point: the trustworthy harness, before any tuningcommit 5cc5ba4 · image, 3 reps build · overall 0.76× of Rust
16 connections1 connection
F#RustRailsF#/RustF#RustRailsF#/Rust
Room page21,892173 µs28,720122 µs2270.76×96× Rails3,885453 µs6,500142 µs1110.60×35× Rails
Messages page23,346161 µs30,230114 µs3900.77×60× Rails4,227449 µs6,981136 µs2090.61×20× Rails
Sidebar18,888200 µs28,378123 µs5810.67×32× Rails3,837443 µs6,366146 µs2680.60×14× Rails
Search20,026184 µs26,606124 µs4100.75×49× Rails3,990468 µs5,638158 µs1890.71×21× Rails
Post a message6,046549 µs7,140389 µs3100.85×19× Rails1,958998 µs2,814399 µs1600.70×12× Rails

What was done

Unit 7.0 rebuilt the measuring before anyone optimized: container logs capped, every route warmed for at least 30 s until flat within 3%, the host's pinned CPUs probed before each window, CPU per request from the container's cgroup, and bench/quick for Rust and F# only. Rust was measured here once more, and these Rust medians are the stored reference every later dot compares against.

Requests per second, CPU µs per request beneath. Rust is the stored Phase 7 starting point. Rails is the 5b baseline (3 reps), the last time it ran; it doesn't change. Greyed F# values were carried from an earlier run.
The climb on this project's own suite, over pinned Rust (ccece30, stored medians): one dot per logged version, geometric mean of the five workloads at 16 connections, left to right in the order they ran, clock time under the dots. The F# port's own climb is dotted; onCrack forks from its final re-baseline (1.30×). Rounds one and two had only the cached decision; the default became fresh authorization in round three, so the fresh line branches there (the dotted join is not a measurement). Latest: fresh 4.63×, cached 4.90×. Round three's two dots were measured in round five, on the same day as round five's, and sit at round three's close: round three logged none of its own. Round four logged nothing on this suite and its final image was never measured on it. C was never run on this suite, so it has no line; Rails sits on the floor. The table below is the comparable headline: current Rust and C on upstream's harness. Hover or tap a dot for what was done and the numbers.Every dot, as a table
  1. Port, the build 6 Oct

    Translate it.

    The Rust port, crate by crate, into F# on ASP.NET Core and Falco: database, rich text, the kit, the views, the app.

    Closing headline. First baseline: 0.68–0.79× Rust on the four reads, 1.02× on posts, 20–92× Rails (at 16 connections).

    On the chart at its close: the port 0.79×.

  2. Port, the tuning 6 Oct – 7 Oct

    Match Rust's profile.

    Parity first, then tuning against Rust's own profile: cookies, bodies, row reads, Cable fan-out. Published as the F# port; onCrack forks from its last dot.

    Closing headline. Final re-baseline: 1.24–1.33× Rust at 16 connections.

    On the chart at its close: the port 1.32×.

  3. Round one 7 Oct – 8 Oct

    Keep finished pages.

    Same pixels, unhinged work per request: a versioned read cache, group commit, Content-Length on gzipped answers, Native AOT as an opt-in.

    Closing headline. 3.84× Rust and 2.89× the port at 16 connections: a result in which every read was a cache hit.

    On the chart at its close: cached 3.82×.

  4. Round two 8 Oct – 9 Oct

    Make the benchmark honest, then go faster.

    A benchmark that writes while it reads, Cable on its own socket, a front-server fast path, memory and cold start. It ended against upstream's own harness.

    Closing headline. 3.25× Rust, 2.37× C and 3.93× the port on upstream's harness, with the cached decision, which is not upstream's contract.

    On the chart at its close: cached 4.98×.

  5. Round three 9 Oct

    Check who is asking, every time.

    Fresh authorization on every cache hit became the default (R3.2), search by message id as upstream's (R3.3). The cached decision stays an opt-in.

    Closing headline. Fresh: 2.59× Rust, 1.86× C, 3.82× the port on upstream's harness (two sessions pooled: 2.68× and 3.33× on their own).

    On the chart, its final image measured in round five: fresh 4.32×, cached 4.64×.

  6. Round four

    Fan-out, and keep every subscriber.

    Gather writes (one sendmsg over the frames) and Cable reliability: a shared byte-bounded log, a cut for a stall and not for slowness, a gate that slows the posters. The fan-out lead at the largest room was withdrawn.

    Closing headline. 3.29× Rust, 2.40× C on one session; fan-out 1.59×, 1.24×, 1.16× and 0.94× Rust at 100, 500, 1,000 and 2,000 clients.

    No dot: nothing was logged on this suite in round four.

  7. Round five 13 Oct

    Find the one message.

    The one message that did not arrive was a compiler turning a recursion into a loop in the gather's pinning: found by reading the IL, fixed, tested. The memory bound now covers every chunk. Then the final gates and runs.

    Closing headline. 3.76× Rust, 2.40× C, 5.25× the port on upstream's harness, across sessions of 2.11× to 4.74×; no client cut in PR #6.

    On the chart at its close: fresh 4.63×, cached 4.90×.

What changed in each iteration, in full Every dot's own card lists the commits behind it.

Requests/sec, 16 clientsonCrack÷ Rust÷ CRust f9dca47C cd0cbe4F# portonCrack, cached decision (opt-in)
Room page153,6604.99×2.26×30,80667,94717,109154,260
Messages page155,2054.35×2.10×35,69673,88026,722172,052
Sidebar169,1164.17×2.45×40,53269,07422,901180,585
Search164,9284.73×2.77×34,83359,60023,587170,166
Post a message8,7261.74×2.48×5,0013,5175,90912,289
Current upstream, their method, their contract. once-campfire-verification's bin/benchmark: the median of every round of 3 sessions, 9 rounds a cell, of 8 s at 16 clients, every response validated against the seed, every acknowledged post audited in the database and its search index; four server CPUs and four for the load generator, on this project's VM, not their Ryzen. onCrack re-reads the session and the room membership on every cache hit, as upstream's implementations do; its older cached decision, faster and not comparable, is the last column and an opt-in. Other work on the Mac moves every engine's samples from one session to the next, so read the ranges in the details. onCrack's search lists the newest matches by message id, as upstream's does and its contract checks (round three, unit R3.3); the port keeps Rails 90b3300's order.The details
The All Talk room, signed in as David: the page Rails, Rust, the F# port and onCrack each render to these same pixels.
Same pixelsOne screenshot, because the four are one: the parity harness's captures of this page from Rails, Rust, the port and onCrack are byte-identical.

Same pixels, four engines · the room page · round one, pinned Rust ccece30

Same software.

  1. Railsslowthe original

    233requests a secondserved while you watch, at 233 a second

  2. Rustfast123× Rails

    28,582requests a secondserved while you watch, at 28,582 a second

  3. F# portfaster1.38× Rust

    39,459requests a secondserved while you watch, at 39,459 a second

  4. onCrackcached4.34× Rust · 3.14× the port

    123,942requests a secondserved while you watch, at 123,942 a second

onCrack's row is cache hits. The benchmark asks for one page over and over and never writes, so onCrack serves it from a stored copy. With the room being written to, the lead is 2.30× Rust, not 4.34×.

Each counter ticks at that engine's measured rate for this page, signed in, at 16 connections, all four in the same session.How we know

The honest version · round one, pinned Rust ccece30

Cache hits, and the other end.

A stored page is only as good as the writes that don't touch it. So the same room page was read at 16 connections while one more connection posted into that very room as fast as each app would take it: about 1,100 posts a second, each one invalidating the page.

4.34×Rust, reads onlybench/run; every request a cache hit
  1. Rust28,582
  2. F# port39,459
  3. onCrack123,942
2.30×Rust, reads while the room is written to1.75× the port · its posts in the same window: 1.63× Rust
  1. Rust18,619
  2. F# port24,372
  3. onCrack42,752

Room page reads a second at 16 connections, same scale in both. How it was measured

Fan-out

One message, a thousand clients.

A post goes out over Action Cable to everyone in the room. onCrack delivers 1.65× Rust's messages a second at 100 clients, 1.24× at 500 and 1.17× at 1,000: ahead, with every rep of onCrack above every rep of Rust in the one quiet session of the three. At 2,000 clients it is 1.01×, level, not ahead: the reps overlap and both servers are bound by the sendmsg syscall. Every message reached every client in every one of the 140 Cable phases of the final run.

  1. RustRust

    4,155 messages a second to all of them

    415,503 deliveries a second

  2. F# port0.82× Rust

    3,407 messages a second to all of them

    340,689 deliveries a second · falls behind Rust by 748 messages every second

  3. onCrack1.65× Rust

    6,859 messages a second to all of them

    685,873 deliveries a second

Each dot is 10 clients; each pulse is 1,000 messages, leaving at the app's measured rate.

  1. RustRust

    2,625 messages a second to all of them

    1,312,536 deliveries a second

  2. F# port0.38× Rust

    995 messages a second to all of them

    497,355 deliveries a second · falls behind Rust by 1,630 messages every second

  3. onCrack1.24× Rust

    3,251 messages a second to all of them

    1,625,422 deliveries a second

Each dot is 10 clients; each pulse is 500 messages, leaving at the app's measured rate.

  1. RustRust

    1,706 messages a second to all of them

    1,705,668 deliveries a second

  2. F# port0.27× Rust

    464 messages a second to all of them

    464,004 deliveries a second · falls behind Rust by 1,242 messages every second

  3. onCrack1.17× Rust

    1,995 messages a second to all of them

    1,995,150 deliveries a second

Each dot is 10 clients; each pulse is 500 messages, leaving at the app's measured rate.

  1. RustRust

    1,054 messages a second to all of them

    2,108,262 deliveries a second

  2. F# port0.20× Rust

    211 messages a second to all of them

    422,711 deliveries a second · falls behind Rust by 843 messages every second

  3. onCrack1.01× Rust

    1,067 messages a second to all of them

    2,134,176 deliveries a second

Each dot is 20 clients; each pulse is 200 messages, leaving at the app's measured rate.

Where it came from

Start with the port.

onCrack is a fork. The F# port is the faithful one: the same work per request as the Rust port, translated module by module, and still 1.33× Rust at 16 connections in this session. If you want to read how Campfire works in F#, read that.