Skip to content

Commit e5a36f9

Browse files
committed
[hyperlight_guest] Add traces in the guest to track the execution timing
- Add traces wherever we think it might be of use to help us better profile the codebase. - Add flush instructions before halting or running an `OutB` instruction to ensure the records are sent before the guest exits due to an error or a normal exit Signed-off-by: Doru Blânzeanu <dblnz@pm.me>
1 parent 39e744b commit e5a36f9

File tree

11 files changed

+42
-0
lines changed

11 files changed

+42
-0
lines changed

src/hyperlight_guest/Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,9 @@ Provides only the essential building blocks for interacting with the host enviro
1515
anyhow = { version = "1.0.98", default-features = false }
1616
serde_json = { version = "1.0", default-features = false, features = ["alloc"] }
1717
hyperlight-common = { workspace = true }
18+
hyperlight-guest-tracing = { workspace = true, optional = true }
19+
hyperlight-guest-tracing-macro = { workspace = true}
20+
21+
[features]
22+
default = []
23+
trace_guest = ["dep:hyperlight-guest-tracing"]

src/hyperlight_guest/src/exit.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,22 @@ use hyperlight_common::outb::OutBAction;
2121

2222
/// Halt the execution of the guest and returns control to the host.
2323
#[inline(never)]
24+
#[hyperlight_guest_tracing_macro::trace_function]
2425
pub fn halt() {
26+
// Ensure all tracing data is flushed before halting
27+
hyperlight_guest_tracing_macro::flush!();
2528
unsafe { asm!("hlt", options(nostack)) }
2629
}
2730

2831
/// Exits the VM with an Abort OUT action and code 0.
2932
#[unsafe(no_mangle)]
33+
#[hyperlight_guest_tracing_macro::trace_function]
3034
pub extern "C" fn abort() -> ! {
3135
abort_with_code(&[0, 0xFF])
3236
}
3337

