Skip to content

Commit 4196a2f

Browse files
committed
Make serializing a FunctionCall return a &[u8] instead of Vec<u8>.
This should save memory allocations, but require that a FlatBufferBuilder is passed in. Signed-off-by: Ludvig Liljenberg <[email protected]>
1 parent f199a86 commit 4196a2f

File tree

12 files changed

+153
-164
lines changed

12 files changed

+153
-164
lines changed

Cargo.lock

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

src/hyperlight_common/src/flatbuffer_wrappers/function_call.rs

Lines changed: 116 additions & 144 deletions
Large diffs are not rendered by default.

src/hyperlight_guest/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ anyhow = { version = "1.0.98", default-features = false }
1616
serde_json = { version = "1.0", default-features = false, features = ["alloc"] }
1717
hyperlight-common = { workspace = true }
1818
hyperlight-guest-tracing = { workspace = true, default-features = false }
19+
flatbuffers = { version= "25.2.10", default-features = false }
1920

2021
[features]
2122
default = []

src/hyperlight_guest/src/guest_handle/host_comm.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use alloc::string::ToString;
1919
use alloc::vec::Vec;
2020
use core::slice::from_raw_parts;
2121

22+
use flatbuffers::FlatBufferBuilder;
2223
use hyperlight_common::flatbuffer_wrappers::function_call::{FunctionCall, FunctionCallType};
2324
use hyperlight_common::flatbuffer_wrappers::function_types::{
2425
ParameterValue, ReturnType, ReturnValue,
@@ -99,10 +100,9 @@ impl GuestHandle {
99100
return_type,
100101
);
101102

102-
let host_function_call_buffer: Vec<u8> = host_function_call
103-
.try_into()
104-
.expect("Unable to serialize host function call");
103+
let mut builder = FlatBufferBuilder::new();
105104

105+
let host_function_call_buffer = host_function_call.encode(&mut builder);
106106
self.push_shared_output_data(host_function_call_buffer)?;
107107

108108
unsafe {
@@ -155,7 +155,7 @@ impl GuestHandle {
155155
.try_into()
156156
.expect("Invalid guest_error_buffer, could not be converted to a Vec<u8>");
157157

158-
if let Err(e) = self.push_shared_output_data(guest_error_buffer) {
158+
if let Err(e) = self.push_shared_output_data(&guest_error_buffer) {
159159
panic!("Unable to push guest error to shared output data: {:#?}", e);
160160
}
161161
}
@@ -184,7 +184,7 @@ impl GuestHandle {
184184
.try_into()
185185
.expect("Failed to convert GuestLogData to bytes");
186186

187-
self.push_shared_output_data(bytes)
187+
self.push_shared_output_data(&bytes)
188188
.expect("Unable to push log data to shared output data");
189189

190190
unsafe {

src/hyperlight_guest/src/guest_handle/io.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ limitations under the License.
1616

1717
use alloc::format;
1818
use alloc::string::ToString;
19-
use alloc::vec::Vec;
2019
use core::any::type_name;
2120
use core::slice::from_raw_parts_mut;
2221

@@ -93,7 +92,7 @@ impl GuestHandle {
9392

9493
/// Pushes the given data onto the shared output data buffer.
9594
#[hyperlight_guest_tracing::trace_function]
96-
pub fn push_shared_output_data(&self, data: Vec<u8>) -> Result<()> {
95+
pub fn push_shared_output_data(&self, data: &[u8]) -> Result<()> {
9796
let peb_ptr = self.peb().unwrap();
9897
let output_stack_size = unsafe { (*peb_ptr).output_stack.size as usize };
9998
let output_stack_ptr = unsafe { (*peb_ptr).output_stack.ptr as *mut u8 };
@@ -139,7 +138,7 @@ impl GuestHandle {
139138

140139
// write the actual data
141140
hyperlight_guest_tracing::trace!("copy data", {
142-
odb[stack_ptr_rel as usize..stack_ptr_rel as usize + data.len()].copy_from_slice(&data);
141+
odb[stack_ptr_rel as usize..stack_ptr_rel as usize + data.len()].copy_from_slice(data);
143142
});
144143

145144
// write the offset to the newly written data, to the top of the stack

src/hyperlight_guest_bin/src/guest_function/call.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ fn internal_dispatch_function() -> Result<()> {
9898
handle.write_error(e.kind, Some(e.message.as_str()));
9999
})?;
100100

101-
handle.push_shared_output_data(result_vec)
101+
handle.push_shared_output_data(&result_vec)
102102
}
103103

104104
// This is implemented as a separate function to make sure that epilogue in the internal_dispatch_function is called before the halt()

src/hyperlight_host/benches/benchmarks.rs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ limitations under the License.
1515
*/
1616

1717
use criterion::{Criterion, criterion_group, criterion_main};
18+
use flatbuffers::FlatBufferBuilder;
1819
use hyperlight_common::flatbuffer_wrappers::function_call::{FunctionCall, FunctionCallType};
1920
use hyperlight_common::flatbuffer_wrappers::function_types::{ParameterValue, ReturnType};
2021
use hyperlight_host::GuestBinary;
@@ -157,20 +158,28 @@ fn function_call_serialization_benchmark(c: &mut Criterion) {
157158
ReturnType::Int,
158159
);
159160

160-
let serialized_bytes: Vec<u8> = function_call.clone().try_into().unwrap();
161-
162161
group.bench_function("serialize_function_call", |b| {
163162
b.iter_with_setup(
164-
|| function_call.clone(),
165-
|fc| {
166-
let _serialized: Vec<u8> = fc.try_into().unwrap();
163+
|| {
164+
(
165+
FlatBufferBuilder::with_capacity(64 * 1024 * 1024),
166+
function_call.clone(),
167+
)
168+
},
169+
|(mut builder, fc)| {
170+
let serialized: &[u8] = fc.encode(&mut builder);
171+
std::hint::black_box(serialized);
167172
},
168173
);
169174
});
170175

171176
group.bench_function("deserialize_function_call", |b| {
177+
let mut builder = FlatBufferBuilder::new();
178+
let bytes = function_call.clone().encode(&mut builder).to_vec();
179+
172180
b.iter(|| {
173-
let _deserialized: FunctionCall = serialized_bytes.as_slice().try_into().unwrap();
181+
let deserialized: FunctionCall = (&bytes[..]).try_into().unwrap();
182+
std::hint::black_box(deserialized);
174183
});
175184
});
176185

src/hyperlight_host/src/sandbox/initialized_multi_use.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,12 @@ use std::path::Path;
2323
use std::sync::atomic::{AtomicU64, Ordering};
2424
use std::sync::{Arc, Mutex};
2525

26+
use flatbuffers::FlatBufferBuilder;
2627
use hyperlight_common::flatbuffer_wrappers::function_call::{FunctionCall, FunctionCallType};
2728
use hyperlight_common::flatbuffer_wrappers::function_types::{
2829
ParameterValue, ReturnType, ReturnValue,
2930
};
31+
use hyperlight_common::flatbuffer_wrappers::util::estimate_flatbuffer_capacity;
3032
use tracing::{Span, instrument};
3133

3234
use super::host_funcs::FunctionRegistry;
@@ -44,7 +46,7 @@ use crate::mem::memory_region::{MemoryRegion, MemoryRegionFlags};
4446
use crate::mem::ptr::RawPtr;
4547
use crate::mem::shared_mem::HostSharedMemory;
4648
use crate::metrics::maybe_time_and_emit_guest_call;
47-
use crate::{HyperlightError, Result, log_then_return};
49+
use crate::{Result, log_then_return};
4850

4951
/// Global counter for assigning unique IDs to sandboxes
5052
static SANDBOX_ID_COUNTER: AtomicU64 = AtomicU64::new(0);
@@ -392,20 +394,21 @@ impl MultiUseSandbox {
392394
args: Vec<ParameterValue>,
393395
) -> Result<ReturnValue> {
394396
let res = (|| {
397+
let estimated_capacity = estimate_flatbuffer_capacity(function_name, &args);
398+
395399
let fc = FunctionCall::new(
396400
function_name.to_string(),
397401
Some(args),
398402
FunctionCallType::Guest,
399403
return_type,
400404
);
401405

402-
let buffer: Vec<u8> = fc.try_into().map_err(|_| {
403-
HyperlightError::Error("Failed to serialize FunctionCall".to_string())
404-
})?;
406+
let mut builder = FlatBufferBuilder::with_capacity(estimated_capacity);
407+
let buffer = fc.encode(&mut builder);
405408

406409
self.get_mgr_wrapper_mut()
407410
.as_mut()
408-
.write_guest_function_call(&buffer)?;
411+
.write_guest_function_call(buffer)?;
409412

410413
self.vm.dispatch_call_from_host(
411414
self.dispatch_ptr.clone(),

src/tests/rust_guests/callbackguest/Cargo.lock

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

src/tests/rust_guests/dummyguest/Cargo.lock

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

0 commit comments

Comments
 (0)