Open and answer this issue on GitHub.
libraries, note · opened 2026-10-04 · updated 2026-10-06 · 1 comment
ADR-263 D1 (#412) reads a regular file on the calling thread when the runtime is idle. Standard input stays on an I/O worker (ADR-263 §6). That holds up for a terminal or a slow peer: the read waits far longer for the input than the hand-off costs.
It does not hold for standard input as a pipe that is already full:
cat measurements.txt | prog
Here the bytes are there at once, as a file’s are. A program that walks the input a line at a time (io::lines, Part III 17.1) reads it in chunks through rt::io::stdin_chunk:
CHUNK is 8 KiB (crates/nikaia-std/src/io.rs), so 13 GB of input means about 1.6 million hand-offs to a worker and back. Each one is a channel send, a worker wake-up, a reply and a park.vec[0_u8; want] in rt/worker.rs, Op::StdinChunk). That is the same waste ADR-263 D3 removed from the file path.io::read_to_string / io::read (all of stdin at once) make a single hand-off and are not affected.
CHUNK (e.g. 64 KiB) changes the count. The single read per chunk stays, so a slow pipe still yields whatever is there.This would be an amendment to ADR-263 §6, not a new setting (ADR-303 D5).
Sockets. They are non-blocking and read on readiness, and the hand-off is noise beside network latency (ADR-263 §6).
Steps 1 and 2 are done in 0.0.442 (99f9961).
The measurement. I did not use callgrind here: under valgrind the threads run serialized, and every hand-off to the worker becomes a scheduler round, so the run did not finish in 20 minutes. Instead I took wall-clock times. A program that counts lines and their bytes through io::lines(), opt-level = 3, 4 M lines (60 MB, handwritten gen), best of 9, interleaved, 4 cores:
cat data \| prog |
prog < data |
|
|---|---|---|
| 8 KiB a hop, buffer zeroed (before) | 791 ms | 671 ms |
8 KiB a hop, no zeroing (take(want).read_to_end into capacity, measurement only) |
799 ms | - |
| 64 KiB a hop, zeroed (now) | 414 ms | 389 ms |
want bytes have arrived and so breaks the one-read rule. It was only a measurement.CHUNK is now 64 KiB, a pipe’s capacity on Linux. It is still one read a hop, so a slow pipe hands over whatever is there.Step 3, a calling-thread path for a full pipe, is not built. It amends ADR-263 §6, and whether it still pays at 64 KiB has to be measured against a file read of the same lines first. §6 says that much now.
Generated by Claude Code