build: use ucontext coroutines instead of pthreads on Linux and arm64 - #3
Closed
jbaczuk-qualia wants to merge 2 commits into
Closed
jbaczuk-qualia wants to merge 2 commits into
jbaczuk-qualia wants to merge 2 commits into
Conversation
fibers ships prebuilt binaries for linux-x64 only, so every arm64 host (production Graviton nodes, the arm64 CI runners, M-series dev containers) compiles from source and lands in the CORO_PTHREAD branch of binding.gyp, where each fiber is an OS thread and each switch is a pthread condvar handoff. On the same node 18.16.1 arm64 host a run()/yield() round trip costs 12.7 us p50 with pthreads and 0.71 us with swapcontext, and the pthread build shows the same ~9x in Meteor's fiber_yield_switch_seconds histogram. glibc implements swapcontext on aarch64; the "problems getting real fibers working on arm" comment predates arm64. Linux now picks CORO_UCONTEXT on glibc and CORO_ASM on musl (upstream's conditions), and the arm/arm64 blocks select CORO_UCONTEXT explicitly. Test suite on node 18.16.1 arm64: 18/19 with ucontext (pool.js and cleanup.js now pass) versus 16/19 with pthreads; future-exception.js fails on both. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
5.0.5 is already published (@meteor/blaze depends on ^5.0.5), so the ucontext build needs a new version before it can be released. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Author
|
Closed 2026-09-21, kept for posterity. Switching arm64 production from |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Production runs arm64 (a prod pod has
node_modules/fibers/bin/linux-arm64-108-glibc, which only exists when npm compiled fibers from source: the published package shipslinux-x64prebuilts only). On arm64binding.gypselectsCORO_PTHREAD, so every fiber is an OS thread and everyFiber.yield()/run()is a pthread condvar handoff between two threads. The same applies to the arm64 CI runners and to M-series dev containers.This switches Linux to
CORO_UCONTEXTon glibc (CORO_ASMon musl, upstream's conditions) and makes the arm/arm64 blocks selectCORO_UCONTEXTexplicitly. glibc implementsswapcontexton aarch64; the "problems getting real fibers working on arm" comment predates arm64. Independent of the node 24 work in #2 (this is the samebinding.gypchange, cherry-picked ontoasync-resource).Numbers (node 18.16.1, arm64, same host)
Pure switch microbenchmark, 200k
run()/yield()round trips:CORO_PTHREAD)CORO_UCONTEXT)In
global-deployment-centerwith@qualia/prom-client'sfiber_yield_switch_seconds(qualialabs/qualia#56265), the pthread build measured 18 µs p50 / 577 µs p99 per switch during a manual click-through; the ucontext build on node 24 measured 2.0 µs / 48 µs on a similar workload. Beyond latency, pthread mode also costs one OS thread and one kernel context switch per fiber.Verification
test/*.json node 18.16.1 arm64: 18/19 with ucontext (pool.jsandcleanup.jsnow pass) versus 16/19 with the pthread build;future-exception.jsfails on both.nodejs-dev:f031bb860eimage): suite 18/19 vs 16/19, switch p50 2.49 µs vs 14.0 µs, GC stress (--stress-incremental-marking --stress-compaction) 150 rounds clean on both backends, 200k-yield leak check flat on both. Production is Graviton4 (Neoverse V2), which only widens the gap.Rollout
5.0.5is already published (@meteor/blazedepends on^5.0.5), so5422b70bumps this branch to5.0.6. Publishing it makes every^5.0.4/^5.0.5consumer pick up the ucontext build on its next lockfile refresh; arm64 consumers compile from source at install time (no arm64 prebuilt is published), so the change takes effect on the nextnpm installin CI and in each service's Docker build. Intended, but it should follow the Lucky run above and ideally a canary on one Graviton4 pod.🤖 Generated with Claude Code