Windows: cache the stdio write mode for the duration of a lock session - #159562
Conversation
|
r? @aapoalas rustbot has assigned @aapoalas. Use Why was this reviewer chosen?The reviewer was selected based on:
|
|
Reminder, once the PR becomes ready for a review, use |
|
@rustbot ready |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
🔨 2 commits were squashed into f05562d. |
8fa6c14 to
f05562d
Compare
This comment has been minimized.
This comment has been minimized.
This comment was marked as outdated.
This comment was marked as outdated.
|
📋 This PR cannot be approved because it has merge conflicts. Please resolve the merge conflicts by rebasing, and try again. |
|
Oop, right: we have a merge conflict! Sorry @Joel-Wwalker could you resolve that? r=me once CI passes <3 @bors delegate+ |
|
✌️ @Joel-Wwalker, you can now approve this pull request! If @aapoalas told you to " |
* Windows: cache the stdio write mode for the duration of a lock session Every write to stdout/stderr re-queried GetStdHandle and GetConsoleMode (and GetConsoleOutputCP for consoles) to decide how to write, which dominates bulk writes through a locked handle. Cache the handle and the console verdict in the sys-level Stdout/Stderr and re-query when a new lock session begins, so SetStdHandle calls made between lock sessions keep working. * Gate the stdio lock-session refresh to Windows On targets where refresh is a no-op, lock() now compiles to exactly the code it had before, instead of relying on the borrow-flag dance optimizing out.
f05562d to
0154b97
Compare
|
This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed. Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers. |
…uwer Rollup of 7 pull requests Successful merges: - #161873 (move bug and span_bug macros to rustc_span) - #162584 (Use File::*lock*() in rustc_data_structures::flock when possible) - #162704 (Parser: Uninterpolate when checking for const closures, try bikeshed blocks & in relevant diagnostic code) - #162787 (Fix suggestions for names captured by formatting macros) - #159562 (Windows: cache the stdio write mode for the duration of a lock session) - #162813 (Pre lint port cleanups) - #162822 (PassWrapper: adapt for removal of EABIVersion arg in LLVM 24)
Rollup merge of #159562 - Joel-Wwalker:154071-stdio-handle-cache, r=aapoalas Windows: cache the stdio write mode for the duration of a lock session On Windows, every write to stdout/stderr calls `GetStdHandle` and `GetConsoleMode` (and `GetConsoleOutputCP` for consoles) to decide how to write. For bulk writes through a locked handle that is most of the work; #154071 measured 14% of CPU time in `is_console` alone. This caches the handle and the console verdict in the sys-level `Stdout`/`Stderr` and re-queries when a new lock session begins, as [suggested in the issue](#154071 (comment)). Holding a `StdoutLock` pins the stream; unlocked writes acquire the lock per call, so they re-query per write exactly as before, and `SetStdHandle` calls made between lock sessions keep working (the #40490 behavior is preserved). Numbers from the issue's workload shape (16 KiB chunks to `NUL`, 4 GiB total, Windows 11): | mode | before | after | |---|---|---| | `stdout().lock()` | 0.478 s (8,561 MiB/s) | 0.120 s (34,350 MiB/s) | | unlocked | 0.467 s | 0.293 s | The unlocked case also improves because one implicit lock session can contain several sys-level writes when `LineWriter` splits a chunk at newlines. The console path cannot run in CI, so it was verified under a pseudoconsole: several writes through one lock session on a CP437 console came through `WriteConsoleW` intact (non-ASCII included), and after `SetConsoleOutputCP` plus a new lock session the refresh picked up the change. The `refresh` hook is a small `#[cfg(windows)]` shim on `StdoutRaw`/`StderrRaw`; happy to change it to a method on every platform's sys type instead if that is preferred. Fixes #154071
…uwer Rollup of 7 pull requests Successful merges: - rust-lang/rust#161873 (move bug and span_bug macros to rustc_span) - rust-lang/rust#162584 (Use File::*lock*() in rustc_data_structures::flock when possible) - rust-lang/rust#162704 (Parser: Uninterpolate when checking for const closures, try bikeshed blocks & in relevant diagnostic code) - rust-lang/rust#162787 (Fix suggestions for names captured by formatting macros) - rust-lang/rust#159562 (Windows: cache the stdio write mode for the duration of a lock session) - rust-lang/rust#162813 (Pre lint port cleanups) - rust-lang/rust#162822 (PassWrapper: adapt for removal of EABIVersion arg in LLVM 24)
…uwer Rollup of 7 pull requests Successful merges: - rust-lang/rust#161873 (move bug and span_bug macros to rustc_span) - rust-lang/rust#162584 (Use File::*lock*() in rustc_data_structures::flock when possible) - rust-lang/rust#162704 (Parser: Uninterpolate when checking for const closures, try bikeshed blocks & in relevant diagnostic code) - rust-lang/rust#162787 (Fix suggestions for names captured by formatting macros) - rust-lang/rust#159562 (Windows: cache the stdio write mode for the duration of a lock session) - rust-lang/rust#162813 (Pre lint port cleanups) - rust-lang/rust#162822 (PassWrapper: adapt for removal of EABIVersion arg in LLVM 24)
On Windows, every write to stdout/stderr calls
GetStdHandleandGetConsoleMode(andGetConsoleOutputCPfor consoles) to decide how to write. For bulk writes through a locked handle that is most of the work; #154071 measured 14% of CPU time inis_consolealone.This caches the handle and the console verdict in the sys-level
Stdout/Stderrand re-queries when a new lock session begins, as suggested in the issue. Holding aStdoutLockpins the stream; unlocked writes acquire the lock per call, so they re-query per write exactly as before, andSetStdHandlecalls made between lock sessions keep working (the #40490 behavior is preserved).Numbers from the issue's workload shape (16 KiB chunks to
NUL, 4 GiB total, Windows 11):stdout().lock()The unlocked case also improves because one implicit lock session can contain several sys-level writes when
LineWritersplits a chunk at newlines.The console path cannot run in CI, so it was verified under a pseudoconsole: several writes through one lock session on a CP437 console came through
WriteConsoleWintact (non-ASCII included), and afterSetConsoleOutputCPplus a new lock session the refresh picked up the change.The
refreshhook is a small#[cfg(windows)]shim onStdoutRaw/StderrRaw; happy to change it to a method on every platform's sys type instead if that is preferred.Fixes #154071