@@ -90,7 +90,7 @@ pub type ExtraAllowedSyscall = i64;
90
90
/// Determine whether a suitable hypervisor is available to run
91
91
/// this sandbox.
92
92
///
93
- // Returns a boolean indicating whether a suitable hypervisor is present.
93
+ /// Returns a boolean indicating whether a suitable hypervisor is present.
94
94
#[ instrument( skip_all, parent = Span :: current( ) ) ]
95
95
pub fn is_hypervisor_present ( ) -> bool {
96
96
hypervisor:: get_available_hypervisor ( ) . is_some ( )
@@ -103,18 +103,23 @@ pub fn is_hypervisor_present() -> bool {
103
103
pub ( crate ) struct TraceInfo {
104
104
/// The epoch against which trace events are timed; at least as
105
105
/// early as the creation of the sandbox being traced.
106
- #[ allow( dead_code) ]
107
106
pub epoch : std:: time:: Instant ,
108
107
/// The frequency of the timestamp counter.
109
- #[ allow( dead_code) ]
110
- pub tsc_freq : u64 ,
108
+ pub tsc_freq : Option < u64 > ,
111
109
/// The epoch at which the guest started, if it has started.
112
110
/// This is used to calculate the time spent in the guest relative to the
113
- /// time of the host.
114
- #[ allow( dead_code) ]
111
+ /// time when the host started.
115
112
pub guest_start_epoch : Option < std:: time:: Instant > ,
116
- /// The start guest time, in TSC cycles, for the current guest.
117
- #[ allow( dead_code) ]
113
+ /// The start guest time, in TSC cycles, for the current guest has a double purpose.
114
+ /// This field is used in two ways:
115
+ /// 1. It contains the TSC value recorded on the host when the guest started.
116
+ /// This is used to calculate the TSC frequency which is the same on the host and guest.
117
+ /// The TSC frequency is used to convert TSC values to timestamps in the trace.
118
+ /// **NOTE**: This is only used until the TSC frequency is calculated, when the first
119
+ /// records are received.
120
+ /// 2. To store the TSC value at recorded on the guest when the guest started (first record
121
+ /// received)
122
+ /// This is used to calculate the records timestamps relative to when guest started.
118
123
pub guest_start_tsc : Option < u64 > ,
119
124
/// The file to which the trace is being written
120
125
#[ allow( dead_code) ]
@@ -139,8 +144,17 @@ impl TraceInfo {
139
144
) -> crate :: Result < Self > {
140
145
let mut path = std:: env:: current_dir ( ) ?;
141
146
path. push ( "trace" ) ;
147
+
148
+ // create directory if it does not exist
149
+ if !path. exists ( ) {
150
+ std:: fs:: create_dir ( & path) ?;
151
+ }
142
152
path. push ( uuid:: Uuid :: new_v4 ( ) . to_string ( ) ) ;
143
153
path. set_extension ( "trace" ) ;
154
+
155
+ log:: info!( "Creating trace file at: {}" , path. display( ) ) ;
156
+ println ! ( "Creating trace file at: {}" , path. display( ) ) ;
157
+
144
158
#[ cfg( feature = "unwind_guest" ) ]
145
159
let hash = unwind_module. hash ( ) ;
146
160
#[ cfg( feature = "unwind_guest" ) ]
@@ -150,11 +164,17 @@ impl TraceInfo {
150
164
let cache = framehop:: x86_64:: CacheX86_64 :: new ( ) ;
151
165
( unwinder, Arc :: new ( Mutex :: new ( cache) ) )
152
166
} ;
153
- let tsc_freq = Self :: calculate_tsc_freq ( ) ?;
167
+ if !hyperlight_guest_tracing:: invariant_tsc:: has_invariant_tsc ( ) {
168
+ // If the platform does not support invariant TSC, warn the user.
169
+ // On Azure nested virtualization, the TSC invariant bit is not correctly reported, this is a known issue.
170
+ log:: warn!(
171
+ "Invariant TSC is not supported on this platform, trace timestamps may be inaccurate"
172
+ ) ;
173
+ }
154
174
155
175
let ret = Self {
156
176
epoch : std:: time:: Instant :: now ( ) ,
157
- tsc_freq,
177
+ tsc_freq : None ,
158
178
guest_start_epoch : None ,
159
179
guest_start_tsc : None ,
160
180
file : Arc :: new ( Mutex :: new ( std:: fs:: File :: create_new ( path) ?) ) ,
@@ -173,22 +193,40 @@ impl TraceInfo {
173
193
Ok ( ret)
174
194
}
175
195
176
- /// Calculate the TSC frequency based on the RDTSC instruction.
177
- fn calculate_tsc_freq ( ) -> crate :: Result < u64 > {
178
- if !hyperlight_guest_tracing:: invariant_tsc:: has_invariant_tsc ( ) {
179
- return Err ( crate :: new_error!(
180
- "Invariant TSC is not supported on this platform"
181
- ) ) ;
182
- }
183
- let start = hyperlight_guest_tracing:: invariant_tsc:: read_tsc ( ) ;
184
- let start_time = std:: time:: Instant :: now ( ) ;
185
- // Sleep for 1 second to get a good sample
186
- std:: thread:: sleep ( std:: time:: Duration :: from_secs ( 1 ) ) ;
187
- let end = hyperlight_guest_tracing:: invariant_tsc:: read_tsc ( ) ;
196
+ /// Calculate the TSC frequency based on the RDTSC instruction on the host.
197
+ fn calculate_tsc_freq ( & mut self ) -> crate :: Result < ( ) > {
198
+ let ( start, start_time) = match (
199
+ self . guest_start_tsc . as_ref ( ) ,
200
+ self . guest_start_epoch . as_ref ( ) ,
201
+ ) {
202
+ ( Some ( start) , Some ( start_time) ) => ( * start, * start_time) ,
203
+ _ => {
204
+ // If the guest start TSC and time are not set, we use the current time and TSC.
205
+ // This is not ideal, but it allows us to calculate the TSC frequency without
206
+ // failing.
207
+ // This is a fallback mechanism to ensure that we can still calculate, however it
208
+ // should be noted that this may lead to inaccuracies in the TSC frequency.
209
+ // The start time should be already set before running the guest for each sandbox.
210
+ log:: error!(
211
+ "Guest start TSC and time are not set. Calculating TSC frequency will use current time and TSC."
212
+ ) ;
213
+ (
214
+ hyperlight_guest_tracing:: invariant_tsc:: read_tsc ( ) ,
215
+ std:: time:: Instant :: now ( ) ,
216
+ )
217
+ }
218
+ } ;
219
+
188
220
let end_time = std:: time:: Instant :: now ( ) ;
221
+ let end = hyperlight_guest_tracing:: invariant_tsc:: read_tsc ( ) ;
222
+
189
223
let elapsed = end_time. duration_since ( start_time) . as_secs_f64 ( ) ;
224
+ let tsc_freq = ( ( end - start) as f64 / elapsed) as u64 ;
225
+
226
+ log:: info!( "Calculated TSC frequency: {} Hz" , tsc_freq) ;
227
+ self . tsc_freq = Some ( tsc_freq) ;
190
228
191
- Ok ( ( ( end - start ) as f64 / elapsed ) as u64 )
229
+ Ok ( ( ) )
192
230
}
193
231
}
194
232
0 commit comments