@@ -153,6 +153,15 @@ fn sandbox_lifecycle_benchmark(c: &mut Criterion) {
153153 ) ;
154154 }
155155
156+ // Isolates the cost of building a MultiUseSandbox from an
157+ // already-resident Snapshot. The Snapshot is loaded outside the
158+ // timed region.
159+ for size in SandboxSize :: all ( ) {
160+ group. bench_function ( format ! ( "sandbox_from_snapshot/{}" , size. name( ) ) , |b| {
161+ bench_sandbox_from_snapshot ( b, size)
162+ } ) ;
163+ }
164+
156165 group. finish ( ) ;
157166}
158167
@@ -347,6 +356,25 @@ fn bench_snapshot_restore(b: &mut criterion::Bencher, size: SandboxSize) {
347356 } ) ;
348357}
349358
359+ fn bench_sandbox_from_snapshot ( b : & mut criterion:: Bencher , size : SandboxSize ) {
360+ use hyperlight_host:: HostFunctions ;
361+ use hyperlight_host:: sandbox:: snapshot:: Snapshot ;
362+
363+ let dir = tempfile:: tempdir ( ) . unwrap ( ) ;
364+ let snap_path = dir. path ( ) . join ( "bench" ) ;
365+ {
366+ let mut sbox = create_multiuse_sandbox_with_size ( size) ;
367+ let snapshot = sbox. snapshot ( ) . unwrap ( ) ;
368+ snapshot. to_oci ( & snap_path, "latest" ) . unwrap ( ) ;
369+ }
370+ let loaded = std:: sync:: Arc :: new ( Snapshot :: from_oci ( & snap_path, "latest" ) . unwrap ( ) ) ;
371+
372+ b. iter ( || {
373+ let _ =
374+ MultiUseSandbox :: from_snapshot ( loaded. clone ( ) , HostFunctions :: default ( ) , None ) . unwrap ( ) ;
375+ } ) ;
376+ }
377+
350378fn snapshots_benchmark ( c : & mut Criterion ) {
351379 let mut group = c. benchmark_group ( "snapshots" ) ;
352380
@@ -551,6 +579,118 @@ fn shared_memory_benchmark(c: &mut Criterion) {
551579 group. finish ( ) ;
552580}
553581
582+ // ============================================================================
583+ // Benchmark Category: Snapshot Files
584+ // ============================================================================
585+
586+ fn snapshot_file_benchmark ( c : & mut Criterion ) {
587+ use hyperlight_host:: HostFunctions ;
588+ use hyperlight_host:: sandbox:: snapshot:: Snapshot ;
589+
590+ let mut group = c. benchmark_group ( "snapshot_files" ) ;
591+
592+ // Pre-create OCI snapshot images for all sizes.
593+ let dirs: Vec < _ > = SandboxSize :: all ( )
594+ . iter ( )
595+ . map ( |size| {
596+ let dir = tempfile:: tempdir ( ) . unwrap ( ) ;
597+ let snap_path = dir. path ( ) . join ( size. name ( ) ) ;
598+ let snapshot = {
599+ let mut sbox = create_multiuse_sandbox_with_size ( * size) ;
600+ sbox. snapshot ( ) . unwrap ( )
601+ } ;
602+ snapshot. to_oci ( & snap_path, "latest" ) . unwrap ( ) ;
603+ ( dir, snapshot, snap_path)
604+ } )
605+ . collect ( ) ;
606+
607+ // Benchmark: save_snapshot. Wipe the layout between iterations
608+ // so each save measures a fresh write rather than a tag-append.
609+ for ( i, size) in SandboxSize :: all ( ) . iter ( ) . enumerate ( ) {
610+ let snap_dir = tempfile:: tempdir ( ) . unwrap ( ) ;
611+ let path = snap_dir. path ( ) . join ( "bench" ) ;
612+ let snapshot = & dirs[ i] . 1 ;
613+ group. bench_function ( format ! ( "save_snapshot/{}" , size. name( ) ) , |b| {
614+ b. iter_batched (
615+ || {
616+ let _ = std:: fs:: remove_dir_all ( & path) ;
617+ } ,
618+ |_| snapshot. to_oci ( & path, "latest" ) . unwrap ( ) ,
619+ criterion:: BatchSize :: PerIteration ,
620+ ) ;
621+ } ) ;
622+ }
623+
624+ // Benchmark: load_snapshot (parse manifest + config + mmap blob).
625+ for ( i, size) in SandboxSize :: all ( ) . iter ( ) . enumerate ( ) {
626+ let snap_path = dirs[ i] . 2 . clone ( ) ;
627+ group. bench_function ( format ! ( "load_snapshot/{}" , size. name( ) ) , |b| {
628+ b. iter ( || {
629+ let _ = Snapshot :: from_oci ( & snap_path, "latest" ) . unwrap ( ) ;
630+ } ) ;
631+ } ) ;
632+ }
633+
634+ // Benchmark: load_snapshot_unchecked (skip blob digest verification).
635+ for ( i, size) in SandboxSize :: all ( ) . iter ( ) . enumerate ( ) {
636+ let snap_path = dirs[ i] . 2 . clone ( ) ;
637+ group. bench_function ( format ! ( "load_snapshot_unchecked/{}" , size. name( ) ) , |b| {
638+ b. iter ( || {
639+ let _ = Snapshot :: from_oci_unchecked ( & snap_path, "latest" ) . unwrap ( ) ;
640+ } ) ;
641+ } ) ;
642+ }
643+
644+ // Benchmark: cold_start_via_evolve (new + evolve + call)
645+ for size in SandboxSize :: all ( ) {
646+ group. bench_function ( format ! ( "cold_start_via_evolve/{}" , size. name( ) ) , |b| {
647+ b. iter ( || {
648+ let mut sbox = create_multiuse_sandbox_with_size ( size) ;
649+ sbox. call :: < String > ( "Echo" , "hello\n " . to_string ( ) ) . unwrap ( ) ;
650+ } ) ;
651+ } ) ;
652+ }
653+
654+ // Benchmark: cold_start_via_snapshot (load + from_snapshot + call)
655+ for ( i, size) in SandboxSize :: all ( ) . iter ( ) . enumerate ( ) {
656+ let snap_path = dirs[ i] . 2 . clone ( ) ;
657+ group. bench_function ( format ! ( "cold_start_via_snapshot/{}" , size. name( ) ) , |b| {
658+ b. iter ( || {
659+ let loaded = Snapshot :: from_oci ( & snap_path, "latest" ) . unwrap ( ) ;
660+ let mut sbox = MultiUseSandbox :: from_snapshot (
661+ std:: sync:: Arc :: new ( loaded) ,
662+ HostFunctions :: default ( ) ,
663+ None ,
664+ )
665+ . unwrap ( ) ;
666+ sbox. call :: < String > ( "Echo" , "hello\n " . to_string ( ) ) . unwrap ( ) ;
667+ } ) ;
668+ } ) ;
669+ }
670+
671+ // Benchmark: cold_start_via_snapshot_unchecked (load unchecked + from_snapshot + call)
672+ for ( i, size) in SandboxSize :: all ( ) . iter ( ) . enumerate ( ) {
673+ let snap_path = dirs[ i] . 2 . clone ( ) ;
674+ group. bench_function (
675+ format ! ( "cold_start_via_snapshot_unchecked/{}" , size. name( ) ) ,
676+ |b| {
677+ b. iter ( || {
678+ let loaded = Snapshot :: from_oci_unchecked ( & snap_path, "latest" ) . unwrap ( ) ;
679+ let mut sbox = MultiUseSandbox :: from_snapshot (
680+ std:: sync:: Arc :: new ( loaded) ,
681+ HostFunctions :: default ( ) ,
682+ None ,
683+ )
684+ . unwrap ( ) ;
685+ sbox. call :: < String > ( "Echo" , "hello\n " . to_string ( ) ) . unwrap ( ) ;
686+ } ) ;
687+ } ,
688+ ) ;
689+ }
690+
691+ group. finish ( ) ;
692+ }
693+
554694criterion_group ! {
555695 name = benches;
556696 config = Criterion :: default ( ) ;
@@ -561,6 +701,7 @@ criterion_group! {
561701 guest_call_benchmark_large_param,
562702 function_call_serialization_benchmark,
563703 sample_workloads_benchmark,
564- shared_memory_benchmark
704+ shared_memory_benchmark,
705+ snapshot_file_benchmark
565706}
566707criterion_main ! ( benches) ;
0 commit comments