Skip to content

Commit 1dea1fd

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 <[email protected]>
1 parent cb8c1fc commit 1dea1fd

File tree

19 files changed

+208
-51
lines changed

19 files changed

+208
-51
lines changed

Cargo.lock

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

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: 10 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)
@@ -62,7 +68,10 @@ pub unsafe fn abort_with_code_and_message(code: &[u8], message_ptr: *const c_cha
6268
}
6369

6470
/// OUT bytes to the host through multiple exits.
71+
#[hyperlight_guest_tracing_macro::trace_function]
6572
pub(crate) fn outb(port: u16, data: &[u8]) {
73+
// Ensure all tracing data is flushed before sending OUT bytes
74+
hyperlight_guest_tracing_macro::flush!();
6675
unsafe {
6776
let mut i = 0;
6877
while i < data.len() {
@@ -79,6 +88,7 @@ pub(crate) fn outb(port: u16, data: &[u8]) {
7988
}
8089

8190
/// OUT function for sending a 32-bit value to the host.
91+
#[hyperlight_guest_tracing_macro::trace_function]
8292
pub(crate) unsafe fn out32(port: u16, val: u32) {
8393
unsafe {
8494
asm!("out dx, eax", in("dx") port, in("eax") val, options(preserves_flags, nomem, nostack));

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,
@@ -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: 16 additions & 9 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]>,
@@ -68,15 +69,18 @@ impl GuestHandle {
6869
let buffer = &idb[last_element_offset_rel as usize..];
6970

7071
// convert the buffer to T
71-
let type_t = match T::try_from(buffer) {
72-
Ok(t) => Ok(t),
73-
Err(_e) => {
74-
return Err(HyperlightGuestError::new(
75-
ErrorCode::GuestError,
76-
format!("Unable to convert buffer to {}", type_name::<T>()),
77-
));
72+
let type_t = hyperlight_guest_tracing_macro::trace!(
73+
"convert buffer",
74+
match T::try_from(buffer) {
75+
Ok(t) => Ok(t),
76+
Err(_e) => {
77+
return Err(HyperlightGuestError::new(
78+
ErrorCode::GuestError,
79+
format!("Unable to convert buffer to {}", type_name::<T>()),
80+
));
81+
}
7882
}
79-
};
83+
);
8084

8185
// update the stack pointer to point to the element we just popped of since that is now free
8286
idb[..8].copy_from_slice(&last_element_offset_rel.to_le_bytes());
@@ -88,6 +92,7 @@ impl GuestHandle {
8892
}
8993

9094
/// Pushes the given data onto the shared output data buffer.
95+
#[hyperlight_guest_tracing_macro::trace_function]
9196
pub fn push_shared_output_data(&self, data: Vec<u8>) -> Result<()> {
9297
let peb_ptr = self.peb().unwrap();
9398
let output_stack_size = unsafe { (*peb_ptr).output_stack.size as usize };
@@ -133,7 +138,9 @@ impl GuestHandle {
133138
}
134139

135140
// write the actual data
136-
odb[stack_ptr_rel as usize..stack_ptr_rel as usize + data.len()].copy_from_slice(&data);
141+
hyperlight_guest_tracing_macro::trace!("copy data", {
142+
odb[stack_ptr_rel as usize..stack_ptr_rel as usize + data.len()].copy_from_slice(&data);
143+
});
137144

138145
// write the offset to the newly written data, to the top of the stack
139146
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: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,12 @@ pub extern "C" fn hl_exception_handler(
6565
exception_number: u64,
6666
page_fault_address: u64,
6767
) {
68+
// When using the `trace_function` macro, it wraps the function body with create_trace_record
69+
// call, which generates a warning because of the `abort_with_code_and_message` call which does
70+
// not return.
71+
// This is manually added to avoid the warning.
72+
hyperlight_guest_tracing_macro::trace!("> hl_exception_handler");
73+
6874
let ctx = stack_pointer as *mut Context;
6975
let exn_info = (stack_pointer + size_of::<Context>() as u64) as *mut ExceptionInfo;
7076

@@ -95,6 +101,7 @@ pub extern "C" fn hl_exception_handler(
95101
)(exception_number, exn_info, ctx, page_fault_address)
96102
}
97103
{
104+
hyperlight_guest_tracing_macro::trace!("< hl_exception_handler");
98105
return;
99106
}
100107
}

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();

0 commit comments

Comments
 (0)