Skip to content

perf: read the pty in 64 KB chunks instead of 1 KB - #25

Open
lordspace wants to merge 1 commit into
TerminalStudio:mainfrom
orbisius:oterm-read-buffer-size
Open

perf: read the pty in 64 KB chunks instead of 1 KB#25
lordspace wants to merge 1 commit into
TerminalStudio:mainfrom
orbisius:oterm-read-buffer-size

Conversation

@lordspace

Copy link
Copy Markdown

Fixes #24

What this changes

read_loop reads with a 1 KB stack buffer and posts one Dart port message per
read, on both the POSIX and the Windows reader. This raises the buffer to 64 KB
behind a named PTY_READ_BUFFER_SIZE, in both files.

Two lines of behaviour change, no API change.

Why

One read is one port message, and the message is what costs — a typed-data
allocation, a stream event, Future propagation on the Dart side, and the GC
after it. At 1 KB, 15 MB of program output becomes ~15,000 messages, and the UI
isolate spends its time on message machinery rather than on the terminal.

Measured in a real Flutter terminal app (Linux, release build, find /usr =
15.2 MB), timing how long the app stays busy after the command finishes
i.e. how long the UI is unresponsive:

Terminal window 1 KB (current) 64 KB
small (~848 cells) 52.2 s 8.0 s
maximized (~6478 cells) 58.2 s 10.1 s

~5.8x faster, and the difference between a terminal that stalls on a noisy
build and one that does not.

Rendering was ruled out before touching this: 7.6x the terminal cells cost only
12% more time
, so the cost is per-byte, not per-cell. A CPU profile agreed —
the hot leaves were typed-data allocation, GC (__munmap), and
_propagateToListeners / _scheduleMicrotask, i.e. the per-message path rather
than parsing or painting.

Things a reviewer would reasonably ask

Does this add latency to interactive typing? No. read() returns as soon as
any data is available and never waits to fill the buffer, so an echoed keystroke
still arrives in one small read. The buffer size caps a read; it does not set one.

Is 64 KB on the stack safe? It is a stack array on the dedicated reader
thread, against a default 8 MB thread stack. If you would rather not spend 64 KB
of frame, a smaller value captures much of the win, or it can move to a single
malloc per reader — happy to change it either way.

Why both files? The Windows reader carries the same 1 KB buffer, so a
POSIX-only change would leave Windows on the slow path.

Why not flow control instead? The existing ackRead path is untouched and
still works exactly as before; this is orthogonal and helps whether or not a
consumer opts into acking.

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.

flutter_pty: the 1 KB read buffer dominates cost under heavy output

1 participant