Repository navigation
Drop WC_ERR_INVALID_CHARS from Windows stdio - #164175
Conversation
| // Apparently Windows doesn't handle large reads on stdin or writes to stdout/stderr well (see | ||
| // #13304 for details). | ||
| // | ||
| // From MSDN (2011): "The storage for this buffer is allocated from a shared heap for the | ||
| // process that is 64 KB in size. The maximum size of the buffer will depend on heap usage." | ||
| // The way the console used to work up to Windows 8 is that the "LPC"s carried | ||
| // a small scratch space for reads/writes. If the client exceeded it, the server | ||
| // allocated a larger buffer from a fixed size section object. Its size was | ||
| // `CONSOLE_PORT_MEMORY_SIZE`, aka 64KiB. This meant any IO larger than that failed. | ||
| // If the Windows 7 source code ever leaks: The relevant function is `ConsoleAllocateCaptureBuffer`. | ||
| // | ||
| // We choose the cap at 8 KiB because libuv does the same, and it seems to be acceptable so far. | ||
| // It remains a good size for a stack allocated buffer, however. |
There was a problem hiding this comment.
@ChrisDenton This PR is my 2nd proposal after #164170, as such only 83ad357 is relevant here.
My proposal aside, I thought you may find this updated comment interesting. :)
This comment has been minimized.
This comment has been minimized.
|
I think this makes a lot of sense because, aside from simplifying the code, it's much closer to our stdio behaviour on other platforms. I'm going to nominate this for libs discussion since it would partially overturn an RFC (see https://rust-lang.github.io/rfcs/0517-io-os-reform.html#windows-and-stdio). That was an RFC from before Rust 1.0 but the given rationale for erroring does not seem convincing to me: @rustbot label +I-libs-nominated |
|
This was discussed in today's libs meeting. The libs team are happy for this to go ahead. |
This comment has been minimized.
This comment has been minimized.
83ad357 to
6d8b996
Compare
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
66ceffe to
c5a2e72
Compare
|
@ChrisDenton I've squashed the commits. However, I pushed a separate commit that fixes a regression in #164170, where I accidentally left a |
|
That's already being fixed by 02b3e2c which is already in the queue alongside some other win7 fixes. |
|
Oh, btw, I have successfully tested an experimental version of condrv.sys with buffering. Even with the lowest effort change, and no fast-pass, it results in a ~3x perf uplift when running e.g. |
d9ffc65 to
c5a2e72
Compare
|
Ah it's great someone fixed my blunder already! I've un-pushed it. |
|
@bors r+
That's exciting! I do hear a fair few complaints about Windows console perf so even just addressing the low hanging fruit would I think be a big win. |
…uwer Rollup of 7 pull requests Successful merges: - #164175 (Drop WC_ERR_INVALID_CHARS from Windows stdio) - #164361 (delegation: map return even if there is no target expression) - #162778 (rustdoc: add disambiguators for identically named method in sidebar) - #163224 ([rustdoc] Add tabs to settings popover) - #164220 (Test the interaction between `--remap-path-prefix` and doctests) - #164318 (Fix check with `is_impl_trait_in_trait()` before expecting local id) - #164360 (Fix(lib/sys): Restore Win7 compilation)
Rollup merge of #164175 - lhecker:windows-stdout-perf-chunking, r=ChrisDenton Drop WC_ERR_INVALID_CHARS from Windows stdio This PR builds on top of #164170 and refactors the transcoding of UTF8 output to UTF16 for use with `WriteConsoleW`. Previously, the stdlib would reject any non-UTF8 strings. I argue that this is unreasonable, as historically the Windows console is a pure character device. It makes no difference to it whether text is in an invalid encoding, as such text is always represented as U+FFFD. As such, it also makes no difference if we sanitize it with U+FFFD. This is still true today, despite Windows' more modern, true PTYs. Assuming I'm right, this PR presents a major simplification: Output is not double-checked for validity anymore. Instead, its fed directly into `MultiByteToWideChar`. THe only thing we still need to do is splice chunked UTF8 output together, as well as we can. This permits us to increase the buffer size from 8Ki to 64Ki wchars, which roughly doubles throughput over the current main branch. To make the stdout behave identical to stdin, this PR also removes `MB_ERR_INVALID_CHARS` from the `WideCharToMultiByte` call. ### Linewise output of `RELEASES.md`: Output | Version | lines/s | MB/s | Speedup --------|----------|--------:|------:|-------- console | 1.99.0 | 31526 | 1.79 | console | nightly | 29251 | 1.66 | console | #164170 | 67294 | 3.82 | 2.13x console | **this** | 73211 | 4.15 | 2.32x `NUL` | 1.99.0 | 784311 | 44.50 | `NUL` | nightly | 776529 | 44.06 | `NUL` | #164170 | 1141618 | 64.78 | 1.46x `NUL` | **this** | 1129683 | 64.10 | 1.44x ### 128KiB chunked passthrough of `enwik8`: Output | Version | MB/s | Speedup --------|----------|--------:|-------- console | 1.99.0 | 86.99 | console | nightly | 165.27 | 1.90x console | #164170 | 165.61 | 1.90x console | **this** | 303.51 | 3.49x `NUL` | 1.99.0 | 1123.82 | `NUL` | nightly | 1137.30 | `NUL` | #164170 | 1289.35 | `NUL` | **this** | 1294.18 |
This PR builds on top of #164170 and refactors the
transcoding of UTF8 output to UTF16 for use with
WriteConsoleW.Previously, the stdlib would reject any non-UTF8 strings. I argue that
this is unreasonable, as historically the Windows console is a pure
character device. It makes no difference to it whether text is in an
invalid encoding, as such text is always represented as U+FFFD.
As such, it also makes no difference if we sanitize it with U+FFFD.
This is still true today, despite Windows' more modern, true PTYs.
Assuming I'm right, this PR presents a major simplification:
Output is not double-checked for validity anymore. Instead, its fed
directly into
MultiByteToWideChar. THe only thing we still needto do is splice chunked UTF8 output together, as well as we can.
This permits us to increase the buffer size from 8Ki to 64Ki wchars,
which roughly doubles throughput over the current main branch.
To make the stdout behave identical to stdin, this PR also removes
MB_ERR_INVALID_CHARSfrom theWideCharToMultiBytecall.Linewise output of
RELEASES.md:NULNULNULNUL128KiB chunked passthrough of
enwik8:NULNULNULNULr? ChrisDenton