Uh oh!
There was an error while loading. Please reload this page.
Add Read::size_hint and pre-allocate in read_to_end - #45928
Conversation
If this adds a new system call when calling read_to_end on a File, it has been discussed before. Putting a system call in size_hint (metadata) is not ideal. (I can't find it though.) |
SimonSapin
commented
Nov 11, 2017
Yes, |
There was a problem hiding this comment.
It's a minor point but this should probably use a saturating cast not as.
There was a problem hiding this comment.
Is there an API for doing saturating integer casts? Writing #[cfg(target_pointer_size = …)] code here seems tedious.
There was a problem hiding this comment.
Sadly not yet (rust-lang/rfcs#1218). Something like cmp::min(meta.len(), usize::max_value() as u64) as usize should work though.
There was a problem hiding this comment.
On the other hand this is a hint, the default impl returns zero without necessarily being at EOF so underestimating should be OK. And if you’re reading a file larger than your address space, you’re gonna have a hard time in read_to_end anyway.
There was a problem hiding this comment.
This also needs to check its current position and subtract that off, right?
There was a problem hiding this comment.
Right. However the obvious fix doesn’t work because <File as Seek>::seek takes &mut self, even with SeekFrom::Current(0). I wonder if there should be some API like File::position(&self) -> io::Result<u64>.
There was a problem hiding this comment.
Never mind, <std::fs::File as Seek>::seek calls std::sys::fs::File::seek which takes &self, so size_hint can call the latter directly.
Update: This was fixed by #46050. |
shepmaster
commented
Nov 18, 2017
random-assigning to... r? @sfackler |
sfackler
commented
Nov 20, 2017
Does #46050 give the same improvement? |
sunfishcode
commented
Nov 20, 2017
A non-obvious detail of If you're calling metadata(), when it provides a size, can you trust the size (and not take it as a hint)? If so, in that case you could add alternate logic in |
mbrubeck
commented
Nov 20, 2017
You can't trust the size from metadata because the file may change between the metadata call and the read call. |
sunfishcode
commented
Nov 20, 2017
You always have to be prepared to get fewer bytes than expected, or errors, but if there are more bytes than expected, it's no different from someone appending bytes after your last read returned 0. You'll miss the newly appended bytes, but it was a race anyway. That assumes that |
bors
commented
Nov 21, 2017
☔ The latest upstream changes (presumably #46166) made this pull request unmergeable. Please resolve the merge conflicts. |
carols10cents
commented
Nov 27, 2017
What's the status of this @SimonSapin ? I'm having a hard time telling :) |
c2f42cc to
dd1fc4aComparedd1fc4a to
6adc9e6CompareSimonSapin
commented
Nov 28, 2017
I’ve run the benchmark again in rustc 1.24.0-nightly (560a5da 2017-11-27), which includes #46050. Previous results were “3% more time to 43% less time” Now the time with So this PR’s improvement seems independent of #46050’s improvement. More important IMO is whether Details |
sunfishcode
commented
Nov 28, 2017
Reserving This can be fixed either by reserving |
This one byte of extra capacity is necessary for the final zero-size read that indicates EOF.
SimonSapin
commented
Nov 28, 2017
Good point. I’ve added the |
sunfishcode
commented
Nov 28, 2017
To be sure, |
sfackler
commented
Nov 28, 2017
Cool - something like this seems worthwhile then. Should it return an |
SimonSapin
commented
Nov 30, 2017
@sfackler Good point. Changed to |
SimonSapin
commented
Nov 30, 2017
I don’t have a strong opinion on the strategy of this PR v.s. that of #46340. A key difference is the semantics of |
bors
commented
Dec 4, 2017
☔ The latest upstream changes (presumably #46485) made this pull request unmergeable. Please resolve the merge conflicts. |
sfackler
commented
Dec 4, 2017
Sorry for the delay here - should we maybe make an issue to figure out the approach to take? I'd like to avoid splitting the discussion across two PRs. |
shepmaster
commented
Dec 9, 2017
I'm going to make an executive decision and mark this and #46340 as waiting on a team decision as it seems that they cannot both exist together. Let me know if you disagree. |
sfackler
commented
Jan 10, 2018
The @rust-lang/libs team talked about this and #46340 during our triage meeting and decided that we're not looking to expand the surface area of |
Pre-allocate in fs::read and fs::read_string This is a simpler alternative to rust-lang#46340 and rust-lang#45928, as requested by the libs team.
Pre-allocate in fs::read and fs::read_string This is a simpler alternative to rust-lang#46340 and rust-lang#45928, as requested by the libs team.
Pre-allocate in fs::read and fs::read_string This is a simpler alternative to rust-lang#46340 and rust-lang#45928, as requested by the libs team.
Many
FromIteratorimplementations rely onIterator::size_hintto pre-allocate memory. This is a prototype of what something equivalent forstd::io::Readcould look like. An alternative would be to not add any public API but use an private specialization trait, likeZipImplin libcore.This came up in #45837 in the case of reading from a file. I’ve measured
File::read_to_endwith a vector created withVec::with_capacity(file.metadata().len() as usize), compared toVec::new(). On my linux desktop with an SSD (though everything is probably in filesystem cache here), pre-allocating + reading take 3% more time to 43% less time depending on file size.