@@ -30,6 +30,20 @@ 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+
3347fn guest_call_benchmark ( c : & mut Criterion ) {
3448 let mut group = c. benchmark_group ( "guest_functions" ) ;
3549
@@ -41,6 +55,18 @@ fn guest_call_benchmark(c: &mut Criterion) {
4155 b. iter ( || sbox. call :: < String > ( "Echo" , "hello\n " . to_string ( ) ) . unwrap ( ) ) ;
4256 } ) ;
4357
58+ // Benchmarks a single guest restore after a guest function call.
59+ // The benchmark only includes the time to reset the sandbox memory after the call.
60+ group. bench_function ( "guest_restore" , |b| {
61+ let mut sbox = create_multiuse_sandbox ( ) ;
62+ let snapshot = sbox. snapshot ( ) . unwrap ( ) ;
63+ sbox. call :: < String > ( "Echo" , "hello\n " . to_string ( ) ) . unwrap ( ) ;
64+
65+ b. iter ( || {
66+ sbox. restore ( & snapshot) . unwrap ( ) ;
67+ } ) ;
68+ } ) ;
69+
4470 // Benchmarks a single guest function call.
4571 // The benchmark does include the time to reset the sandbox memory after the call.
4672 group. bench_function ( "guest_call_with_restore" , |b| {
@@ -75,37 +101,57 @@ fn guest_call_benchmark(c: &mut Criterion) {
75101 group. finish ( ) ;
76102}
77103
78- fn guest_call_benchmark_large_param ( c : & mut Criterion ) {
79- let mut group = c. benchmark_group ( "guest_functions_with_large_parameters " ) ;
104+ fn guest_call_benchmark_large_params ( c : & mut Criterion ) {
105+ let mut group = c. benchmark_group ( "2_large_parameters " ) ;
80106 #[ cfg( target_os = "windows" ) ]
81107 group. sample_size ( 10 ) ; // This benchmark is very slow on Windows, so we reduce the sample size to avoid long test runs.
82108
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
109+ // Parameter sizes to test in MB. Each guest call will use two parameters of this size (vec and str).
110+ const PARAM_SIZES_MB : & [ u64 ] = & [ 5 , 10 , 20 , 40 , 60 ] ;
88111
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 ) ;
112+ for & param_size_mb in PARAM_SIZES_MB {
113+ let benchmark_name = format ! ( "guest_call_restore_{}mb_params" , param_size_mb) ;
114+ group. bench_function ( & benchmark_name, |b| {
115+ let param_size_bytes = param_size_mb * 1024 * 1024 ;
92116
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 ( ) ;
117+ let large_vec = vec ! [ 0u8 ; param_size_bytes as usize ] ;
118+ let large_string = String :: from_utf8 ( large_vec. clone ( ) ) . unwrap ( ) ;
99119
100- b. iter ( || {
101- sandbox
102- . call_guest_function_by_name :: < ( ) > (
103- "LargeParameters" ,
104- ( large_vec. clone ( ) , large_string. clone ( ) ) ,
105- )
106- . unwrap ( )
120+ let mut config = SandboxConfiguration :: default ( ) ;
121+ config. set_heap_size ( 600 * 1024 * 1024 ) ;
122+ config. set_input_data_size ( 300 * 1024 * 1024 ) ;
123+
124+ let sandbox = UninitializedSandbox :: new (
125+ GuestBinary :: FilePath ( simple_guest_as_string ( ) . unwrap ( ) ) ,
126+ Some ( config) ,
127+ )
128+ . unwrap ( ) ;
129+ let mut sandbox = sandbox. evolve ( ) . unwrap ( ) ;
130+ let snapshot = sandbox. snapshot ( ) . unwrap ( ) ;
131+
132+ // Iter_custom to avoid measure clone time of params
133+ b. iter_custom ( |iters| {
134+ let mut total_duration = std:: time:: Duration :: ZERO ;
135+
136+ for _ in 0 ..iters {
137+ let vec_clone = large_vec. clone ( ) ;
138+ let string_clone = large_string. clone ( ) ;
139+
140+ let start = std:: time:: Instant :: now ( ) ;
141+ sandbox
142+ . call_guest_function_by_name :: < ( ) > (
143+ "LargeParameters" ,
144+ ( vec_clone, string_clone) ,
145+ )
146+ . unwrap ( ) ;
147+ sandbox. restore ( & snapshot) . unwrap ( ) ;
148+ total_duration += start. elapsed ( ) ;
149+ }
150+
151+ total_duration
152+ } ) ;
107153 } ) ;
108- } ) ;
154+ }
109155
110156 group. finish ( ) ;
111157}
@@ -138,9 +184,58 @@ fn sandbox_benchmark(c: &mut Criterion) {
138184 group. finish ( ) ;
139185}
140186
187+ fn sandbox_heap_size_benchmark ( c : & mut Criterion ) {
188+ let mut group = c. benchmark_group ( "sandbox_heap_sizes" ) ;
189+
190+ const HEAP_SIZES_MB : & [ u64 ] = & [ 50 , 100 , 250 , 500 , 995 ] ;
191+
192+ // Benchmark sandbox creation with default heap size
193+ group. bench_function ( "create_sandbox_default_heap" , |b| {
194+ b. iter_with_large_drop ( || create_sandbox_with_heap_size ( None ) ) ;
195+ } ) ;
196+
197+ // Benchmark sandbox creation with different heap sizes
198+ for & heap_size_mb in HEAP_SIZES_MB {
199+ let benchmark_name = format ! ( "create_sandbox_{}mb_heap" , heap_size_mb) ;
200+ group. bench_function ( & benchmark_name, |b| {
201+ b. iter_with_large_drop ( || create_sandbox_with_heap_size ( Some ( heap_size_mb) ) ) ;
202+ } ) ;
203+ }
204+
205+ group. finish ( ) ;
206+ }
207+
208+ fn guest_call_heap_size_benchmark ( c : & mut Criterion ) {
209+ let mut group = c. benchmark_group ( "guest_call_restore_heap_sizes" ) ;
210+
211+ const HEAP_SIZES_MB : & [ Option < u64 > ] =
212+ & [ None , Some ( 50 ) , Some ( 100 ) , Some ( 250 ) , Some ( 500 ) , Some ( 995 ) ] ;
213+
214+ // Benchmark guest function call with different heap sizes (including default)
215+ for & heap_size_mb in HEAP_SIZES_MB {
216+ let benchmark_name = match heap_size_mb {
217+ None => "guest_call_restore_default_mb_heap" . to_string ( ) ,
218+ Some ( size) => format ! ( "guest_call_restore_{}_mb_heap" , size) ,
219+ } ;
220+ group. bench_function ( & benchmark_name, |b| {
221+ let mut sandbox = create_sandbox_with_heap_size ( heap_size_mb) ;
222+ let snapshot = sandbox. snapshot ( ) . unwrap ( ) ;
223+
224+ b. iter ( || {
225+ sandbox
226+ . call_guest_function_by_name :: < String > ( "Echo" , "hello\n " . to_string ( ) )
227+ . unwrap ( ) ;
228+ sandbox. restore ( & snapshot) . unwrap ( ) ;
229+ } ) ;
230+ } ) ;
231+ }
232+
233+ group. finish ( ) ;
234+ }
235+
141236criterion_group ! {
142237 name = benches;
143238 config = Criterion :: default ( ) ;
144- targets = guest_call_benchmark, sandbox_benchmark, guest_call_benchmark_large_param
239+ targets = guest_call_benchmark, sandbox_benchmark, sandbox_heap_size_benchmark , guest_call_benchmark_large_params , guest_call_heap_size_benchmark
145240}
146241criterion_main ! ( benches) ;
0 commit comments