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