Skip to content

Commit eb5c742

Browse files
committed
dd: improve allocation strategy for huge bs
1 parent e417bd1 commit eb5c742

1 file changed

Lines changed: 23 additions & 12 deletions

File tree

src/uu/dd/src/dd.rs

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -520,25 +520,36 @@ impl Input<'_> {
520520
/// Fills a given buffer.
521521
/// Reads in increments of 'self.ibs'.
522522
/// The start of each ibs-sized read follows the previous one.
523-
fn fill_consecutive(&mut self, buf: &mut Vec<u8>) -> io::Result<ReadStat> {
523+
fn fill_consecutive(&mut self, buf: &mut Vec<u8>, bsize: usize) -> io::Result<ReadStat> {
524524
let mut reads_complete = 0;
525525
let mut reads_partial = 0;
526526
let mut bytes_total = 0;
527-
528-
for chunk in buf.chunks_mut(self.settings.ibs) {
529-
match self.read(chunk)? {
527+
buf.clear();
528+
let spare = buf.spare_capacity_mut();
529+
let spare_len = spare.len();
530+
let target_area = &mut spare[..bsize.min(spare_len)];
531+
532+
for chunk in target_area.chunks_mut(self.settings.ibs) {
533+
// std cannot fix https://github.com/uutils/coreutils/issues/11544 without unsafe yet
534+
// caution: restrict usage of this to write-only
535+
let slice = unsafe {
536+
std::slice::from_raw_parts_mut(chunk.as_mut_ptr().cast::<u8>(), chunk.len())
537+
};
538+
match self.read(slice)? {
530539
rlen if rlen == self.settings.ibs => {
531540
bytes_total += rlen;
532541
reads_complete += 1;
533542
}
534543
rlen if rlen > 0 => {
535544
bytes_total += rlen;
536545
reads_partial += 1;
546+
break;
537547
}
538-
_ => break,
548+
_ => break, // end of file
539549
}
540550
}
541-
buf.truncate(bytes_total);
551+
// todo: use wrapper to extend buf with read at same time without unsafe
552+
unsafe { buf.set_len(bytes_total) };
542553
Ok(ReadStat {
543554
reads_complete,
544555
reads_partial,
@@ -551,7 +562,10 @@ impl Input<'_> {
551562
/// Fills a given buffer.
552563
/// Reads in increments of 'self.ibs'.
553564
/// The start of each ibs-sized read is aligned to multiples of ibs; remaining space is filled with the 'pad' byte.
554-
fn fill_blocks(&mut self, buf: &mut Vec<u8>, pad: u8) -> io::Result<ReadStat> {
565+
fn fill_blocks(&mut self, buf: &mut Vec<u8>, bsize: usize, pad: u8) -> io::Result<ReadStat> {
566+
// Resize the buffer to the bsize. Any garbage data in the buffer is overwritten or truncated, so there is no need to fill with BUF_INIT_BYTE first.
567+
// resizing buf cause serious performance drop https://github.com/uutils/coreutils/issues/11544
568+
buf.resize(bsize, BUF_INIT_BYTE);
555569
let mut reads_complete = 0;
556570
let mut reads_partial = 0;
557571
let mut base_idx = 0;
@@ -1366,13 +1380,10 @@ fn read_helper(i: &mut Input, buf: &mut Vec<u8>, bsize: usize) -> io::Result<Rea
13661380
}
13671381
// ------------------------------------------------------------------
13681382
// Read
1369-
// Resize the buffer to the bsize. Any garbage data in the buffer is overwritten or truncated, so there is no need to fill with BUF_INIT_BYTE first.
1370-
// resizing buf cause serious performance drop https://github.com/uutils/coreutils/issues/11544
1371-
buf.resize(bsize, BUF_INIT_BYTE);
13721383

13731384
let mut rstat = match i.settings.iconv.sync {
1374-
Some(ch) => i.fill_blocks(buf, ch)?,
1375-
_ => i.fill_consecutive(buf)?,
1385+
Some(ch) => i.fill_blocks(buf, bsize, ch)?,
1386+
_ => i.fill_consecutive(buf, bsize)?,
13761387
};
13771388
// Return early if no data
13781389
if rstat.reads_complete == 0 && rstat.reads_partial == 0 {

0 commit comments

Comments
 (0)