1 // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 // SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
3 
4 use criterion::{black_box, BatchSize, Criterion};
5 use virtio_queue::{Queue, QueueOwnedT, QueueT};
6 use vm_memory::{GuestAddress, GuestMemory, GuestMemoryMmap};
7 
8 use virtio_queue::mock::MockSplitQueue;
9 
benchmark_queue(c: &mut Criterion)10 pub fn benchmark_queue(c: &mut Criterion) {
11     fn walk_queue<M: GuestMemory>(q: &mut Queue, mem: &M) -> (usize, usize) {
12         let mut num_chains = 0;
13         let mut num_descriptors = 0;
14 
15         q.iter(mem).unwrap().for_each(|chain| {
16             num_chains += 1;
17             chain.for_each(|_| num_descriptors += 1);
18         });
19 
20         (num_chains, num_descriptors)
21     }
22 
23     fn bench_queue<S, R>(c: &mut Criterion, bench_name: &str, setup: S, mut routine: R)
24     where
25         S: FnMut() -> Queue + Clone,
26         R: FnMut(Queue),
27     {
28         c.bench_function(bench_name, move |b| {
29             b.iter_batched(
30                 setup.clone(),
31                 |q| routine(black_box(q)),
32                 BatchSize::SmallInput,
33             )
34         });
35     }
36 
37     let mem = GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0x0), 0x1_0000_0000)]).unwrap();
38 
39     let queue_with_chains = |num_chains, len, indirect| {
40         let mut mq = MockSplitQueue::new(&mem, 256);
41         for _ in 0..num_chains {
42             if indirect {
43                 mq.add_indirect_chain(len).unwrap();
44             } else {
45                 mq.add_chain(len).unwrap();
46             }
47         }
48         mq.create_queue().unwrap()
49     };
50 
51     let empty_queue = || {
52         let mq = MockSplitQueue::new(&mem, 256);
53         mq.create_queue().unwrap()
54     };
55 
56     for indirect in [false, true].iter().copied() {
57         bench_queue(
58             c,
59             &format!("single chain (indirect={})", indirect),
60             || queue_with_chains(1, 128, indirect),
61             |mut q| {
62                 let (num_chains, num_descriptors) = walk_queue(&mut q, &mem);
63                 assert_eq!(num_chains, 1);
64                 assert_eq!(num_descriptors, 128);
65             },
66         );
67 
68         bench_queue(
69             c,
70             &format!("multiple chains (indirect={})", indirect),
71             || queue_with_chains(128, 1, indirect),
72             |mut q| {
73                 let (num_chains, num_descriptors) = walk_queue(&mut q, &mem);
74                 assert_eq!(num_chains, 128);
75                 assert_eq!(num_descriptors, 128);
76             },
77         );
78     }
79 
80     bench_queue(c, "add used", empty_queue, |mut q| {
81         for _ in 0..128 {
82             q.add_used(&mem, 123, 0x1000).unwrap();
83         }
84     });
85 }
86