From c3312dca3ff0cf275f50095e1ee6775c9ee525db Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Sun, 15 Mar 2026 14:13:46 +0100 Subject: [PATCH] performance-metrics: Add qcow2 punch hole micro benchmark Add micro_bench_qcow_punch_hole which times punch_hole calls through QcowSync on a prepopulated qcow2 image. Each call deallocates one cluster exercising deallocate_bytes with refcount decrement and fallocate punch_hole on the host file. Two TEST_LIST entries: micro_block_qcow_punch_hole_64_us and micro_block_qcow_punch_hole_256_us with 64 and 256 cluster workloads. 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 225212b8f..93ab45e31 100644 --- a/performance-metrics/src/main.rs +++ b/performance-metrics/src/main.rs @@ -378,7 +378,7 @@ mod adjuster { } } -const TEST_LIST: [PerformanceTest; 66] = [ +const TEST_LIST: [PerformanceTest; 68] = [ PerformanceTest { name: "boot_time_ms", func_ptr: performance_boot_time, @@ -1301,6 +1301,30 @@ const TEST_LIST: [PerformanceTest; 66] = [ }, unit_adjuster: adjuster::s_to_us, }, + PerformanceTest { + name: "micro_block_qcow_punch_hole_128_us", + func_ptr: micro_bench_block::micro_bench_qcow_punch_hole, + 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_punch_hole_256_us", + func_ptr: micro_bench_block::micro_bench_qcow_punch_hole, + 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 d02e99762..2ebde205f 100644 --- a/performance-metrics/src/micro_bench_block.rs +++ b/performance-metrics/src/micro_bench_block.rs @@ -106,3 +106,29 @@ pub fn micro_bench_qcow_write(control: &PerformanceTestControl) -> f64 { elapsed } + +/// Punch holes for num_ops clusters in a prepopulated qcow2 image through +/// the QcowSync async_io path and time the total punch_hole wall clock. +/// +/// This exercises the discard path: deallocate_bytes decrements refcounts, +/// frees clusters and issues fallocate punch_hole on the host file. +/// +/// Returns the total punch_hole wall clock time in seconds. +pub fn micro_bench_qcow_punch_hole(control: &PerformanceTestControl) -> f64 { + let num_ops = control.num_ops.expect("num_ops required") as usize; + let (_tmp, disk) = util::qcow_tempfile(num_ops); + let mut async_io = disk.new_async_io(1).expect("new_async_io failed"); + + let start = Instant::now(); + for i in 0..num_ops { + async_io + .punch_hole(i as u64 * QCOW_CLUSTER_SIZE, QCOW_CLUSTER_SIZE, i as u64) + .expect("punch_hole failed"); + } + let elapsed = start.elapsed().as_secs_f64(); + + // Drain completions so Drop is clean. + drain_completions(async_io.as_mut(), num_ops); + + elapsed +}