mirror of
https://github.com/uutils/coreutils
synced 2024-12-26 21:13:26 +00:00
dd: use an alarm thread instead of elapsed() calls
Quick benchmark on FreeBSD 13.1-RELEASE: Summary './dd-thread-alarm if=/dev/zero of=/dev/null count=4000000 status=progress' ran 1.17 ± 0.17 times faster than './dd-baseline if=/dev/zero of=/dev/null count=4000000 status=progress'
This commit is contained in:
parent
f5a9ffe52f
commit
cf7b90bbe7
1 changed files with 43 additions and 4 deletions
|
@ -65,6 +65,46 @@ struct Settings {
|
||||||
status: Option<StatusLevel>,
|
status: Option<StatusLevel>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use std::thread::sleep;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use std::sync::{
|
||||||
|
atomic::{AtomicBool, Ordering::Relaxed},
|
||||||
|
Arc,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Alarm {
|
||||||
|
interval: Duration,
|
||||||
|
trigger: Arc<AtomicBool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Alarm {
|
||||||
|
pub fn with_interval(interval: Duration) -> Alarm {
|
||||||
|
let trigger = Arc::new(AtomicBool::default());
|
||||||
|
|
||||||
|
let weak_trigger = Arc::downgrade(&trigger);
|
||||||
|
std::thread::spawn(move || loop {
|
||||||
|
sleep(interval);
|
||||||
|
if let Some(trigger) = weak_trigger.upgrade() {
|
||||||
|
trigger.store(true, Relaxed);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Alarm { interval, trigger }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_triggered(&self) -> bool {
|
||||||
|
self.trigger.swap(false, Relaxed)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_interval(&self) -> Duration {
|
||||||
|
self.interval
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A number in blocks or bytes
|
/// A number in blocks or bytes
|
||||||
///
|
///
|
||||||
/// Some values (seek, skip, iseek, oseek) can have values either in blocks or in bytes.
|
/// Some values (seek, skip, iseek, oseek) can have values either in blocks or in bytes.
|
||||||
|
@ -628,7 +668,6 @@ fn dd_copy(mut i: Input, mut o: Output) -> std::io::Result<()> {
|
||||||
// information.
|
// information.
|
||||||
let (prog_tx, rx) = mpsc::channel();
|
let (prog_tx, rx) = mpsc::channel();
|
||||||
let output_thread = thread::spawn(gen_prog_updater(rx, i.settings.status));
|
let output_thread = thread::spawn(gen_prog_updater(rx, i.settings.status));
|
||||||
let mut progress_as_secs = 0;
|
|
||||||
|
|
||||||
// Optimization: if no blocks are to be written, then don't
|
// Optimization: if no blocks are to be written, then don't
|
||||||
// bother allocating any buffers.
|
// bother allocating any buffers.
|
||||||
|
@ -639,6 +678,7 @@ fn dd_copy(mut i: Input, mut o: Output) -> std::io::Result<()> {
|
||||||
// Create a common buffer with a capacity of the block size.
|
// Create a common buffer with a capacity of the block size.
|
||||||
// This is the max size needed.
|
// This is the max size needed.
|
||||||
let mut buf = vec![BUF_INIT_BYTE; bsize];
|
let mut buf = vec![BUF_INIT_BYTE; bsize];
|
||||||
|
let alarm = Alarm::with_interval(Duration::from_secs(1));
|
||||||
|
|
||||||
// The main read/write loop.
|
// The main read/write loop.
|
||||||
//
|
//
|
||||||
|
@ -667,9 +707,8 @@ fn dd_copy(mut i: Input, mut o: Output) -> std::io::Result<()> {
|
||||||
// error.
|
// error.
|
||||||
rstat += rstat_update;
|
rstat += rstat_update;
|
||||||
wstat += wstat_update;
|
wstat += wstat_update;
|
||||||
let prog_update = ProgUpdate::new(rstat, wstat, start.elapsed(), false);
|
if alarm.is_triggered() {
|
||||||
if prog_update.duration.as_secs() >= progress_as_secs {
|
let prog_update = ProgUpdate::new(rstat, wstat, start.elapsed(), false);
|
||||||
progress_as_secs = prog_update.duration.as_secs() + 1;
|
|
||||||
prog_tx.send(prog_update).unwrap_or(());
|
prog_tx.send(prog_update).unwrap_or(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue