Skip to content

Commit 87aed3e

Browse files
committed
Add new benchmarks for varying sizes of sandboxes and guest function parameters
Signed-off-by: Ludvig Liljenberg <[email protected]>
1 parent 9ad8569 commit 87aed3e

File tree

1 file changed

+196
-31
lines changed

1 file changed

+196
-31
lines changed

src/hyperlight_host/benches/benchmarks.rs

Lines changed: 196 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -30,19 +30,75 @@ fn create_multiuse_sandbox() -> MultiUseSandbox {
3030
create_uninit_sandbox().evolve().unwrap()
3131
}
3232

33+
fn create_sandbox_with_heap_size(heap_size_mb: Option<u64>) -> MultiUseSandbox {
34+
let path = simple_guest_as_string().unwrap();
35+
let config = if let Some(size_mb) = heap_size_mb {
36+
let mut config = SandboxConfiguration::default();
37+
config.set_heap_size(size_mb * 1024 * 1024); // Convert MB to bytes
38+
Some(config)
39+
} else {
40+
None
41+
};
42+
43+
let uninit_sandbox = UninitializedSandbox::new(GuestBinary::FilePath(path), config).unwrap();
44+
uninit_sandbox.evolve().unwrap()
45+
}
46+
3347
fn guest_call_benchmark(c: &mut Criterion) {
3448
let mut group = c.benchmark_group("guest_functions");
3549

36-
// Benchmarks a single guest function call.
37-
// The benchmark does **not** include the time to reset the sandbox memory after the call.
50+
// Single guest function call.
3851
group.bench_function("guest_call", |b| {
3952
let mut sbox = create_multiuse_sandbox();
4053

4154
b.iter(|| sbox.call::<String>("Echo", "hello\n".to_string()).unwrap());
4255
});
4356

44-
// Benchmarks a single guest function call.
45-
// The benchmark does include the time to reset the sandbox memory after the call.
57+
// Single snapshot restore after a guest function call.
58+
group.bench_function("guest_restore", |b| {
59+
let mut sbox = create_multiuse_sandbox();
60+
let snapshot = sbox.snapshot().unwrap();
61+
62+
b.iter_custom(|iters| {
63+
let mut total_duration = std::time::Duration::ZERO;
64+
65+
for _ in 0..iters {
66+
// Dirty some pages
67+
sbox.call::<String>("Echo", "hello\n".to_string()).unwrap();
68+
69+
// Measure only the restore operation
70+
let start = std::time::Instant::now();
71+
sbox.restore(&snapshot).unwrap();
72+
total_duration += start.elapsed();
73+
}
74+
75+
total_duration
76+
});
77+
});
78+
79+
// Single guest function call after a restore.
80+
group.bench_function("guest_call_after_restore", |b| {
81+
let mut sbox = create_multiuse_sandbox();
82+
let snapshot = sbox.snapshot().unwrap();
83+
84+
b.iter_custom(|iters| {
85+
let mut total_duration = std::time::Duration::ZERO;
86+
87+
for _ in 0..iters {
88+
// Restore (not timed)
89+
sbox.restore(&snapshot).unwrap();
90+
91+
// Measure only the guest function call
92+
let start = std::time::Instant::now();
93+
sbox.call::<String>("Echo", "hello\n".to_string()).unwrap();
94+
total_duration += start.elapsed();
95+
}
96+
97+
total_duration
98+
});
99+
});
100+
101+
// Single guest function call with a snapshot restore after
46102
group.bench_function("guest_call_with_restore", |b| {
47103
let mut sbox = create_multiuse_sandbox();
48104
let snapshot = sbox.snapshot().unwrap();
@@ -53,8 +109,7 @@ fn guest_call_benchmark(c: &mut Criterion) {
53109
});
54110
});
55111

