Commit db0a06e
authored
Rollup merge of rust-lang#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.3 files changed
+50
-31
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
554 | 554 | | |
555 | 555 | | |
556 | 556 | | |
557 | | - | |
558 | | - | |
| 557 | + | |
559 | 558 | | |
560 | | - | |
561 | | - | |
562 | | - | |
563 | | - | |
| 559 | + | |
| 560 | + | |
| 561 | + | |
| 562 | + | |
| 563 | + | |
| 564 | + | |
| 565 | + | |
| 566 | + | |
| 567 | + | |
| 568 | + | |
| 569 | + | |
| 570 | + | |
| 571 | + | |
| 572 | + | |
| 573 | + | |
| 574 | + | |
| 575 | + | |
| 576 | + | |
564 | 577 | | |
565 | 578 | | |
566 | | - | |
567 | | - | |
568 | | - | |
569 | | - | |
570 | | - | |
571 | | - | |
572 | | - | |
573 | | - | |
574 | | - | |
575 | | - | |
| 579 | + | |
576 | 580 | | |
577 | | - | |
578 | | - | |
579 | | - | |
580 | | - | |
581 | | - | |
582 | | - | |
| 581 | + | |
| 582 | + | |
| 583 | + | |
| 584 | + | |
| 585 | + | |
| 586 | + | |
583 | 587 | | |
584 | | - | |
585 | | - | |
| 588 | + | |
586 | 589 | | |
587 | 590 | | |
588 | 591 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
175 | 175 | | |
176 | 176 | | |
177 | 177 | | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
178 | 182 | | |
179 | 183 | | |
180 | 184 | | |
| |||
215 | 219 | | |
216 | 220 | | |
217 | 221 | | |
218 | | - | |
219 | | - | |
220 | | - | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
221 | 230 | | |
222 | 231 | | |
223 | 232 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
128 | 128 | | |
129 | 129 | | |
130 | 130 | | |
131 | | - | |
132 | | - | |
| 131 | + | |
| 132 | + | |
133 | 133 | | |
134 | 134 | | |
135 | 135 | | |
| |||
160 | 160 | | |
161 | 161 | | |
162 | 162 | | |
163 | | - | |
164 | | - | |
| 163 | + | |
| 164 | + | |
165 | 165 | | |
166 | 166 | | |
167 | 167 | | |
| |||
193 | 193 | | |
194 | 194 | | |
195 | 195 | | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
196 | 203 | | |
197 | 204 | | |
198 | 205 | | |
| |||
0 commit comments