-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Extend io::copy buffer reuse to BufReader too #112330
Conversation
r? @thomcc (rustbot has picked a reviewer for you, use r? to override) |
This comment has been minimized.
This comment has been minimized.
81c1d01
to
9c20c89
Compare
// Hack: this relies on `impl Read for BufReader` always calling fill_buf | ||
// if the buffer is empty, even for empty slices. | ||
// It can't be called directly here since specialization prevents us | ||
// from adding I: Read | ||
match self.read(&mut []) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I could maybe get everything I want by adding a bunch of hidden helper functions to the Read
trait and only implement them on BufReader
(and provide stub default impls for everything else) but imo that would be an even bigger hack than this. And that would require combining associated type defaults with specialization which is uncharted territory.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is worth doing right now.
☔ The latest upstream changes (presumably #112716) made this pull request unmergeable. Please resolve the merge conflicts. |
Looks good to me. r=me after the rebase. |
previously it was only able to use BufWriter. This was due to a limitation in the BufReader generics that prevented specialization. This change works around the issue by using `where Self: Read` instead of `where I: Read`. This limits our options, e.g. we can't access BufRead methods, but it happens to work out if we rely on some implementation details.
9c20c89
to
3738785
Compare
@bors r=thomcc |
☀️ Test successful - checks-actions |
Finished benchmarking commit (7513407): comparison URL. Overall result: ✅ improvements - no action needed@rustbot label: -perf-regression Instruction countThis is a highly reliable metric that was used to determine the overall result at the top of this comment.
Max RSS (memory usage)ResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
CyclesResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
Binary sizeResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
Bootstrap: 656.303s -> 655.196s (-0.17%) |
previously it was only able to use BufWriter. This was due to a limitation in the BufReader generics that prevented specialization. This change works around the issue by using
BufReader where Self: Read
instead ofBufReader<I> where I: Read
. This limits our options, e.g. we can't access the inner reader, but it happens to work out if we rely on some implementation details.Copying 1MiB from
/dev/zero
to/dev/null
through a 256KiB BufReader yields following improvementsPreviously this would read 256KiB into the reader but then copy 8KiB chunks to the writer through an additional intermediate buffer inside
io::copy
. Since those devices don't do much work most of the speedup should come from fewer syscalls and avoided memcopies.The b3sum crate notes that the default buffer size in io::copy is too small. With this optimization they could achieve the desired performance by wrapping the reader in a
BufReader
instead of handrolling it.Currently the optimization doesn't apply to things like
StdinLock
, but this can be addressed with an additionalAsMutBufReader
specialization trait.