56-
// Benchmarks a guest function call calling into the host.
57-
// The benchmark does **not** include the time to reset the sandbox memory after the call.
112+
// Single guest function call which includes a call to a host function.
58113
group.bench_function("guest_call_with_call_to_host_function", |b| {
59114
let mut uninitialized_sandbox = create_uninit_sandbox();
60115

@@ -75,37 +130,58 @@ fn guest_call_benchmark(c: &mut Criterion) {
75130
group.finish();
76131
}
77132

78-
fn guest_call_benchmark_large_param(c: &mut Criterion) {
79-
let mut group = c.benchmark_group("guest_functions_with_large_parameters");
133+
// Guest function call and restore, with large parameters passed as arguments.
134+
fn guest_call_benchmark_large_params(c: &mut Criterion) {
135+
let mut group = c.benchmark_group("2_large_parameters");
80136
#[cfg(target_os = "windows")]
81137
group.sample_size(10); // This benchmark is very slow on Windows, so we reduce the sample size to avoid long test runs.
82138

83-
// This benchmark includes time to first clone a vector and string, so it is not a "pure' benchmark of the guest call, but it's still useful
84-
group.bench_function("guest_call_with_large_parameters", |b| {
85-
const SIZE: usize = 50 * 1024 * 1024; // 50 MB
86-
let large_vec = vec![0u8; SIZE];
87-
let large_string = unsafe { String::from_utf8_unchecked(large_vec.clone()) }; // Safety: indeed above vec is valid utf8
139+
// Parameter sizes to test in MB. Each guest call will use two parameters of this size (vec and str).
140+
const PARAM_SIZES_MB: &[u64] = &[5, 20, 60];
88141

89-
let mut config = SandboxConfiguration::default();
90-
config.set_input_data_size(2 * SIZE + (1024 * 1024)); // 2 * SIZE + 1 MB, to allow 1MB for the rest of the serialized function call
91-
config.set_heap_size(SIZE as u64 * 15);
142+
for &param_size_mb in PARAM_SIZES_MB {
143+
let benchmark_name = format!("guest_call_restore_{}mb_params", param_size_mb);
144+
group.bench_function(&benchmark_name, |b| {
145+
let param_size_bytes = param_size_mb * 1024 * 1024;
92146

93-
let sandbox = UninitializedSandbox::new(
94-
GuestBinary::FilePath(simple_guest_as_string().unwrap()),
95-
Some(config),
96-
)
97-
.unwrap();
98-
let mut sandbox = sandbox.evolve().unwrap();
147+
let large_vec = vec![0u8; param_size_bytes as usize];
148+
let large_string = String::from_utf8(large_vec.clone()).unwrap();
99149

100-
b.iter(|| {
101-
sandbox
102-
.call_guest_function_by_name::<()>(
103-
"LargeParameters",
104-
(large_vec.clone(), large_string.clone()),
105-
)
106-
.unwrap()
150+
let mut config = SandboxConfiguration::default();
151+
config.set_heap_size(600 * 1024 * 1024);
152+
config.set_input_data_size(300 * 1024 * 1024);
153+
154+
let sandbox = UninitializedSandbox::new(
155+
GuestBinary::FilePath(simple_guest_as_string().unwrap()),
156+
Some(config),
157+
)
158+
.unwrap();
159+
let mut sandbox = sandbox.evolve().unwrap();
160+
let snapshot = sandbox.snapshot().unwrap();
161+
162+
// Iter_custom to avoid measure clone time of params
163+
b.iter_custom(|iters| {
164+
let mut total_duration = std::time::Duration::ZERO;
165+
166+
for _ in 0..iters {
167+
let vec_clone = large_vec.clone();
168+
let string_clone = large_string.clone();
169+
170+
let start = std::time::Instant::now();
171+
sandbox
172+
.call_guest_function_by_name::<()>(
173+
"LargeParameters",
174+
(vec_clone, string_clone),
175+
)
176+
.unwrap();
177+
sandbox.restore(&snapshot).unwrap();
178+
total_duration += start.elapsed();
179+
}
180+
181+
total_duration
182+
});
107183
});
108-
});
184+
}
109185

110186
group.finish();
111187
}
@@ -138,9 +214,98 @@ fn sandbox_benchmark(c: &mut Criterion) {
138214
group.finish();
139215
}
140216

217+
// Sandbox creation with different heap sizes
218+
fn sandbox_heap_size_benchmark(c: &mut Criterion) {
219+
let mut group = c.benchmark_group("sandbox_heap_sizes");
220+
221+
const HEAP_SIZES_MB: &[Option<u64>] = &[None, Some(50), Some(500), Some(995)];
222+
223+
// Benchmark sandbox creation with different heap sizes (including default)
224+
for &heap_size_mb in HEAP_SIZES_MB {
225+
let benchmark_name = match heap_size_mb {
226+
None => "create_sandbox_default_heap".to_string(),
227+
Some(size) => format!("create_sandbox_{}mb_heap", size),
228+
};
229+
group.bench_function(&benchmark_name, |b| {
230+
b.iter_with_large_drop(|| create_sandbox_with_heap_size(heap_size_mb));
231+
});
232+
}
233+
234+
group.finish();
235+
}
236+
237+
// Guest function call and restore with different heap sizes
238+
fn guest_call_heap_size_benchmark(c: &mut Criterion) {
239+
let mut group = c.benchmark_group("guest_call_restore_heap_sizes");
240+
241+
const HEAP_SIZES_MB: &[Option<u64>] = &[None, Some(50), Some(500), Some(995)];
242+
243+
// Benchmark guest function call with different heap sizes (including default)
244+
for &heap_size_mb in HEAP_SIZES_MB {
245+
let benchmark_name = match heap_size_mb {
246+
None => "guest_call_restore_default_heap".to_string(),
247+
Some(size) => format!("guest_call_restore_{}mb_heap", size),
248+
};
249+
group.bench_function(&benchmark_name, |b| {
250+
let mut sandbox = create_sandbox_with_heap_size(heap_size_mb);
251+
let snapshot = sandbox.snapshot().unwrap();
252+
253+
b.iter(|| {
254+
sandbox
255+
.call_guest_function_by_name::<String>("Echo", "hello\n".to_string())
256+
.unwrap();
257+
sandbox.restore(&snapshot).unwrap();
258+
});
259+
});
260+
}
261+
262+
group.finish();
263+
}
264+
265+
// Snapshot creation with varying heap size
266+
fn snapshot_benchmark(c: &mut Criterion) {
267+
let mut group = c.benchmark_group("snapshot");
268+
269+
const HEAP_SIZES_MB: &[Option<u64>] = &[None, Some(50), Some(500), Some(995)];
270+
271+
for &heap_size_mb in HEAP_SIZES_MB {
272+
let benchmark_name = match heap_size_mb {
273+
None => "default_heap".to_string(),
274+
Some(size) => format!("{}_mb_heap", size),
275+
};
276+
group.bench_function(&benchmark_name, |b| {
277+
let mut sandbox = create_sandbox_with_heap_size(heap_size_mb);
278+
let original_state = sandbox.snapshot().unwrap();
279+
280+
b.iter_custom(|iters| {
281+
let mut total_duration = std::time::Duration::ZERO;
282+
283+
for _ in 0..iters {
284+
// Dirty some pages
285+
sandbox
286+
.call::<String>("Echo", "hello\n".to_string())
287+
.unwrap();
288+
289+
// Measure only the snapshot operation
290+
let start = std::time::Instant::now();
291+
let _snapshot = sandbox.snapshot().unwrap();
292+
total_duration += start.elapsed();
293+
294+
// Restore the original state to avoid accumulating snapshots
295+
sandbox.restore(&original_state).unwrap();
296+
}
297+
298+
total_duration
299+
});
300+
});
301+
}
302+
303+
group.finish();
304+
}
305+
141306
criterion_group! {
142307
name = benches;
143308
config = Criterion::default();
144-
targets = guest_call_benchmark, sandbox_benchmark, guest_call_benchmark_large_param
309+
targets = guest_call_benchmark, sandbox_benchmark, sandbox_heap_size_benchmark, guest_call_benchmark_large_params, guest_call_heap_size_benchmark, snapshot_benchmark
145310
}
146311
criterion_main!(benches);

0 commit comments

Comments
 (0)