From aca64ced8f60a11f1f432846b2fde19912431113 Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Thu, 26 Mar 2026 21:20:14 +0100 Subject: [PATCH] performance-metrics: Add compressed QCOW2 tempfile helper Add compressed_qcow_tempfile() which creates a zlib compressed QCOW2 image by populating a RAW tempfile with data and converting it via qemu-img convert -c. Every cluster in the resulting image is stored compressed so reads exercise the decompression path. To be used by the compressed read benchmark. Signed-off-by: Anatol Belski --- performance-metrics/src/util.rs | 55 +++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/performance-metrics/src/util.rs b/performance-metrics/src/util.rs index 3ba9a9eee..b859c8764 100644 --- a/performance-metrics/src/util.rs +++ b/performance-metrics/src/util.rs @@ -4,8 +4,10 @@ //! Shared benchmark helpers. +use std::fs::File; use std::io::{ErrorKind, Seek, SeekFrom, Write}; use std::os::unix::fs::FileExt; +use std::process::Command; use std::thread; use std::time::Duration; @@ -182,6 +184,59 @@ pub fn qcow_overlay_tempfile(num_clusters: usize) -> (TempFile, TempFile, QcowDi (backing, overlay, disk) } +/// Create a zlib compressed QCOW2 image with `num_clusters` clusters +/// via `qemu-img convert -c`. +fn create_compressed_qcow_tempfile(num_clusters: usize) -> TempFile { + let virtual_size = QCOW_CLUSTER_SIZE * num_clusters as u64; + + let raw_tmp = TempFile::new().expect("failed to create raw tempfile"); + { + let f = raw_tmp.as_file(); + f.set_len(virtual_size).expect("set_len failed"); + let buf = vec![0xA5u8; QCOW_CLUSTER_SIZE as usize]; + for i in 0..num_clusters { + f.write_at(&buf, i as u64 * QCOW_CLUSTER_SIZE) + .expect("write_at failed"); + } + } + + let qcow_tmp = TempFile::new().expect("failed to create qcow2 tempfile"); + let qcow_path = qcow_tmp.as_path().to_str().unwrap().to_string(); + let raw_path = raw_tmp.as_path().to_str().unwrap().to_string(); + let status = Command::new("qemu-img") + .args([ + "convert", + "-f", + "raw", + "-O", + "qcow2", + "-c", + "-o", + "compression_type=zlib", + &raw_path, + &qcow_path, + ]) + .status() + .expect("failed to run qemu-img"); + assert!(status.success(), "qemu-img convert failed"); + + qcow_tmp +} + +/// Compressed QCOW2 opened via QcowDiskSync. +pub fn compressed_qcow_tempfile(num_clusters: usize) -> (TempFile, QcowDiskSync) { + let tmp = create_compressed_qcow_tempfile(num_clusters); + let path = tmp.as_path().to_str().unwrap().to_string(); + let disk = QcowDiskSync::new( + File::open(&path).expect("failed to open compressed qcow2"), + false, + false, + true, + ) + .expect("failed to open compressed qcow2 via QcowDiskSync"); + (tmp, disk) +} + /// Spin and wait until the given eventfd becomes readable. pub fn wait_for_eventfd(notifier: &EventFd) { loop {