From 16d6a16e5cfc25d5f536ccc3d2affe5b6224e47d Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Sun, 15 Feb 2026 18:05:33 +0100 Subject: [PATCH] performance-metrics: Add standalone qcow2 perf tests Add performance tests for standalone qcow2 images without backing files - uncompressed, zlib and zstd compressed. Each variant includes single queue and multiqueue tests for sequential read, random read and warmed up sequential read. Signed-off-by: Anatol Belski --- performance-metrics/src/main.rs | 278 ++++++++++++++++++- performance-metrics/src/performance_tests.rs | 25 ++ 2 files changed, 302 insertions(+), 1 deletion(-) diff --git a/performance-metrics/src/main.rs b/performance-metrics/src/main.rs index a08e6e15e..c48e5a906 100644 --- a/performance-metrics/src/main.rs +++ b/performance-metrics/src/main.rs @@ -333,7 +333,7 @@ mod adjuster { } } -const TEST_LIST: [PerformanceTest; 42] = [ +const TEST_LIST: [PerformanceTest; 60] = [ PerformanceTest { name: "boot_time_ms", func_ptr: performance_boot_time, @@ -724,6 +724,282 @@ const TEST_LIST: [PerformanceTest; 42] = [ }, unit_adjuster: adjuster::identity, }, + PerformanceTest { + name: "block_qcow2_read_MiBps", + func_ptr: performance_block_io, + control: PerformanceTestControl { + num_queues: Some(1), + queue_size: Some(128), + block_control: Some(BlockControl { + fio_ops: FioOps::Read, + bandwidth: true, + test_file: QCOW2_UNCOMPRESSED_IMG, + }), + ..PerformanceTestControl::default() + }, + unit_adjuster: adjuster::Bps_to_MiBps, + }, + PerformanceTest { + name: "block_qcow2_random_read_MiBps", + func_ptr: performance_block_io, + control: PerformanceTestControl { + num_queues: Some(1), + queue_size: Some(128), + block_control: Some(BlockControl { + fio_ops: FioOps::RandomRead, + bandwidth: true, + test_file: QCOW2_UNCOMPRESSED_IMG, + }), + ..PerformanceTestControl::default() + }, + unit_adjuster: adjuster::Bps_to_MiBps, + }, + PerformanceTest { + name: "block_qcow2_read_warm_MiBps", + func_ptr: performance_block_io, + control: PerformanceTestControl { + num_queues: Some(1), + queue_size: Some(128), + warmup_iterations: 2, + block_control: Some(BlockControl { + fio_ops: FioOps::Read, + bandwidth: true, + test_file: QCOW2_UNCOMPRESSED_IMG, + }), + ..PerformanceTestControl::default() + }, + unit_adjuster: adjuster::Bps_to_MiBps, + }, + PerformanceTest { + name: "block_qcow2_multi_queue_read_MiBps", + func_ptr: performance_block_io, + control: PerformanceTestControl { + num_queues: Some(4), + queue_size: Some(128), + block_control: Some(BlockControl { + fio_ops: FioOps::Read, + bandwidth: true, + test_file: QCOW2_UNCOMPRESSED_IMG, + }), + ..PerformanceTestControl::default() + }, + unit_adjuster: adjuster::Bps_to_MiBps, + }, + PerformanceTest { + name: "block_qcow2_multi_queue_random_read_MiBps", + func_ptr: performance_block_io, + control: PerformanceTestControl { + num_queues: Some(4), + queue_size: Some(128), + block_control: Some(BlockControl { + fio_ops: FioOps::RandomRead, + bandwidth: true, + test_file: QCOW2_UNCOMPRESSED_IMG, + }), + ..PerformanceTestControl::default() + }, + unit_adjuster: adjuster::Bps_to_MiBps, + }, + PerformanceTest { + name: "block_qcow2_multi_queue_read_warm_MiBps", + func_ptr: performance_block_io, + control: PerformanceTestControl { + num_queues: Some(4), + queue_size: Some(128), + warmup_iterations: 2, + block_control: Some(BlockControl { + fio_ops: FioOps::Read, + bandwidth: true, + test_file: QCOW2_UNCOMPRESSED_IMG, + }), + ..PerformanceTestControl::default() + }, + unit_adjuster: adjuster::Bps_to_MiBps, + }, + PerformanceTest { + name: "block_qcow2_zlib_read_MiBps", + func_ptr: performance_block_io, + control: PerformanceTestControl { + num_queues: Some(1), + queue_size: Some(128), + block_control: Some(BlockControl { + fio_ops: FioOps::Read, + bandwidth: true, + test_file: QCOW2_ZLIB_IMG, + }), + ..PerformanceTestControl::default() + }, + unit_adjuster: adjuster::Bps_to_MiBps, + }, + PerformanceTest { + name: "block_qcow2_zlib_random_read_MiBps", + func_ptr: performance_block_io, + control: PerformanceTestControl { + num_queues: Some(1), + queue_size: Some(128), + block_control: Some(BlockControl { + fio_ops: FioOps::RandomRead, + bandwidth: true, + test_file: QCOW2_ZLIB_IMG, + }), + ..PerformanceTestControl::default() + }, + unit_adjuster: adjuster::Bps_to_MiBps, + }, + PerformanceTest { + name: "block_qcow2_zlib_read_warm_MiBps", + func_ptr: performance_block_io, + control: PerformanceTestControl { + num_queues: Some(1), + queue_size: Some(128), + warmup_iterations: 2, + block_control: Some(BlockControl { + fio_ops: FioOps::Read, + bandwidth: true, + test_file: QCOW2_ZLIB_IMG, + }), + ..PerformanceTestControl::default() + }, + unit_adjuster: adjuster::Bps_to_MiBps, + }, + PerformanceTest { + name: "block_qcow2_zlib_multi_queue_read_MiBps", + func_ptr: performance_block_io, + control: PerformanceTestControl { + num_queues: Some(4), + queue_size: Some(128), + block_control: Some(BlockControl { + fio_ops: FioOps::Read, + bandwidth: true, + test_file: QCOW2_ZLIB_IMG, + }), + ..PerformanceTestControl::default() + }, + unit_adjuster: adjuster::Bps_to_MiBps, + }, + PerformanceTest { + name: "block_qcow2_zlib_multi_queue_random_read_MiBps", + func_ptr: performance_block_io, + control: PerformanceTestControl { + num_queues: Some(4), + queue_size: Some(128), + block_control: Some(BlockControl { + fio_ops: FioOps::RandomRead, + bandwidth: true, + test_file: QCOW2_ZLIB_IMG, + }), + ..PerformanceTestControl::default() + }, + unit_adjuster: adjuster::Bps_to_MiBps, + }, + PerformanceTest { + name: "block_qcow2_zlib_multi_queue_read_warm_MiBps", + func_ptr: performance_block_io, + control: PerformanceTestControl { + num_queues: Some(4), + queue_size: Some(128), + warmup_iterations: 2, + block_control: Some(BlockControl { + fio_ops: FioOps::Read, + bandwidth: true, + test_file: QCOW2_ZLIB_IMG, + }), + ..PerformanceTestControl::default() + }, + unit_adjuster: adjuster::Bps_to_MiBps, + }, + PerformanceTest { + name: "block_qcow2_zstd_read_MiBps", + func_ptr: performance_block_io, + control: PerformanceTestControl { + num_queues: Some(1), + queue_size: Some(128), + block_control: Some(BlockControl { + fio_ops: FioOps::Read, + bandwidth: true, + test_file: QCOW2_ZSTD_IMG, + }), + ..PerformanceTestControl::default() + }, + unit_adjuster: adjuster::Bps_to_MiBps, + }, + PerformanceTest { + name: "block_qcow2_zstd_random_read_MiBps", + func_ptr: performance_block_io, + control: PerformanceTestControl { + num_queues: Some(1), + queue_size: Some(128), + block_control: Some(BlockControl { + fio_ops: FioOps::RandomRead, + bandwidth: true, + test_file: QCOW2_ZSTD_IMG, + }), + ..PerformanceTestControl::default() + }, + unit_adjuster: adjuster::Bps_to_MiBps, + }, + PerformanceTest { + name: "block_qcow2_zstd_read_warm_MiBps", + func_ptr: performance_block_io, + control: PerformanceTestControl { + num_queues: Some(1), + queue_size: Some(128), + warmup_iterations: 2, + block_control: Some(BlockControl { + fio_ops: FioOps::Read, + bandwidth: true, + test_file: QCOW2_ZSTD_IMG, + }), + ..PerformanceTestControl::default() + }, + unit_adjuster: adjuster::Bps_to_MiBps, + }, + PerformanceTest { + name: "block_qcow2_zstd_multi_queue_read_MiBps", + func_ptr: performance_block_io, + control: PerformanceTestControl { + num_queues: Some(4), + queue_size: Some(128), + block_control: Some(BlockControl { + fio_ops: FioOps::Read, + bandwidth: true, + test_file: QCOW2_ZSTD_IMG, + }), + ..PerformanceTestControl::default() + }, + unit_adjuster: adjuster::Bps_to_MiBps, + }, + PerformanceTest { + name: "block_qcow2_zstd_multi_queue_random_read_MiBps", + func_ptr: performance_block_io, + control: PerformanceTestControl { + num_queues: Some(4), + queue_size: Some(128), + block_control: Some(BlockControl { + fio_ops: FioOps::RandomRead, + bandwidth: true, + test_file: QCOW2_ZSTD_IMG, + }), + ..PerformanceTestControl::default() + }, + unit_adjuster: adjuster::Bps_to_MiBps, + }, + PerformanceTest { + name: "block_qcow2_zstd_multi_queue_read_warm_MiBps", + func_ptr: performance_block_io, + control: PerformanceTestControl { + num_queues: Some(4), + queue_size: Some(128), + warmup_iterations: 2, + block_control: Some(BlockControl { + fio_ops: FioOps::Read, + bandwidth: true, + test_file: QCOW2_ZSTD_IMG, + }), + ..PerformanceTestControl::default() + }, + unit_adjuster: adjuster::Bps_to_MiBps, + }, PerformanceTest { name: "block_qcow2_backing_qcow2_read_MiBps", func_ptr: performance_block_io, diff --git a/performance-metrics/src/performance_tests.rs b/performance-metrics/src/performance_tests.rs index 6e84fdd8e..b959fce5c 100644 --- a/performance-metrics/src/performance_tests.rs +++ b/performance-metrics/src/performance_tests.rs @@ -37,6 +37,9 @@ const QCOW2_BACKING_FILE: &str = "/var/tmp/ch-blk-io-test-qcow2-backing.qcow2"; pub const OVERLAY_WITH_QCOW2_BACKING: &str = "/var/tmp/ch-blk-io-test-overlay-qcow2.qcow2"; const RAW_BACKING_FILE: &str = "/var/tmp/ch-blk-io-test-raw-backing.raw"; pub const OVERLAY_WITH_RAW_BACKING: &str = "/var/tmp/ch-blk-io-test-overlay-raw.qcow2"; +pub const QCOW2_UNCOMPRESSED_IMG: &str = "/var/tmp/ch-blk-io-test-uncompressed.qcow2"; +pub const QCOW2_ZLIB_IMG: &str = "/var/tmp/ch-blk-io-test-zlib.qcow2"; +pub const QCOW2_ZSTD_IMG: &str = "/var/tmp/ch-blk-io-test-zstd.qcow2"; pub fn init_tests(overrides: &PerformanceTestOverrides) { let mut cmd = format!("dd if=/dev/zero of={BLK_IO_TEST_IMG} bs=1M count=4096"); @@ -78,6 +81,22 @@ pub fn init_tests(overrides: &PerformanceTestOverrides) { "qemu-img create -f qcow2 -b {RAW_BACKING_FILE} -F raw {OVERLAY_WITH_RAW_BACKING} 4G" ); assert!(exec_host_command_output(&cmd).status.success()); + + // Standalone QCOW2 image with no backing file + cmd = format!("qemu-img create -f qcow2 -o preallocation=full {QCOW2_UNCOMPRESSED_IMG} 4G"); + assert!(exec_host_command_output(&cmd).status.success()); + + // Zlib compressed QCOW2 image, convert populates actual compressed clusters + cmd = format!( + "qemu-img convert -f qcow2 -O qcow2 -c -o compression_type=zlib {QCOW2_UNCOMPRESSED_IMG} {QCOW2_ZLIB_IMG}" + ); + assert!(exec_host_command_output(&cmd).status.success()); + + // Zstd compressed QCOW2 image, convert populates actual compressed clusters + cmd = format!( + "qemu-img convert -f qcow2 -O qcow2 -c -o compression_type=zstd {QCOW2_UNCOMPRESSED_IMG} {QCOW2_ZSTD_IMG}" + ); + assert!(exec_host_command_output(&cmd).status.success()); } pub fn cleanup_tests() { @@ -91,6 +110,12 @@ pub fn cleanup_tests() { .unwrap_or_else(|_| panic!("Failed to remove file '{RAW_BACKING_FILE}'.")); fs::remove_file(OVERLAY_WITH_RAW_BACKING) .unwrap_or_else(|_| panic!("Failed to remove file '{OVERLAY_WITH_RAW_BACKING}'.")); + fs::remove_file(QCOW2_UNCOMPRESSED_IMG) + .unwrap_or_else(|_| panic!("Failed to remove file '{QCOW2_UNCOMPRESSED_IMG}'.")); + fs::remove_file(QCOW2_ZLIB_IMG) + .unwrap_or_else(|_| panic!("Failed to remove file '{QCOW2_ZLIB_IMG}'.")); + fs::remove_file(QCOW2_ZSTD_IMG) + .unwrap_or_else(|_| panic!("Failed to remove file '{QCOW2_ZSTD_IMG}'.")); } // Performance tests are expected to be executed sequentially, so we can