[pbs-devel] [PATCH proxmox-backup 2/2] examples: add tape write benchmark

Dominik Csapak d.csapak at proxmox.com
Tue May 7 15:45:53 CEST 2024


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 at proxmox.com>
---
 examples/tape-write-benchmark.rs | 91 ++++++++++++++++++++++++++++++++
 1 file changed, 91 insertions(+)
 create mode 100644 examples/tape-write-benchmark.rs

diff --git a/examples/tape-write-benchmark.rs b/examples/tape-write-benchmark.rs
new file mode 100644
index 000000000..d5686e65a
--- /dev/null
+++ b/examples/tape-write-benchmark.rs
@@ -0,0 +1,91 @@
+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(())
+}
-- 
2.39.2





More information about the pbs-devel mailing list