@@ -37,17 +37,14 @@ pub mod snapshot;
3737/// Trait used by the macros to paper over the differences between hyperlight and hyperlight-wasm
3838mod callable;
3939
40- #[ cfg( feature = "mem_profile" ) ]
41- use std:: io:: Write ;
40+ /// Module for tracing guest execution
4241#[ cfg( feature = "trace_guest" ) ]
43- use std :: sync :: { Arc , Mutex } ;
42+ pub ( crate ) mod trace ;
4443
4544/// Trait used by the macros to paper over the differences between hyperlight and hyperlight-wasm
4645pub use callable:: Callable ;
4746/// Re-export for `SandboxConfiguration` type
4847pub use config:: SandboxConfiguration ;
49- #[ cfg( feature = "mem_profile" ) ]
50- use framehop:: Unwinder ;
5148/// Re-export for the `MultiUseSandbox` type
5249pub use initialized_multi_use:: MultiUseSandbox ;
5350use tracing:: { Span , instrument} ;
@@ -88,140 +85,6 @@ pub fn is_hypervisor_present() -> bool {
8885 hypervisor:: get_available_hypervisor ( ) . is_some ( )
8986}
9087
91- /// The information that trace collection requires in order to write
92- /// an accurate trace.
93- #[ derive( Clone ) ]
94- #[ cfg( feature = "trace_guest" ) ]
95- pub ( crate ) struct TraceInfo {
96- /// The epoch against which trace events are timed; at least as
97- /// early as the creation of the sandbox being traced.
98- pub epoch : std:: time:: Instant ,
99- /// The frequency of the timestamp counter.
100- pub tsc_freq : Option < u64 > ,
101- /// The epoch at which the guest started, if it has started.
102- /// This is used to calculate the time spent in the guest relative to the
103- /// time when the host started.
104- pub guest_start_epoch : Option < std:: time:: Instant > ,
105- /// The start guest time, in TSC cycles, for the current guest has a double purpose.
106- /// This field is used in two ways:
107- /// 1. It contains the TSC value recorded on the host when the guest started.
108- /// This is used to calculate the TSC frequency which is the same on the host and guest.
109- /// The TSC frequency is used to convert TSC values to timestamps in the trace.
110- /// **NOTE**: This is only used until the TSC frequency is calculated, when the first
111- /// records are received.
112- /// 2. To store the TSC value at recorded on the guest when the guest started (first record
113- /// received)
114- /// This is used to calculate the records timestamps relative to when guest started.
115- pub guest_start_tsc : Option < u64 > ,
116- /// The file to which the trace is being written
117- #[ allow( dead_code) ]
118- pub file : Arc < Mutex < std:: fs:: File > > ,
119- /// The unwind information for the current guest
120- #[ allow( dead_code) ]
121- #[ cfg( feature = "mem_profile" ) ]
122- pub unwind_module : Arc < dyn crate :: mem:: exe:: UnwindInfo > ,
123- /// The framehop unwinder for the current guest
124- #[ cfg( feature = "mem_profile" ) ]
125- pub unwinder : framehop:: x86_64:: UnwinderX86_64 < Vec < u8 > > ,
126- /// The framehop cache
127- #[ cfg( feature = "mem_profile" ) ]
128- pub unwind_cache : Arc < Mutex < framehop:: x86_64:: CacheX86_64 > > ,
129- }
130- #[ cfg( feature = "trace_guest" ) ]
131- impl TraceInfo {
132- /// Create a new TraceInfo by saving the current time as the epoch
133- /// and generating a random filename.
134- pub fn new (
135- #[ cfg( feature = "mem_profile" ) ] unwind_module : Arc < dyn crate :: mem:: exe:: UnwindInfo > ,
136- ) -> crate :: Result < Self > {
137- let mut path = std:: env:: current_dir ( ) ?;
138- path. push ( "trace" ) ;
139-
140- // create directory if it does not exist
141- if !path. exists ( ) {
142- std:: fs:: create_dir ( & path) ?;
143- }
144- path. push ( uuid:: Uuid :: new_v4 ( ) . to_string ( ) ) ;
145- path. set_extension ( "trace" ) ;
146-
147- log:: info!( "Creating trace file at: {}" , path. display( ) ) ;
148- println ! ( "Creating trace file at: {}" , path. display( ) ) ;
149-
150- #[ cfg( feature = "mem_profile" ) ]
151- let hash = unwind_module. hash ( ) ;
152- #[ cfg( feature = "mem_profile" ) ]
153- let ( unwinder, unwind_cache) = {
154- let mut unwinder = framehop:: x86_64:: UnwinderX86_64 :: new ( ) ;
155- unwinder. add_module ( unwind_module. clone ( ) . as_module ( ) ) ;
156- let cache = framehop:: x86_64:: CacheX86_64 :: new ( ) ;
157- ( unwinder, Arc :: new ( Mutex :: new ( cache) ) )
158- } ;
159- if !hyperlight_guest_tracing:: invariant_tsc:: has_invariant_tsc ( ) {
160- // If the platform does not support invariant TSC, warn the user.
161- // On Azure nested virtualization, the TSC invariant bit is not correctly reported, this is a known issue.
162- log:: warn!(
163- "Invariant TSC is not supported on this platform, trace timestamps may be inaccurate"
164- ) ;
165- }
166-
167- let ret = Self {
168- epoch : std:: time:: Instant :: now ( ) ,
169- tsc_freq : None ,
170- guest_start_epoch : None ,
171- guest_start_tsc : None ,
172- file : Arc :: new ( Mutex :: new ( std:: fs:: File :: create_new ( path) ?) ) ,
173- #[ cfg( feature = "mem_profile" ) ]
174- unwind_module,
175- #[ cfg( feature = "mem_profile" ) ]
176- unwinder,
177- #[ cfg( feature = "mem_profile" ) ]
178- unwind_cache,
179- } ;
180- /* write a frame identifying the binary */
181- #[ cfg( feature = "mem_profile" ) ]
182- self :: outb:: record_trace_frame ( & ret, 0 , |f| {
183- let _ = f. write_all ( hash. as_bytes ( ) ) ;
184- } ) ?;
185- Ok ( ret)
186- }
187-
188- /// Calculate the TSC frequency based on the RDTSC instruction on the host.
189- fn calculate_tsc_freq ( & mut self ) -> crate :: Result < ( ) > {
190- let ( start, start_time) = match (
191- self . guest_start_tsc . as_ref ( ) ,
192- self . guest_start_epoch . as_ref ( ) ,
193- ) {
194- ( Some ( start) , Some ( start_time) ) => ( * start, * start_time) ,
195- _ => {
196- // If the guest start TSC and time are not set, we use the current time and TSC.
197- // This is not ideal, but it allows us to calculate the TSC frequency without
198- // failing.
199- // This is a fallback mechanism to ensure that we can still calculate, however it
200- // should be noted that this may lead to inaccuracies in the TSC frequency.
201- // The start time should be already set before running the guest for each sandbox.
202- log:: error!(
203- "Guest start TSC and time are not set. Calculating TSC frequency will use current time and TSC."
204- ) ;
205- (
206- hyperlight_guest_tracing:: invariant_tsc:: read_tsc ( ) ,
207- std:: time:: Instant :: now ( ) ,
208- )
209- }
210- } ;
211-
212- let end_time = std:: time:: Instant :: now ( ) ;
213- let end = hyperlight_guest_tracing:: invariant_tsc:: read_tsc ( ) ;
214-
215- let elapsed = end_time. duration_since ( start_time) . as_secs_f64 ( ) ;
216- let tsc_freq = ( ( end - start) as f64 / elapsed) as u64 ;
217-
218- log:: info!( "Calculated TSC frequency: {} Hz" , tsc_freq) ;
219- self . tsc_freq = Some ( tsc_freq) ;
220-
221- Ok ( ( ) )
222- }
223- }
224-
22588#[ cfg( test) ]
22689mod tests {
22790 use std:: sync:: Arc ;
0 commit comments