-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathfs_read_write_seek.rs
145 lines (114 loc) · 5.19 KB
/
fs_read_write_seek.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/* Benchmarks for the microvisor implementation. In general, I'm not doing
* results checking / assertations to avoid adding bias to the results. */
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
use rustposix::interface;
use std::ffi::*;
use std::time::Duration;
use rustposix::safeposix::cage::*;
use rustposix::tests;
// Using this to include my criterion settings from a single shared file.
// I did not use "use" or "mod" because benches/ isn't in the crate's usual
// namespace and I didn't want to either make a separate crate with a single,
// tiny file or add this file to the rustposix crate.
mod global_criterion_settings;
pub fn run_benchmark(c: &mut Criterion) {
// I'm following the initialization workflow from the unit tests here.
//
// I'm using the lindrustinit to set up cages and the file system.
rustposix::safeposix::dispatcher::lindrustinit(0);
// Since all system calls are a method of a cage object, I also need this
// reference.
let cage = interface::cagetable_getref(1);
// --- COMPARING read + write + lseek CALLS ACROSS Lind + Native OS kernel ---
let mut group = c.benchmark_group("Compare fs:write+read+lseek");
// Should be similar. Use a linear scale...
group.plot_config(
criterion::PlotConfiguration::default().summary_scale(criterion::AxisScale::Linear),
);
// Reduce the time to go faster! Default is 5s...
group.measurement_time(Duration::from_secs(2));
// Shorten the warm up time as well from 3s to this...
group.warm_up_time(Duration::from_secs(1));
// --- Lind ---
// Iterate for different buffer sizes...
for buflen in [1, 64, 1024, 65536].iter() {
let fd = cage.open_syscall("foo", O_CREAT | O_TRUNC | O_RDWR, S_IRWXA);
let deststring = tests::str2cbuf(
&String::from_utf8(vec![b'X'; *buflen]).expect("error building string"),
);
// The size of the buffer and the amount we expect to read and write.
// I need to type convert this because it's a usize by default.
// I'm lazily converting with as here because it's not feasible to
// test values where usize would overflow this.
let expected_retval = *buflen as i32;
let read_buffer = tests::sizecbuf(*buflen).as_mut_ptr();
// Let's see how fast various file system calls are
group.bench_with_input(
BenchmarkId::new("TF03:Lind write+read+lseek", buflen),
buflen,
|b, buflen| {
b.iter(|| {
assert_eq!(cage.write_syscall(fd, deststring, *buflen), expected_retval);
assert_eq!(cage.lseek_syscall(fd, 0, SEEK_SET), 0);
assert_eq!(cage.read_syscall(fd, read_buffer, *buflen), expected_retval);
assert_eq!(cage.lseek_syscall(fd, 0, SEEK_SET), 0);
})
},
);
cage.close_syscall(fd);
cage.unlink_syscall("foo");
}
// --- Native ---
// Iterate for different buffer sizes...
for buflen in [1, 64, 1024, 65536].iter() {
let fd: c_int;
let c_str = CString::new("/tmp/foo").unwrap();
let path = c_str.into_raw() as *const u8;
unsafe {
fd = libc::open(path, O_CREAT | O_TRUNC | O_RDWR, S_IRWXA);
}
let deststring = tests::str2cbuf(
&String::from_utf8(vec![b'X'; *buflen]).expect("error building string"),
);
let read_buffer = tests::sizecbuf(*buflen).as_mut_ptr();
// The size of the buffer and the amount we expect to read and write.
// I need to type convert this because it's a usize by default.
// I'm lazily converting with as here because it's not feasible to
// test values where usize would overflow this.
// NOTE: This has a different type than Lind, which is i32. I think
// this is likely okay.
let expected_retval = *buflen as isize;
// For comparison let's time the native OS...
group.bench_with_input(
BenchmarkId::new("TF03:Native write+read+lseek", buflen),
buflen,
|b, buflen| {
b.iter(|| unsafe {
assert_eq!(
libc::write(fd, deststring as *const c_void, *buflen),
expected_retval
);
assert_eq!(libc::lseek(fd, 0, SEEK_SET), 0);
assert_eq!(
libc::read(fd, read_buffer as *mut c_void, *buflen),
expected_retval
);
assert_eq!(libc::lseek(fd, 0, SEEK_SET), 0);
})
},
);
unsafe {
libc::close(fd);
libc::unlink(path);
}
}
group.finish();
// This cleans up in ways I do not fully understand. I think it ensures
// the file system is cleaned up
rustposix::safeposix::dispatcher::lindrustfinalize();
}
criterion_group!(name=benches;
// Add the global settings here so we don't type it everywhere
config=global_criterion_settings::get_criterion();
targets=run_benchmark);
criterion_main!(benches);