Skip to content

store: read with libc pread by default on macOS - #1058

Merged
reardencode merged 1 commit into
reardencode:masterfrom
smolcars:store/darwin-pread-default
Oct 17, 2026
Merged

reardencode merged 1 commit into
reardencode:masterfrom
smolcars:store/darwin-pread-default

Conversation

@niteshbalusu11

Copy link
Copy Markdown
Contributor

Summary

macOS has no io_uring. Its only completion session is a worker pool: each read takes one shared lock, wakes a pool thread, then wakes the caller. During IBD most reads are small and often cached, so that handoff costs more than the read. This makes libc pread the macOS default.

 io_uring_enabled()   (RBITCOIN_IO unset)
-  every OS: open the completion session (macOS: worker pool)
+  Linux / Windows: unchanged (io_uring / IOCP)
+  macOS: no session, libc pread on the calling thread
 RBITCOIN_IO=pool
   still opens the pool session on any OS

Evidence

Signet IBD to 326,785 from one local peer, scripts skipped, all indexes on, 10-core Mac. Same binary, only RBITCOIN_IO changes. Same tip hash in every run.

pool (old default) pread (new default)
Warm, 2 runs 639 / 661 s 539 / 528 s (18% faster)
Cold, resume from 250,875 after a cache flush, 2 runs 355 / 351 s 275 / 281 s (21% faster)
System CPU (warm) ~1,480 s ~380 s
  • Before: unset_io_env_opens_a_session_except_on_darwin fails on master ("Darwin defaults to libc pread").
    After: passes. fmt, clippy, deny, ast-grep, os-smoke, and the os-smoke self-test pass locally. Workspace tests pass except three that also fail on master on this Mac.
  • ci-os-smoke.sh now pins bulk_io::tests::unset_io_env_opens_a_session on every OS; the old default_kind_follows_os test now only exists on Linux and Windows, so only the Windows smoke lists it.

Merge Danger

Door: two-way

Revert, or set RBITCOIN_IO=pool, to get the old macOS reads back. No schema, on-disk, durability, or consensus change.

Blast Radius: macOS

Every store reader on macOS (IBD, Electrum, Esplora, RPC) uses pread. Linux and Windows are unchanged. Not measured: heavy serving load on macOS.

🤖 Generated with Claude Code

macOS has no io_uring. Its only completion session is a worker pool that
hands every read to a pool thread through one shared lock and wakes two
threads per read. During IBD most reads are small and often cached, so the
handoff cost more than the read.

Signet to 326,785 on a 10-core Mac, scripts skipped, all indexes:
- warm: pool 639/661 s, pread 539/528 s (about 18% faster)
- cold (resume from 250,875 after a cache flush): pool 355/351 s,
  pread 275/281 s (about 21% faster)
- system CPU drops about four times; same tip hash every run

RBITCOIN_IO=pool still opens the pool session. Linux and Windows defaults
are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@reardencode

Copy link
Copy Markdown
Owner

Very interesting results. I wonder if we'll need to go deeper on this to get good performance later in a mainnet sync when the reads for past transactions are widespread. At the very least, we're overusing the pooled reads. Since I don't have a Mac, I'll take this without digging deeper, but if you do a mainnet sync and it gets surprisingly slow on IO later on, some IO may need to be moved to a pooled IO engine to keep the disk busy.

@reardencode
reardencode merged commit bb3ac63 into reardencode:master Oct 17, 2026
18 checks passed
@niteshbalusu11
niteshbalusu11 deleted the store/darwin-pread-default branch October 17, 2026 22:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants