Skip to content

Commit d88d9b0

Browse files
committed
feat(guest): use mimalloc global allocator
1 parent d3826af commit d88d9b0

File tree

9 files changed

+121
-268
lines changed

9 files changed

+121
-268
lines changed

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,6 @@
22
path = src/hyperlight_guest_bin/third_party/picolibc
33
url = https://github.com/picolibc/picolibc.git
44
shallow = true
5+
[submodule "src/hyperlight_guest_bin/third_party/mimalloc"]
6+
path = src/hyperlight_guest_bin/third_party/mimalloc
7+
url = https://github.com/microsoft/mimalloc

Cargo.lock

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

src/hyperlight_guest_bin/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ hyperlight-guest-tracing = { workspace = true, default-features = false }
2727
buddy_system_allocator = "0.11.0"
2828
log = { version = "0.4", default-features = false }
2929
spin = "0.10.0"
30+
libc_alloc = "1.0.7"
3031

3132
[lints]
3233
workspace = true

src/hyperlight_guest_bin/build.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ fn cc_build(picolibc_dir: &PathBuf, target: &str) -> Result<cc::Build> {
209209
.flag("-fno-common")
210210
.flag("-fno-builtin")
211211
.flag("-Wno-unused-command-line-argument")
212+
.flag("-Wno-unused-parameter")
212213
.flag("-fdiagnostics-color=always")
213214
.flag("-Wall")
214215
.flag("-Winvalid-pch")
@@ -265,6 +266,16 @@ fn cc_build(picolibc_dir: &PathBuf, target: &str) -> Result<cc::Build> {
265266
Ok(build)
266267
}
267268

269+
fn add_mimalloc(build: &mut cc::Build, mimalloc_dir: &Path, _target: &str) -> Result<()> {
270+
build.define("MI_MALLOC_OVERRIDE", "1");
271+
build.define("__wasi__", "1");
272+
build.include(mimalloc_dir.join("include"));
273+
build.include(mimalloc_dir.join("src"));
274+
build.file(mimalloc_dir.join("src/static.c"));
275+
276+
Ok(())
277+
}
278+
268279
fn add_libc(build: &mut cc::Build, picolibc_dir: &Path, target: &str) -> Result<()> {
269280
let base = LIBC_FILES.iter();
270281
let files = match target {
@@ -277,7 +288,7 @@ fn add_libc(build: &mut cc::Build, picolibc_dir: &Path, target: &str) -> Result<
277288
build.file(&source_path);
278289
}
279290

280-
build.file("c/clock.c");
291+
build.files(&["c/clock.c", "c/mimalloc.c"]);
281292
Ok(())
282293
}
283294

@@ -331,9 +342,11 @@ fn cargo_main() -> Result<()> {
331342
}
332343

333344
let picolibc_dir = PathBuf::from("third_party/picolibc");
345+
let mimalloc_dir = PathBuf::from("third_party/mimalloc");
334346
let mut build = cc_build(&picolibc_dir, &target)?;
335347

336348
add_libc(&mut build, &picolibc_dir, &target)?;
349+
add_mimalloc(&mut build, &mimalloc_dir, &target)?;
337350

338351
if want_libm {
339352
add_libm(&mut build, &picolibc_dir, &target)?;

src/hyperlight_guest_bin/build_files.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,6 @@ pub(crate) const LIBC_FILES: &[&str] = &[
434434
"ubsan/ubsan_val_to_string.c",
435435
"ubsan/ubsan_val_to_umax.c",
436436
"ubsan/ubsan_warning.c",
437-
"picolib/picosbrk.c",
438437
"picolib/dso_handle.c",
439438
"picolib/getauxval.c",
440439
"picolib/machine/x86/interrupt.c",
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
#include <stdbool.h>
2+
#include <stdlib.h>
3+
#include <stdio.h>
4+
#include <unistd.h>
5+
#include <errno.h>
6+
#include <mimalloc.h>
7+
8+
// -----------------------------------------------------------------------------
9+
// Static variables for sbrk region_
10+
// -----------------------------------------------------------------------------
11+
static char *heap_start = NULL;
12+
static char *heap_end = NULL;
13+
static char *brk_ptr = NULL;
14+
15+
/*
16+
* Initialize a mimalloc arena on the donated memory region.
17+
* After this call, all allocations use only the pre‐reserved arena.
18+
*/
19+
void init_arena(void *donated_ptr, size_t donated_size) {
20+
/* do not use OS memory for allocation */
21+
mi_option_set_enabled(mi_option_limit_os_alloc, true);
22+
23+
mi_arena_id_t arena_id = 0;
24+
bool ok = mi_manage_os_memory_ex(
25+
donated_ptr,
26+
donated_size,
27+
1 /* committed */,
28+
0 /* large */,
29+
0 /* zero */,
30+
-1 /* numa_node */,
31+
1 /* exclusive */,
32+
&arena_id
33+
);
34+
35+
if (!ok) {
36+
fprintf(stderr, "mi_manage_os_memory_ex failed\n");
37+
abort();
38+
}
39+
40+
/* create a heap in the donated arena and set it as default */
41+
mi_heap_t *heap = mi_heap_new_in_arena(arena_id);
42+
mi_heap_set_default(heap);
43+
}
44+
45+
/*
46+
* Register the heap region to be used by sbrk().
47+
* Must be called before any sbrk() invocation.
48+
*/
49+
void init_sbrk(void *start, size_t size) {
50+
heap_start = (char*)start;
51+
heap_end = heap_start + size;
52+
brk_ptr = heap_start;
53+
}
54+
55+
/*
56+
* Unix‐style sbrk implementation over the registered heap region.
57+
* On success returns the previous break; on failure returns (void*)-1
58+
* and sets errno = ENOMEM.
59+
*/
60+
void *sbrk(ptrdiff_t incr) {
61+
if (heap_start == NULL) {
62+
errno = ENOMEM;
63+
return (void*)-1;
64+
}
65+
66+
if (incr < 0) {
67+
/* shrink: ensure we don't move below heap_start */
68+
size_t dec = (size_t)(-incr);
69+
if ((size_t)(brk_ptr - heap_start) < dec) {
70+
errno = ENOMEM;
71+
return (void*)-1;
72+
}
73+
} else {
74+
/* grow: ensure we don't move past heap_end */
75+
size_t inc = (size_t)incr;
76+
if ((size_t)(heap_end - brk_ptr) < inc) {
77+
errno = ENOMEM;
78+
return (void*)-1;
79+
}
80+
}
81+
82+
void *old_brk = brk_ptr;
83+
brk_ptr += incr;
84+
return old_brk;
85+
}

src/hyperlight_guest_bin/src/lib.rs

Lines changed: 10 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ limitations under the License.
1818
// === Dependencies ===
1919
extern crate alloc;
2020

21+
use core::ffi::c_void;
2122
use alloc::string::ToString;
2223

23-
use buddy_system_allocator::LockedHeap;
2424
#[cfg(target_arch = "x86_64")]
2525
use exceptions::{gdt::load_gdt, idtr::load_idt};
2626
use guest_function::call::dispatch_function;
@@ -34,6 +34,7 @@ use hyperlight_guest::exit::{abort_with_code_and_message, halt};
3434
use hyperlight_guest::guest_handle::handle::GuestHandle;
3535
use hyperlight_guest_tracing::{trace, trace_function};
3636
use log::LevelFilter;
37+
use libc_alloc::LibcAlloc;
3738
use spin::Once;
3839

3940
// === Modules ===
@@ -54,75 +55,17 @@ pub mod guest_function {
5455

5556
pub mod guest_logger;
5657
pub mod host_comm;
57-
pub mod memory;
5858
pub mod paging;
5959

6060
#[cfg(feature = "libc")]
6161
mod host_bridge;
6262

63-
// Globals
64-
#[cfg(feature = "mem_profile")]
65-
struct ProfiledLockedHeap<const ORDER: usize>(LockedHeap<ORDER>);
66-
#[cfg(feature = "mem_profile")]
67-
unsafe impl<const ORDER: usize> alloc::alloc::GlobalAlloc for ProfiledLockedHeap<ORDER> {
68-
unsafe fn alloc(&self, layout: core::alloc::Layout) -> *mut u8 {
69-
let addr = unsafe { self.0.alloc(layout) };
70-
unsafe {
71-
core::arch::asm!("out dx, al",
72-
in("dx") OutBAction::TraceMemoryAlloc as u16,
73-
in("rax") layout.size() as u64,
74-
in("rcx") addr as u64);
75-
}
76-
addr
77-
}
78-
unsafe fn dealloc(&self, ptr: *mut u8, layout: core::alloc::Layout) {
79-
unsafe {
80-
core::arch::asm!("out dx, al",
81-
in("dx") OutBAction::TraceMemoryFree as u16,
82-
in("rax") layout.size() as u64,
83-
in("rcx") ptr as u64);
84-
self.0.dealloc(ptr, layout)
85-
}
86-
}
87-
unsafe fn alloc_zeroed(&self, layout: core::alloc::Layout) -> *mut u8 {
88-
let addr = unsafe { self.0.alloc_zeroed(layout) };
89-
unsafe {
90-
core::arch::asm!("out dx, al",
91-
in("dx") OutBAction::TraceMemoryAlloc as u16,
92-
in("rax") layout.size() as u64,
93-
in("rcx") addr as u64);
94-
}
95-
addr
96-
}
97-
unsafe fn realloc(
98-
&self,
99-
ptr: *mut u8,
100-
layout: core::alloc::Layout,
101-
new_size: usize,
102-
) -> *mut u8 {
103-
let new_ptr = unsafe { self.0.realloc(ptr, layout, new_size) };
104-
unsafe {
105-
core::arch::asm!("out dx, al",
106-
in("dx") OutBAction::TraceMemoryFree as u16,
107-
in("rax") layout.size() as u64,
108-
in("rcx") ptr);
109-
core::arch::asm!("out dx, al",
110-
in("dx") OutBAction::TraceMemoryAlloc as u16,
111-
in("rax") new_size as u64,
112-
in("rcx") new_ptr);
113-
}
114-
new_ptr
115-
}
116-
}
63+
64+
11765

11866
// === Globals ===
119-
#[cfg(not(feature = "mem_profile"))]
120-
#[global_allocator]
121-
pub(crate) static HEAP_ALLOCATOR: LockedHeap<32> = LockedHeap::<32>::empty();
122-
#[cfg(feature = "mem_profile")]
12367
#[global_allocator]
124-
pub(crate) static HEAP_ALLOCATOR: ProfiledLockedHeap<32> =
125-
ProfiledLockedHeap(LockedHeap::<32>::empty());
68+
static ALLOCATOR: LibcAlloc = LibcAlloc;
12669

12770
pub(crate) static mut GUEST_HANDLE: GuestHandle = GuestHandle::new();
12871
pub(crate) static mut REGISTERED_GUEST_FUNCTIONS: GuestFunctionRegister =
@@ -154,6 +97,8 @@ fn panic(info: &core::panic::PanicInfo) -> ! {
15497
unsafe extern "C" {
15598
fn hyperlight_main();
15699
fn srand(seed: u32);
100+
fn init_sbrk(donated_ptr: *const c_void, donated_size: usize);
101+
fn init_arena(donated_ptr: *const c_void, donated_size: usize);
157102
}
158103

159104
static INIT: Once = Once::new();
@@ -188,16 +133,10 @@ pub extern "C" fn entrypoint(peb_address: u64, seed: u64, ops: u64, max_log_leve
188133
load_idt();
189134
}
190135

191-
let heap_start = (*peb_ptr).guest_heap.ptr as usize;
136+
let heap_start = (*peb_ptr).guest_heap.ptr as *const c_void;
192137
let heap_size = (*peb_ptr).guest_heap.size as usize;
193-
#[cfg(not(feature = "mem_profile"))]
194-
let heap_allocator = &HEAP_ALLOCATOR;
195-
#[cfg(feature = "mem_profile")]
196-
let heap_allocator = &HEAP_ALLOCATOR.0;
197-
heap_allocator
198-
.try_lock()
199-
.expect("Failed to access HEAP_ALLOCATOR")
200-
.init(heap_start, heap_size);
138+
init_arena(heap_start, heap_size);
139+
init_sbrk(heap_start, heap_size);
201140

202141
OS_PAGE_SIZE = ops as u32;
203142

0 commit comments

Comments
 (0)