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