Skip to content

Commit 0eeb18c

Browse files
lauraltjiangliu
authored andcommitted
Add basic performance tests
Added tests that measure the durations of read and write operations from Bytes trait. These tests are applied only on Bytes implementation from GuestRegionMmap. To run the benches use: `cargo bench --bench main --features backend-mmap`. Signed-off-by: Laura Loghin <[email protected]> Signed-off-by: Alexandru Agache <[email protected]>
1 parent cbac816 commit 0eeb18c

File tree

4 files changed

+268
-1
lines changed

4 files changed

+268
-1
lines changed

Cargo.toml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ repository = "https://github.com/rust-vmm/vm-memory"
88
readme = "README.md"
99
license = "Apache-2.0 OR BSD-3-Clause"
1010
edition = "2018"
11+
autobenches = false
1112

1213
[features]
1314
default = []
@@ -24,5 +25,14 @@ version = ">=0.3"
2425
features = ["errhandlingapi"]
2526

2627
[dev-dependencies]
28+
criterion = "0.3.0"
2729
matches = ">=0"
2830
vmm-sys-util = ">= 0.4.0"
31+
32+
[[bench]]
33+
name = "main"
34+
harness = false
35+
36+
[profile.bench]
37+
lto = true
38+
codegen-units = 1

benches/main.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
//
3+
// Use of this source code is governed by a BSD-style license that can be
4+
// found in the LICENSE-BSD-3-Clause file.
5+
//
6+
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
7+
8+
extern crate criterion;
9+
10+
pub use criterion::{black_box, criterion_group, criterion_main, Criterion};
11+
12+
mod mmap;
13+
14+
#[cfg(feature = "backend-mmap")]
15+
use mmap::benchmark_for_mmap;
16+
17+
pub fn criterion_benchmark(_c: &mut Criterion) {
18+
#[cfg(feature = "backend-mmap")]
19+
benchmark_for_mmap(_c);
20+
}
21+
22+
criterion_group! {
23+
name = benches;
24+
config = Criterion::default().sample_size(200).measurement_time(std::time::Duration::from_secs(50));
25+
targets = criterion_benchmark
26+
}
27+
28+
criterion_main! {
29+
benches,
30+
}

