// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause use criterion::{black_box, BatchSize, Criterion}; use virtio_queue::{Queue, QueueOwnedT, QueueT}; use vm_memory::{GuestAddress, GuestMemory, GuestMemoryMmap}; use virtio_queue::mock::MockSplitQueue; pub fn benchmark_queue(c: &mut Criterion) { fn walk_queue(q: &mut Queue, mem: &M) -> (usize, usize) { let mut num_chains = 0; let mut num_descriptors = 0; q.iter(mem).unwrap().for_each(|chain| { num_chains += 1; chain.for_each(|_| num_descriptors += 1); }); (num_chains, num_descriptors) } fn bench_queue(c: &mut Criterion, bench_name: &str, setup: S, mut routine: R) where S: FnMut() -> Queue + Clone, R: FnMut(Queue), { c.bench_function(bench_name, move |b| { b.iter_batched( setup.clone(), |q| routine(black_box(q)), BatchSize::SmallInput, ) }); } let mem = GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0x0), 0x1_0000_0000)]).unwrap(); let queue_with_chains = |num_chains, len, indirect| { let mut mq = MockSplitQueue::new(&mem, 256); for _ in 0..num_chains { if indirect { mq.add_indirect_chain(len).unwrap(); } else { mq.add_chain(len).unwrap(); } } mq.create_queue().unwrap() }; let empty_queue = || { let mq = MockSplitQueue::new(&mem, 256); mq.create_queue().unwrap() }; for indirect in [false, true].iter().copied() { bench_queue( c, &format!("single chain (indirect={})", indirect), || queue_with_chains(1, 128, indirect), |mut q| { let (num_chains, num_descriptors) = walk_queue(&mut q, &mem); assert_eq!(num_chains, 1); assert_eq!(num_descriptors, 128); }, ); bench_queue( c, &format!("multiple chains (indirect={})", indirect), || queue_with_chains(128, 1, indirect), |mut q| { let (num_chains, num_descriptors) = walk_queue(&mut q, &mem); assert_eq!(num_chains, 128); assert_eq!(num_descriptors, 128); }, ); } bench_queue(c, "add used", empty_queue, |mut q| { for _ in 0..128 { q.add_used(&mem, 123, 0x1000).unwrap(); } }); }