Files
cloud-hypervisor/performance-metrics/src/micro_bench_block.rs
Anatol Belski 00957fa9db performance-metrics: Add AIO completion drain micro benchmark
Add micro_block_raw_aio_drain_128_us and
micro_block_raw_aio_drain_256_us tests that submit N AIO writes
to a temporary file, wait for the eventfd signal, then time how
long it takes to drain all completions via next_completed_request().

This measures per completion syscall overhead and provides a
baseline before any batching optimizations.

Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
2026-03-17 22:12:50 +00:00

54 lines
1.7 KiB
Rust

// Copyright 2026 The Cloud Hypervisor Authors. All rights reserved.
//
// SPDX-License-Identifier: Apache-2.0
//! In process micro benchmarks for block layer internals.
//!
//! These run without booting a VM and measure hot path operations
//! (e.g. AIO completion draining) at the syscall level.
use std::os::unix::io::AsRawFd;
use std::time::Instant;
use block::async_io::AsyncIo;
use block::raw_async_aio::RawFileAsyncAio;
use crate::PerformanceTestControl;
use crate::util::{self, BLOCK_SIZE};
/// Submit num_ops AIO writes, wait for them all to land, then time
/// how long it takes to drain every completion via next_completed_request().
///
/// Returns the drain wall clock time in seconds.
pub fn micro_bench_aio_drain(control: &PerformanceTestControl) -> f64 {
let num_ops = control.num_ops.expect("num_ops required") as usize;
let tmp = util::sized_tempfile(num_ops);
let fd = tmp.as_file().as_raw_fd();
let mut aio = RawFileAsyncAio::new(fd, num_ops as u32).expect("failed to create AIO context");
let buf = vec![0xA5u8; BLOCK_SIZE as usize];
// Submit all writes.
for i in 0..num_ops {
let iovec = libc::iovec {
iov_base: buf.as_ptr() as *mut _,
iov_len: buf.len(),
};
aio.write_vectored((i as u64 * BLOCK_SIZE) as libc::off_t, &[iovec], i as u64)
.expect("write_vectored failed");
}
// Wait until the eventfd signals that completions are available.
util::wait_for_eventfd(aio.notifier());
// Drain all completions and measure.
let start = Instant::now();
let mut drained = 0usize;
while drained < num_ops {
if aio.next_completed_request().is_some() {
drained += 1;
}
}
start.elapsed().as_secs_f64()
}