@@ -484,6 +484,25 @@ wasmtime_option_group! {
484484 }
485485}
486486
487+ wasmtime_option_group ! {
488+ #[ derive( PartialEq , Clone , Deserialize ) ]
489+ #[ serde( rename_all = "kebab-case" , deny_unknown_fields) ]
490+ pub struct RecordOptions {
491+ /// Filesystem endpoint to store the recorded execution trace
492+ pub path: Option <String >,
493+ /// Include (optional) signatures to facilitate validation checks during replay
494+ /// (see `wasmtime replay` for details).
495+ pub validation_metadata: Option <bool >,
496+ /// Window size of internal buffering for record events (large windows offer more opportunities
497+ /// for coalescing events at the cost of memory usage).
498+ pub event_window_size: Option <usize >,
499+ }
500+
501+ enum Record {
502+ ...
503+ }
504+ }
505+
487506#[ derive( Debug , Clone , PartialEq ) ]
488507pub struct WasiNnGraph {
489508 pub format : String ,
@@ -534,6 +553,18 @@ pub struct CommonOptions {
534553 #[ serde( skip) ]
535554 wasi_raw : Vec < opt:: CommaSeparated < Wasi > > ,
536555
556+ /// Options to enable and configure execution recording, `-R help` to see all.
557+ ///
558+ /// Generates of a serialized trace of the Wasm module execution that captures all
559+ /// non-determinism observable by the module. This trace can subsequently be
560+ /// re-executed in a determinstic, embedding-agnostic manner (see the `wasmtime replay` command).
561+ ///
562+ /// Note: Minimal configs for deterministic Wasm semantics will be
563+ /// enforced during recording by default (NaN canonicalization, deterministic relaxed SIMD)
564+ #[ arg( short = 'R' , long = "record" , value_name = "KEY[=VAL[,..]]" ) ]
565+ #[ serde( skip) ]
566+ record_raw : Vec < opt:: CommaSeparated < Record > > ,
567+
537568 // These fields are filled in by the `configure` method below via the
538569 // options parsed from the CLI above. This is what the CLI should use.
539570 #[ arg( skip) ]
@@ -560,6 +591,10 @@ pub struct CommonOptions {
560591 #[ serde( rename = "wasi" , default ) ]
561592 pub wasi : WasiOptions ,
562593
594+ #[ arg( skip) ]
595+ #[ serde( rename = "record" , default ) ]
596+ pub record : RecordOptions ,
597+
563598 /// The target triple; default is the host triple
564599 #[ arg( long, value_name = "TARGET" ) ]
565600 #[ serde( skip) ]
@@ -606,12 +641,14 @@ impl CommonOptions {
606641 debug_raw : Vec :: new ( ) ,
607642 wasm_raw : Vec :: new ( ) ,
608643 wasi_raw : Vec :: new ( ) ,
644+ record_raw : Vec :: new ( ) ,
609645 configured : true ,
610646 opts : Default :: default ( ) ,
611647 codegen : Default :: default ( ) ,
612648 debug : Default :: default ( ) ,
613649 wasm : Default :: default ( ) ,
614650 wasi : Default :: default ( ) ,
651+ record : Default :: default ( ) ,
615652 target : None ,
616653 config : None ,
617654 }
@@ -629,12 +666,14 @@ impl CommonOptions {
629666 self . debug = toml_options. debug ;
630667 self . wasm = toml_options. wasm ;
631668 self . wasi = toml_options. wasi ;
669+ self . record = toml_options. record ;
632670 }
633671 self . opts . configure_with ( & self . opts_raw ) ;
634672 self . codegen . configure_with ( & self . codegen_raw ) ;
635673 self . debug . configure_with ( & self . debug_raw ) ;
636674 self . wasm . configure_with ( & self . wasm_raw ) ;
637675 self . wasi . configure_with ( & self . wasi_raw ) ;
676+ self . record . configure_with ( & self . record_raw ) ;
638677 Ok ( ( ) )
639678 }
640679
@@ -979,6 +1018,35 @@ impl CommonOptions {
9791018 true => err,
9801019 }
9811020
1021+ let record = & self . record ;
1022+ match_feature ! {
1023+ [ "rr" : record. path. clone( ) ]
1024+ path => {
1025+ use std:: { io:: BufWriter , sync:: Arc } ;
1026+ use wasmtime:: { RecordConfig , RecordSettings } ;
1027+ let default_settings = RecordSettings :: default ( ) ;
1028+ match_feature! {
1029+ [ "rr-validate" : record. validation_metadata]
1030+ _v => ( ) ,
1031+ _ => err,
1032+ }
1033+ config. enable_record( RecordConfig {
1034+ writer_initializer: Arc :: new( move || {
1035+ Box :: new( BufWriter :: new( fs:: File :: create( & path) . unwrap( ) ) )
1036+ } ) ,
1037+ settings: RecordSettings {
1038+ add_validation: record
1039+ . validation_metadata
1040+ . unwrap_or( default_settings. add_validation) ,
1041+ event_window_size: record
1042+ . event_window_size
1043+ . unwrap_or( default_settings. event_window_size) ,
1044+ } ,
1045+ } ) ?
1046+ } ,
1047+ _ => err,
1048+ }
1049+
9821050 Ok ( config)
9831051 }
9841052
@@ -1093,6 +1161,7 @@ mod tests {
10931161 [debug]
10941162 [wasm]
10951163 [wasi]
1164+ [record]
10961165 "# ;
10971166 let mut common_options: CommonOptions = toml:: from_str ( basic_toml) . unwrap ( ) ;
10981167 common_options. config ( None ) . unwrap ( ) ;
@@ -1214,6 +1283,8 @@ impl fmt::Display for CommonOptions {
12141283 wasm,
12151284 wasi_raw,
12161285 wasi,
1286+ record_raw,
1287+ record,
12171288 configured,
12181289 target,
12191290 config,
@@ -1230,13 +1301,15 @@ impl fmt::Display for CommonOptions {
12301301 let wasi_flags;
12311302 let wasm_flags;
12321303 let debug_flags;
1304+ let record_flags;
12331305
12341306 if * configured {
12351307 codegen_flags = codegen. to_options ( ) ;
12361308 debug_flags = debug. to_options ( ) ;
12371309 wasi_flags = wasi. to_options ( ) ;
12381310 wasm_flags = wasm. to_options ( ) ;
12391311 opts_flags = opts. to_options ( ) ;
1312+ record_flags = record. to_options ( ) ;
12401313 } else {
12411314 codegen_flags = codegen_raw
12421315 . iter ( )
@@ -1247,6 +1320,11 @@ impl fmt::Display for CommonOptions {
12471320 wasi_flags = wasi_raw. iter ( ) . flat_map ( |t| t. 0 . iter ( ) ) . cloned ( ) . collect ( ) ;
12481321 wasm_flags = wasm_raw. iter ( ) . flat_map ( |t| t. 0 . iter ( ) ) . cloned ( ) . collect ( ) ;
12491322 opts_flags = opts_raw. iter ( ) . flat_map ( |t| t. 0 . iter ( ) ) . cloned ( ) . collect ( ) ;
1323+ record_flags = record_raw
1324+ . iter ( )
1325+ . flat_map ( |t| t. 0 . iter ( ) )
1326+ . cloned ( )
1327+ . collect ( ) ;
12501328 }
12511329
12521330 for flag in codegen_flags {
@@ -1264,6 +1342,9 @@ impl fmt::Display for CommonOptions {
12641342 for flag in debug_flags {
12651343 write ! ( f, "-D{flag} " ) ?;
12661344 }
1345+ for flag in record_flags {
1346+ write ! ( f, "-R{flag} " ) ?;
1347+ }
12671348
12681349 Ok ( ( ) )
12691350 }
0 commit comments