benches/mmap/mod.rs

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
//
3+
// Use of this source code is governed by a BSD-style license that can be
4+
// found in the LICENSE-BSD-3-Clause file.
5+
//
6+
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
7+
#![cfg(feature = "backend-mmap")]
8+
9+
extern crate criterion;
10+
extern crate vm_memory;
11+
extern crate vmm_sys_util;
12+
13+
use std::fs::{File, OpenOptions};
14+
use std::io::Cursor;
15+
use std::mem::size_of;
16+
use std::path::Path;
17+
18+
use criterion::{black_box, Criterion};
19+
20+
use vm_memory::{ByteValued, Bytes, GuestAddress, GuestMemory, GuestMemoryMmap};
21+
22+
const REGION_SIZE: u64 = 0x8000_0000;
23+
const REGIONS_COUNT: u64 = 8;
24+
const ACCESS_SIZE: usize = 0x200;
25+
26+
#[repr(C)]
27+
#[derive(Copy, Clone, Default)]
28+
struct SmallDummy {
29+
a: u32,
30+
b: u32,
31+
}
32+
unsafe impl ByteValued for SmallDummy {}
33+
34+
#[repr(C)]
35+
#[derive(Copy, Clone, Default)]
36+
struct BigDummy {
37+
elements: [u64; 12],
38+
}
39+
40+
unsafe impl ByteValued for BigDummy {}
41+
42+
fn make_image(size: usize) -> Vec<u8> {
43+
let mut image: Vec<u8> = Vec::with_capacity(size);
44+
for i in 0..size {
45+
// We just want some different numbers here, so the conversion is OK.
46+
image.push(i as u8);
47+
}
48+
image
49+
}
50+
51+
enum AccessKind {
52+
// The parameter represents the index of the region where the access should happen.
53+
// Indices are 0-based.
54+
InRegion(u64),
55+
// The parameter represents the index of the first region (i.e. where the access starts).
56+
CrossRegion(u64),
57+
}
58+
59+
impl AccessKind {
60+
fn make_offset(&self, access_size: usize) -> u64 {
61+
match *self {
62+
AccessKind::InRegion(idx) => REGION_SIZE * idx,
63+
AccessKind::CrossRegion(idx) => REGION_SIZE * (idx + 1) - (access_size / 2) as u64,
64+
}
65+
}
66+
}
67+
68+
pub fn benchmark_for_mmap(c: &mut Criterion) {
69+
let mut regions: Vec<(GuestAddress, usize)> = Vec::new();
70+
for i in 0..REGIONS_COUNT {
71+
regions.push((GuestAddress(i * REGION_SIZE), REGION_SIZE as usize));
72+
}
73+
74+
let memory = GuestMemoryMmap::from_ranges(regions.as_slice()).unwrap();
75+
// Just a sanity check.
76+
assert_eq!(
77+
memory.last_addr(),
78+
GuestAddress(REGION_SIZE * REGIONS_COUNT - 0x01)
79+
);
80+
81+
let some_small_dummy = SmallDummy {
82+
a: 0x1111_2222,
83+
b: 0x3333_4444,
84+
};
85+
86+
let some_big_dummy = BigDummy {
87+
elements: [0x1111_2222_3333_4444; 12],
88+
};
89+
90+
let mut image = make_image(ACCESS_SIZE);
91+
let buf = &mut [0u8; ACCESS_SIZE];
92+
let mut file = File::open(Path::new("/dev/zero")).expect("Could not open /dev/zero");
93+
let mut file_to_write = OpenOptions::new()
94+
.write(true)
95+
.open("/dev/null")
96+
.expect("Could not open /dev/null");
97+
98+
let accesses = &[
99+
AccessKind::InRegion(0),
100+
AccessKind::CrossRegion(0),
101+
AccessKind::CrossRegion(REGIONS_COUNT - 2),
102+
AccessKind::InRegion(REGIONS_COUNT - 1),
103+
];
104+
105+
for access in accesses {
106+
let offset = access.make_offset(ACCESS_SIZE);
107+
let address = GuestAddress(offset);
108+
109+
// Check performance for read operations.
110+
c.bench_function(format!("read_from_{:#0X}", offset).as_str(), |b| {
111+
b.iter(|| {
112+
black_box(
113+
memory
114+
.read_from(address, &mut Cursor::new(&image), ACCESS_SIZE)
115+
.unwrap(),
116+
)
117+
})
118+
});
119+
120+
c.bench_function(format!("read_from_file_{:#0X}", offset).as_str(), |b| {
121+
b.iter(|| black_box(memory.read_from(address, &mut file, ACCESS_SIZE).unwrap()))
122+
});
123+
124+
c.bench_function(format!("read_exact_from_{:#0X}", offset).as_str(), |b| {
125+
b.iter(|| {
126+
black_box(
127+
memory
128+
.read_exact_from(address, &mut Cursor::new(&mut image), ACCESS_SIZE)
129+
.unwrap(),
130+
)
131+
})
132+
});
133+
134+
c.bench_function(
135+
format!("read_entire_slice_from_{:#0X}", offset).as_str(),
136+
|b| b.iter(|| black_box(memory.read_slice(buf, address).unwrap())),
137+
);
138+
139+
c.bench_function(format!("read_slice_from_{:#0X}", offset).as_str(), |b| {
140+
b.iter(|| black_box(memory.read(buf, address).unwrap()))
141+
});
142+
143+
let obj_off = access.make_offset(size_of::<SmallDummy>());
144+
let obj_addr = GuestAddress(obj_off);
145+
146+
c.bench_function(
147+
format!("read_small_obj_from_{:#0X}", obj_off).as_str(),
148+
|b| b.iter(|| black_box(memory.read_obj::<SmallDummy>(obj_addr).unwrap())),
149+
);
150+
151+
let obj_off = access.make_offset(size_of::<BigDummy>());
152+
let obj_addr = GuestAddress(obj_off);
153+
154+
c.bench_function(format!("read_big_obj_from_{:#0X}", obj_off).as_str(), |b| {
155+
b.iter(|| black_box(memory.read_obj::<BigDummy>(obj_addr).unwrap()))
156+
});
157+
158+
// Check performance for write operations.
159+
c.bench_function(format!("write_to_{:#0X}", offset).as_str(), |b| {
160+
b.iter(|| {
161+
black_box(
162+
memory
163+
.write_to(address, &mut Cursor::new(&mut image), ACCESS_SIZE)
164+
.unwrap(),
165+
)
166+
})
167+
});
168+
169+
c.bench_function(format!("write_to_file_{:#0X}", offset).as_str(), |b| {
170+
b.iter(|| {
171+
black_box(
172+
memory
173+
.write_to(address, &mut file_to_write, ACCESS_SIZE)
174+
.unwrap(),
175+
)
176+
})
177+
});
178+
179+
c.bench_function(format!("write_exact_to_{:#0x}", offset).as_str(), |b| {
180+
b.iter(|| {
181+
black_box(
182+
memory
183+
.write_all_to(address, &mut Cursor::new(&mut image), ACCESS_SIZE)
184+
.unwrap(),
185+
)
186+
})
187+
});
188+
189+
c.bench_function(
190+
format!("write_entire_slice_to_{:#0X}", offset).as_str(),
191+
|b| b.iter(|| black_box(memory.write_slice(buf, address).unwrap())),
192+
);
193+
194+
c.bench_function(format!("write_slice_to_{:#0X}", offset).as_str(), |b| {
195+
b.iter(|| black_box(memory.write(buf, address).unwrap()))
196+
});
197+
198+
let obj_off = access.make_offset(size_of::<SmallDummy>());
199+
let obj_addr = GuestAddress(obj_off);
200+
201+
c.bench_function(
202+
format!("write_small_obj_to_{:#0X}", obj_off).as_str(),
203+
|b| {
204+
b.iter(|| {
205+
black_box(
206+
memory
207+
.write_obj::<SmallDummy>(some_small_dummy, obj_addr)
208+
.unwrap(),
209+
)
210+
})
211+
},
212+
);
213+
214+
let obj_off = access.make_offset(size_of::<BigDummy>());
215+
let obj_addr = GuestAddress(obj_off);
216+
217+
c.bench_function(format!("write_big_obj_to_{:#0X}", obj_off).as_str(), |b| {
218+
b.iter(|| {
219+
black_box(
220+
memory
221+
.write_obj::<BigDummy>(some_big_dummy, obj_addr)
222+
.unwrap(),
223+
)
224+
})
225+
});
226+
}
227+
}

src/bytes.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,6 @@ mod tests {
438438
let mut s: S = Default::default();
439439
s.as_bytes().copy_from(&a);
440440
assert_eq!(s.a, 0);
441-
assert_eq!(s.b, 0x1010101);
441+
assert_eq!(s.b, 0x0101_0101);
442442
}
443443
}

0 commit comments

Comments
 (0)