From b2430d701bc7df964de751f13295fd65372fd448 Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Thu, 26 Mar 2026 21:13:09 +0100 Subject: [PATCH] performance-metrics: Add QCOW2 copy-on-write write micro benchmark Add micro_bench_qcow_cow_write which writes clusters into a QCOW2 overlay backed by a raw file. Each write triggers copy-on-write: cluster allocation, L2 and refcount table updates, then the data write. This measures COW allocation overhead compared to writing into a plain empty image. Workloads: 128 and 256 clusters. Signed-off-by: Anatol Belski --- performance-metrics/src/main.rs | 26 +++++++++++++++++++- performance-metrics/src/micro_bench_block.rs | 26 ++++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/performance-metrics/src/main.rs b/performance-metrics/src/main.rs index e40323788..879cce926 100644 --- a/performance-metrics/src/main.rs +++ b/performance-metrics/src/main.rs @@ -378,7 +378,7 @@ mod adjuster { } } -const TEST_LIST: [PerformanceTest; 74] = [ +const TEST_LIST: [PerformanceTest; 76] = [ PerformanceTest { name: "boot_time_ms", func_ptr: performance_boot_time, @@ -1397,6 +1397,30 @@ const TEST_LIST: [PerformanceTest; 74] = [ }, unit_adjuster: adjuster::s_to_us, }, + PerformanceTest { + name: "micro_block_qcow_cow_write_128_us", + func_ptr: micro_bench_block::micro_bench_qcow_cow_write, + control: PerformanceTestControl { + test_timeout: 10, + test_iterations: 20, + warmup_iterations: 5, + num_ops: Some(128), + ..PerformanceTestControl::default() + }, + unit_adjuster: adjuster::s_to_us, + }, + PerformanceTest { + name: "micro_block_qcow_cow_write_256_us", + func_ptr: micro_bench_block::micro_bench_qcow_cow_write, + control: PerformanceTestControl { + test_timeout: 10, + test_iterations: 20, + warmup_iterations: 5, + num_ops: Some(256), + ..PerformanceTestControl::default() + }, + unit_adjuster: adjuster::s_to_us, + }, ]; fn run_test_with_timeout( diff --git a/performance-metrics/src/micro_bench_block.rs b/performance-metrics/src/micro_bench_block.rs index efb73559d..035ca1d43 100644 --- a/performance-metrics/src/micro_bench_block.rs +++ b/performance-metrics/src/micro_bench_block.rs @@ -221,3 +221,29 @@ pub fn micro_bench_qcow_backing_read(control: &PerformanceTestControl) -> f64 { elapsed } + +/// Write num_ops clusters into a QCOW2 overlay backed by a raw file. +/// +/// Each write triggers copy-on-write: the overlay must allocate a new +/// cluster, update L2 and refcount tables, then write the data. This +/// measures the COW allocation overhead compared to writing into an +/// empty image (no backing read needed since we overwrite the full +/// cluster). +/// +/// Returns the total write wall clock time in seconds. +pub fn micro_bench_qcow_cow_write(control: &PerformanceTestControl) -> f64 { + let num_ops = control.num_ops.expect("num_ops required") as usize; + let (_backing, _overlay, disk) = util::qcow_overlay_tempfile(num_ops); + let mut async_io = disk.new_async_io(1).expect("new_async_io failed"); + + let buf = vec![0xBBu8; QCOW_CLUSTER_SIZE as usize]; + let iovec = write_iovec(&buf); + + let start = Instant::now(); + submit_writes(async_io.as_mut(), num_ops, QCOW_CLUSTER_SIZE, &[iovec]); + let elapsed = start.elapsed().as_secs_f64(); + + drain_completions(async_io.as_mut(), num_ops); + + elapsed +}