Skip to content

Commit 6176db1

Browse files
committed
[trace] Improve guest traces to contain top spans
- For each call to `internal_dispatch_function` now we create a span manually because instrumenting the function would be redundant because of the call to `new_call` that resets tracing state for each new function call - The same logic is used for `generic_init` to enable it for the initialise call Signed-off-by: Doru Blânzeanu <dblnz@pm.me>
1 parent 726bcf5 commit 6176db1

3 files changed

Lines changed: 45 additions & 13 deletions

File tree

src/hyperlight_common/src/flatbuffer_wrappers/function_call.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ pub enum FunctionCallType {
4141
}
4242

4343
/// `Functioncall` represents a call to a function in the guest or host.
44-
#[derive(Clone)]
44+
#[derive(Clone, Debug)]
4545
pub struct FunctionCall {
4646
/// The function name
4747
pub function_name: String,

src/hyperlight_guest_bin/src/guest_function/call.rs

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -81,23 +81,25 @@ pub(crate) fn call_guest_function(function_call: FunctionCall) -> Result<Vec<u8>
8181
pub(crate) fn internal_dispatch_function() {
8282
// Read the current TSC to report it to the host with the spans/events
8383
// This helps calculating the timestamps relative to the guest call
84-
#[cfg(feature = "trace_guest")]
85-
{
84+
#[cfg(all(feature = "trace_guest", target_arch = "x86_64"))]
85+
let _entered = {
8686
let guest_start_tsc = hyperlight_guest_tracing::invariant_tsc::read_tsc();
8787
// Reset the trace state for the new guest function call with the new start TSC
8888
// This clears any existing spans/events from previous calls ensuring a clean state
8989
hyperlight_guest_tracing::new_call(guest_start_tsc);
90-
}
9190

92-
let handle = unsafe { GUEST_HANDLE };
91+
tracing::span!(tracing::Level::INFO, "internal_dispatch_function").entered()
92+
};
9393

94-
#[cfg(debug_assertions)]
95-
log::trace!("internal_dispatch_function");
94+
let handle = unsafe { GUEST_HANDLE };
9695

9796
let function_call = handle
9897
.try_pop_shared_input_data_into::<FunctionCall>()
9998
.expect("Function call deserialization failed");
10099

100+
#[cfg(debug_assertions)]
101+
tracing::trace!("{:?}", function_call);
102+
101103
let res = call_guest_function(function_call);
102104

103105
match res {
@@ -117,8 +119,20 @@ pub(crate) fn internal_dispatch_function() {
117119
}
118120
}
119121

120-
// Ensure that any tracing output during the call is flushed to
121-
// the host, if necessary.
122+
// All this tracing logic shall be done right before the call to `hlt` which is done after this
123+
// function returns
122124
#[cfg(all(feature = "trace_guest", target_arch = "x86_64"))]
123-
hyperlight_guest_tracing::flush();
125+
{
126+
// This span captures the internal dispatch function only, without tracing internals.
127+
// Close the span before flushing to ensure that the `flush` call is not included in the span
128+
// NOTE: This is necessary to avoid closing the span twice. Flush closes all the open
129+
// spans, when preparing to close a guest function call context.
130+
// It is not mandatory, though, but avoids a warning on the host that alerts a spans
131+
// that has not been opened but is being closed.
132+
_entered.exit();
133+
134+
// Ensure that any tracing output during the call is flushed to
135+
// the host, if necessary.
136+
hyperlight_guest_tracing::flush();
137+
}
124138
}

src/hyperlight_guest_bin/src/lib.rs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,12 @@ pub(crate) extern "C" fn generic_init(
226226
hyperlight_guest_tracing::init_guest_tracing(guest_start_tsc);
227227
}
228228

229+
// Open a span to partly capture the initialization of the guest.
230+
// This is done here because the tracing subscriber is initialized and the guest is in a
231+
// well-known state
232+
#[cfg(all(feature = "trace_guest", target_arch = "x86_64"))]
233+
let _entered = tracing::span!(tracing::Level::INFO, "generic_init").entered();
234+
229235
#[cfg(feature = "macros")]
230236
for registration in __private::GUEST_FUNCTION_INIT {
231237
registration();
@@ -235,10 +241,22 @@ pub(crate) extern "C" fn generic_init(
235241
hyperlight_main();
236242
}
237243

238-
// Ensure that any tracing output from the initialisation phase is
239-
// flushed to the host, if necessary.
244+
// All this tracing logic shall be done right before the call to `hlt` which is done after this
245+
// function returns
240246
#[cfg(all(feature = "trace_guest", target_arch = "x86_64"))]
241-
hyperlight_guest_tracing::flush();
247+
{
248+
// This span captures the internal dispatch function only, without tracing internals.
249+
// Close the span before flushing to ensure that the `flush` call is not included in the span
250+
// NOTE: This is necessary to avoid closing the span twice. Flush closes all the open
251+
// spans, when preparing to close a guest function call context.
252+
// It is not mandatory, though, but avoids a warning on the host that alerts a spans
253+
// that has not been opened but is being closed.
254+
_entered.exit();
255+
256+
// Ensure that any tracing output from the initialisation phase is
257+
// flushed to the host, if necessary.
258+
hyperlight_guest_tracing::flush();
259+
}
242260

243261
dispatch_function as usize as u64
244262
}

0 commit comments

Comments
 (0)