@@ -87,7 +87,7 @@ pub type ExtraAllowedSyscall = i64;
87
87
/// Determine whether a suitable hypervisor is available to run
88
88
/// this sandbox.
89
89
///
90
- // Returns a boolean indicating whether a suitable hypervisor is present.
90
+ /// Returns a boolean indicating whether a suitable hypervisor is present.
91
91
#[ instrument( skip_all, parent = Span :: current( ) ) ]
92
92
pub fn is_hypervisor_present ( ) -> bool {
93
93
hypervisor:: get_available_hypervisor ( ) . is_some ( )
@@ -100,18 +100,23 @@ pub fn is_hypervisor_present() -> bool {
100
100
pub ( crate ) struct TraceInfo {
101
101
/// The epoch against which trace events are timed; at least as
102
102
/// early as the creation of the sandbox being traced.
103
- #[ allow( dead_code) ]
104
103
pub epoch : std:: time:: Instant ,
105
104
/// The frequency of the timestamp counter.
106
- #[ allow( dead_code) ]
107
- pub tsc_freq : u64 ,
105
+ pub tsc_freq : Option < u64 > ,
108
106
/// The epoch at which the guest started, if it has started.
109
107
/// This is used to calculate the time spent in the guest relative to the
110
- /// time of the host.
111
- #[ allow( dead_code) ]
108
+ /// time when the host started.
112
109
pub guest_start_epoch : Option < std:: time:: Instant > ,
113
- /// The start guest time, in TSC cycles, for the current guest.
114
- #[ allow( dead_code) ]
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.
115
120
pub guest_start_tsc : Option < u64 > ,
116
121
/// The file to which the trace is being written
117
122
#[ allow( dead_code) ]
@@ -136,8 +141,17 @@ impl TraceInfo {
136
141
) -> crate :: Result < Self > {
137
142
let mut path = std:: env:: current_dir ( ) ?;
138
143
path. push ( "trace" ) ;
144
+
145
+ // create directory if it does not exist
146
+ if !path. exists ( ) {
147
+ std:: fs:: create_dir ( & path) ?;
148
+ }
139
149
path. push ( uuid:: Uuid :: new_v4 ( ) . to_string ( ) ) ;
140
150
path. set_extension ( "trace" ) ;
151
+
152
+ log:: info!( "Creating trace file at: {}" , path. display( ) ) ;
153
+ println ! ( "Creating trace file at: {}" , path. display( ) ) ;
154
+
141
155
#[ cfg( feature = "unwind_guest" ) ]
142
156
let hash = unwind_module. hash ( ) ;
143
157
#[ cfg( feature = "unwind_guest" ) ]
@@ -147,11 +161,17 @@ impl TraceInfo {
147
161
let cache = framehop:: x86_64:: CacheX86_64 :: new ( ) ;
148
162
( unwinder, Arc :: new ( Mutex :: new ( cache) ) )
149
163
} ;
150
- let tsc_freq = Self :: calculate_tsc_freq ( ) ?;
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
+ }
151
171
152
172
let ret = Self {
153
173
epoch : std:: time:: Instant :: now ( ) ,
154
- tsc_freq,
174
+ tsc_freq : None ,
155
175
guest_start_epoch : None ,
156
176
guest_start_tsc : None ,
157
177
file : Arc :: new ( Mutex :: new ( std:: fs:: File :: create_new ( path) ?) ) ,
@@ -170,22 +190,40 @@ impl TraceInfo {
170
190
Ok ( ret)
171
191
}
172
192
173
- /// Calculate the TSC frequency based on the RDTSC instruction.
174
- fn calculate_tsc_freq ( ) -> crate :: Result < u64 > {
175
- if !hyperlight_guest_tracing:: invariant_tsc:: has_invariant_tsc ( ) {
176
- return Err ( crate :: new_error!(
177
- "Invariant TSC is not supported on this platform"
178
- ) ) ;
179
- }
180
- let start = hyperlight_guest_tracing:: invariant_tsc:: read_tsc ( ) ;
181
- let start_time = std:: time:: Instant :: now ( ) ;
182
- // Sleep for 1 second to get a good sample
183
- std:: thread:: sleep ( std:: time:: Duration :: from_secs ( 1 ) ) ;
184
- let end = hyperlight_guest_tracing:: invariant_tsc:: read_tsc ( ) ;
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
+
185
217
let end_time = std:: time:: Instant :: now ( ) ;
218
+ let end = hyperlight_guest_tracing:: invariant_tsc:: read_tsc ( ) ;
219
+
186
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) ;
187
225
188
- Ok ( ( ( end - start ) as f64 / elapsed ) as u64 )
226
+ Ok ( ( ) )
189
227
}
190
228
}
191
229
0 commit comments