372709326e
A small example that simply writes pseudo-random chunks to a drive. This is useful to benchmark throughput on tape drives. The output and behavior is similar to what the pool writer does, but without writing multiple files, committing or loading data from disk. Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
92 lines
2.7 KiB
Rust
92 lines
2.7 KiB
Rust
use std::{
|
|
fs::File,
|
|
io::Read,
|
|
time::{Duration, SystemTime},
|
|
};
|
|
|
|
use anyhow::{format_err, Error};
|
|
use pbs_tape::TapeWrite;
|
|
use proxmox_backup::tape::drive::{LtoTapeHandle, TapeDriver};
|
|
|
|
const URANDOM_PATH: &str = "/dev/urandom";
|
|
const CHUNK_SIZE: usize = 4 * 1024 * 1024; // 4 MiB
|
|
const LOG_LIMIT: usize = 4 * 1024 * 1024 * 1024; // 4 GiB
|
|
|
|
fn write_chunks<'a>(
|
|
mut writer: Box<dyn 'a + TapeWrite>,
|
|
blob_size: usize,
|
|
max_size: usize,
|
|
max_time: Duration,
|
|
) -> Result<(), Error> {
|
|
// prepare chunks in memory
|
|
|
|
let mut blob: Vec<u8> = vec![0u8; blob_size];
|
|
|
|
let mut file = File::open(URANDOM_PATH)?;
|
|
file.read_exact(&mut blob[..])?;
|
|
|
|
let start_time = SystemTime::now();
|
|
loop {
|
|
let iteration_time = SystemTime::now();
|
|
let mut count = 0;
|
|
let mut bytes_written = 0;
|
|
let mut idx = 0;
|
|
let mut incr_count = 0;
|
|
loop {
|
|
if writer.write_all(&blob)? {
|
|
eprintln!("LEOM reached");
|
|
break;
|
|
}
|
|
|
|
// modifying chunks a bit to mitigate compression/deduplication
|
|
blob[idx] = blob[idx].wrapping_add(1);
|
|
incr_count += 1;
|
|
if incr_count >= 256 {
|
|
incr_count = 0;
|
|
idx += 1;
|
|
}
|
|
count += 1;
|
|
bytes_written += blob_size;
|
|
|
|
if bytes_written > max_size {
|
|
break;
|
|
}
|
|
}
|
|
|
|
let elapsed = iteration_time.elapsed()?.as_secs_f64();
|
|
let elapsed_total = start_time.elapsed()?;
|
|
eprintln!(
|
|
"{:.2}s: wrote {} chunks ({:.2} MB at {:.2} MB/s, average: {:.2} MB/s)",
|
|
elapsed_total.as_secs_f64(),
|
|
count,
|
|
bytes_written as f64 / 1_000_000.0,
|
|
(bytes_written as f64) / (1_000_000.0 * elapsed),
|
|
(writer.bytes_written() as f64) / (1_000_000.0 * elapsed_total.as_secs_f64()),
|
|
);
|
|
|
|
if elapsed_total > max_time {
|
|
break;
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
fn main() -> Result<(), Error> {
|
|
let mut args = std::env::args_os();
|
|
args.next(); // binary name
|
|
let path = args.next().expect("no path to tape device given");
|
|
let file = File::open(path).map_err(|err| format_err!("could not open tape device: {err}"))?;
|
|
let mut drive = LtoTapeHandle::new(file)
|
|
.map_err(|err| format_err!("error creating drive handle: {err}"))?;
|
|
write_chunks(
|
|
drive
|
|
.write_file()
|
|
.map_err(|err| format_err!("error starting file write: {err}"))?,
|
|
CHUNK_SIZE,
|
|
LOG_LIMIT,
|
|
Duration::new(60 * 20, 0),
|
|
)
|
|
.map_err(|err| format_err!("error writing data to tape: {err}"))?;
|
|
Ok(())
|
|
}
|