diff options
| author | Matthias Krüger <matthias.krueger@famsik.de> | 2024-03-08 08:19:19 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-03-08 08:19:19 +0100 |
| commit | f586a793846de57f4781b90542b7e26953f5cfab (patch) | |
| tree | 09231e7bf8d84e7ffc3da8529c99e6d5b3bad86a /compiler/rustc_codegen_llvm/src/builder.rs | |
| parent | 7e6a6d07794a6131ba31874bcab8959af48f10bf (diff) | |
| parent | 8212fc513c66ebd9996180456305ecd6c425d5da (diff) | |
| download | rust-f586a793846de57f4781b90542b7e26953f5cfab.tar.gz rust-f586a793846de57f4781b90542b7e26953f5cfab.zip | |
Rollup merge of #121938 - blyxxyz:quadratic-vectored-write, r=Amanieu
Fix quadratic behavior of repeated vectored writes
Some implementations of `Write::write_vectored` in the standard library (`BufWriter`, `LineWriter`, `Stdout`, `Stderr`) check all buffers to calculate the total length. This is O(n) over the number of buffers.
It's common that only a limited number of buffers is written at a time (e.g. 1024 for `writev(2)`). `write_vectored_all` will then call `write_vectored` repeatedly, leading to a runtime of O(n²) over the number of buffers.
This fix is to only calculate as much as needed if it's needed.
Here's a test program:
```rust
#![feature(write_all_vectored)]
use std::fs::File;
use std::io::{BufWriter, IoSlice, Write};
use std::time::Instant;
fn main() {
let buf = vec![b'\0'; 100_000_000];
let mut slices: Vec<IoSlice<'_>> = buf.chunks(100).map(IoSlice::new).collect();
let mut writer = BufWriter::new(File::create("/dev/null").unwrap());
let start = Instant::now();
write_smart(&slices, &mut writer);
println!("write_smart(): {:?}", start.elapsed());
let start = Instant::now();
writer.write_all_vectored(&mut slices).unwrap();
println!("write_all_vectored(): {:?}", start.elapsed());
}
fn write_smart(mut slices: &[IoSlice<'_>], writer: &mut impl Write) {
while !slices.is_empty() {
// Only try to write as many slices as can be written
let res = writer
.write_vectored(slices.get(..1024).unwrap_or(slices))
.unwrap();
slices = &slices[(res / 100)..];
}
}
```
Before this change:
```
write_smart(): 6.666952ms
write_all_vectored(): 498.437092ms
```
After this change:
```
write_smart(): 6.377158ms
write_all_vectored(): 6.923412ms
```
`LineWriter` (and by extension `Stdout`) isn't fully repaired by this because it looks for newlines. I could open an issue for that after this is merged, I think it's fixable but not trivially.
Diffstat (limited to 'compiler/rustc_codegen_llvm/src/builder.rs')
0 files changed, 0 insertions, 0 deletions