3438
/// Exits the VM with an Abort OUT action and a specific code.
39+
#[hyperlight_guest_tracing_macro::trace_function]
3540
pub fn abort_with_code(code: &[u8]) -> ! {
3641
outb(OutBAction::Abort as u16, code);
3742
outb(OutBAction::Abort as u16, &[0xFF]); // send abort terminator (if not included in code)
@@ -42,6 +47,7 @@ pub fn abort_with_code(code: &[u8]) -> ! {
4247
///
4348
/// # Safety
4449
/// This function is unsafe because it dereferences a raw pointer.
50+
#[hyperlight_guest_tracing_macro::trace_function]
4551
pub unsafe fn abort_with_code_and_message(code: &[u8], message_ptr: *const c_char) -> ! {
4652
unsafe {
4753
// Step 1: Send abort code (typically 1 byte, but `code` allows flexibility)
@@ -63,6 +69,8 @@ pub unsafe fn abort_with_code_and_message(code: &[u8], message_ptr: *const c_cha
6369

6470
/// OUT bytes to the host through multiple exits.
6571
pub(crate) fn outb(port: u16, data: &[u8]) {
72+
// Ensure all tracing data is flushed before sending OUT bytes
73+
hyperlight_guest_tracing_macro::flush!();
6674
unsafe {
6775
let mut i = 0;
6876
while i < data.len() {

src/hyperlight_guest/src/guest_handle/host_comm.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ use crate::exit::out32;
3535

3636
impl GuestHandle {
3737
/// Get user memory region as bytes.
38+
#[hyperlight_guest_tracing_macro::trace_function]
3839
pub fn read_n_bytes_from_user_memory(&self, num: u64) -> Result<Vec<u8>> {
3940
let peb_ptr = self.peb().unwrap();
4041
let user_memory_region_ptr = unsafe { (*peb_ptr).init_data.ptr as *mut u8 };
@@ -63,6 +64,7 @@ impl GuestHandle {
6364
///
6465
/// When calling `call_host_function<T>`, this function is called
6566
/// internally to get the return value.
67+
#[hyperlight_guest_tracing_macro::trace_function]
6668
pub fn get_host_return_value<T: TryFrom<ReturnValue>>(&self) -> Result<T> {
6769
let return_value = self
6870
.try_pop_shared_input_data_into::<ReturnValue>()
@@ -83,6 +85,7 @@ impl GuestHandle {
8385
///
8486
/// Note: The function return value must be obtained by calling
8587
/// `get_host_return_value`.
88+
#[hyperlight_guest_tracing_macro::trace_function]
8689
pub fn call_host_function_without_returning_result(
8790
&self,
8891
function_name: &str,
@@ -114,6 +117,7 @@ impl GuestHandle {
114117
/// sends it to the host, and then retrieves the return value.
115118
///
116119
/// The return value is deserialized into the specified type `T`.
120+
#[hyperlight_guest_tracing_macro::trace_function]
117121
pub fn call_host_function<T: TryFrom<ReturnValue>>(
118122
&self,
119123
function_name: &str,
@@ -124,6 +128,7 @@ impl GuestHandle {
124128
self.get_host_return_value::<T>()
125129
}
126130

131+
#[hyperlight_guest_tracing_macro::trace_function]
127132
pub fn get_host_function_details(&self) -> HostFunctionDetails {
128133
let peb_ptr = self.peb().unwrap();
129134
let host_function_details_buffer =
@@ -140,6 +145,7 @@ impl GuestHandle {
140145
}
141146

142147
/// Write an error to the shared output data buffer.
148+
#[hyperlight_guest_tracing_macro::trace_function]
143149
pub fn write_error(&self, error_code: ErrorCode, message: Option<&str>) {
144150
let guest_error: GuestError = GuestError::new(
145151
error_code.clone(),
@@ -155,6 +161,7 @@ impl GuestHandle {
155161
}
156162

157163
/// Log a message with the specified log level, source, caller, source file, and line number.
164+
#[hyperlight_guest_tracing_macro::trace_function]
158165
pub fn log_message(
159166
&self,
160167
log_level: LogLevel,

src/hyperlight_guest/src/guest_handle/io.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ use crate::error::{HyperlightGuestError, Result};
2727

2828
impl GuestHandle {
2929
/// Pops the top element from the shared input data buffer and returns it as a T
30+
#[hyperlight_guest_tracing_macro::trace_function]
3031
pub fn try_pop_shared_input_data_into<T>(&self) -> Result<T>
3132
where
3233
T: for<'a> TryFrom<&'a [u8]>,
@@ -78,8 +79,10 @@ impl GuestHandle {
7879
}
7980
};
8081

82+
hyperlight_guest_tracing_macro::trace!("Start copy of data");
8183
// update the stack pointer to point to the element we just popped of since that is now free
8284
idb[..8].copy_from_slice(&last_element_offset_rel.to_le_bytes());
85+
hyperlight_guest_tracing_macro::trace!("Finish copy of data");
8386

8487
// zero out popped off buffer
8588
idb[last_element_offset_rel as usize..stack_ptr_rel as usize].fill(0);
@@ -88,6 +91,7 @@ impl GuestHandle {
8891
}
8992

9093
/// Pushes the given data onto the shared output data buffer.
94+
#[hyperlight_guest_tracing_macro::trace_function]
9195
pub fn push_shared_output_data(&self, data: Vec<u8>) -> Result<()> {
9296
let peb_ptr = self.peb().unwrap();
9397
let output_stack_size = unsafe { (*peb_ptr).output_stack.size as usize };
@@ -133,7 +137,9 @@ impl GuestHandle {
133137
}
134138

135139
// write the actual data
140+
hyperlight_guest_tracing_macro::trace!("Start copy of data");
136141
odb[stack_ptr_rel as usize..stack_ptr_rel as usize + data.len()].copy_from_slice(&data);
142+
hyperlight_guest_tracing_macro::trace!("Finish copy of data");
137143

138144
// write the offset to the newly written data, to the top of the stack
139145
let bytes: [u8; 8] = stack_ptr_rel.to_le_bytes();

src/hyperlight_guest_bin/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,14 @@ and third-party code used by our C-API needed to build a native hyperlight-guest
1717
default = ["libc", "printf"]
1818
libc = [] # compile musl libc
1919
printf = [] # compile printf
20+
trace_guest = ["hyperlight-common/trace_guest", "dep:hyperlight-guest-tracing", "hyperlight-guest/trace_guest"]
2021
mem_profile = ["hyperlight-common/unwind_guest","hyperlight-common/mem_profile"]
2122

2223
[dependencies]
2324
hyperlight-guest = { workspace = true, default-features = false }
2425
hyperlight-common = { workspace = true, default-features = false }
26+
hyperlight-guest-tracing = { workspace = true, optional = true }
27+
hyperlight-guest-tracing-macro = { workspace = true }
2528
buddy_system_allocator = "0.11.0"
2629
log = { version = "0.4", default-features = false }
2730
spin = "0.10.0"

src/hyperlight_guest_bin/src/exceptions/gdt.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ struct GdtPointer {
7272
}
7373

7474
/// Load the GDT
75+
#[hyperlight_guest_tracing_macro::trace_function]
7576
pub unsafe fn load_gdt() {
7677
unsafe {
7778
let gdt_ptr = GdtPointer {

src/hyperlight_guest_bin/src/exceptions/handler.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use hyperlight_guest::exit::abort_with_code_and_message;
2323

2424
/// Exception handler
2525
#[unsafe(no_mangle)]
26+
#[hyperlight_guest_tracing_macro::trace_function]
2627
pub extern "C" fn hl_exception_handler(
2728
stack_pointer: u64,
2829
exception_number: u64,

src/hyperlight_guest_bin/src/exceptions/idt.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ impl IdtEntry {
7171
// Architectures Software Developer's Manual).
7272
pub(crate) static mut IDT: [IdtEntry; 256] = unsafe { core::mem::zeroed() };
7373

74+
#[hyperlight_guest_tracing_macro::trace_function]
7475
pub(crate) fn init_idt() {
7576
set_idt_entry(Exception::DivideByZero as usize, _do_excp0); // Divide by zero
7677
set_idt_entry(Exception::Debug as usize, _do_excp1); // Debug

src/hyperlight_guest_bin/src/exceptions/idtr.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ impl Idtr {
4040
}
4141
}
4242

43+
#[hyperlight_guest_tracing_macro::trace_function]
4344
pub(crate) unsafe fn load_idt() {
4445
unsafe {
4546
init_idt();

src/hyperlight_guest_bin/src/guest_function/call.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ use crate::{GUEST_HANDLE, REGISTERED_GUEST_FUNCTIONS};
2727

2828
type GuestFunc = fn(&FunctionCall) -> Result<Vec<u8>>;
2929

30+
#[hyperlight_guest_tracing_macro::trace_function]
3031
pub(crate) fn call_guest_function(function_call: FunctionCall) -> Result<Vec<u8>> {
3132
// Validate this is a Guest Function Call
3233
if function_call.function_call_type() != FunctionCallType::Guest {
@@ -60,6 +61,7 @@ pub(crate) fn call_guest_function(function_call: FunctionCall) -> Result<Vec<u8>
6061
core::mem::transmute::<usize, GuestFunc>(function_pointer)
6162
};
6263

64+
hyperlight_guest_tracing_macro::trace!("Calling guest function");
6365
p_function(&function_call)
6466
} else {
6567
// The given function is not registered. The guest should implement a function called guest_dispatch_function to handle this.
@@ -71,6 +73,7 @@ pub(crate) fn call_guest_function(function_call: FunctionCall) -> Result<Vec<u8>
7173
fn guest_dispatch_function(function_call: FunctionCall) -> Result<Vec<u8>>;
7274
}
7375

76+
hyperlight_guest_tracing_macro::trace!("Guest function {} not found");
7477
unsafe { guest_dispatch_function(function_call) }
7578
}
7679
}
@@ -79,6 +82,7 @@ pub(crate) fn call_guest_function(function_call: FunctionCall) -> Result<Vec<u8>
7982
// and we will leak memory as the epilogue will not be called as halt() is not going to return.
8083
#[unsafe(no_mangle)]
8184
#[inline(never)]
85+
#[hyperlight_guest_tracing_macro::trace_function]
8286
fn internal_dispatch_function() -> Result<()> {
8387
let handle = unsafe { GUEST_HANDLE };
8488

@@ -99,6 +103,7 @@ fn internal_dispatch_function() -> Result<()> {
99103
// This is implemented as a separate function to make sure that epilogue in the internal_dispatch_function is called before the halt()
100104
// which if it were included in the internal_dispatch_function cause the epilogue to not be called because the halt() would not return
101105
// when running in the hypervisor.
106+
#[hyperlight_guest_tracing_macro::trace_function]
102107
pub(crate) extern "C" fn dispatch_function() {
103108
let _ = internal_dispatch_function();
104109
halt();

0 commit comments

Comments
 (0)