Skip to content

Commit a2ea1e2

Browse files
committed
feat(guest): use mimalloc global allocator
1 parent a59c7ce commit a2ea1e2

File tree

9 files changed

+125
-292
lines changed

9 files changed

+125
-292
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: 10 additions & 22 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 & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ mem_profile = ["hyperlight-common/unwind_guest","hyperlight-common/mem_profile"]
2323
hyperlight-guest = { workspace = true, default-features = false }
2424
hyperlight-common = { workspace = true, default-features = false }
2525
hyperlight-guest-tracing = { workspace = true, default-features = false }
26-
buddy_system_allocator = "0.11.0"
2726
log = { version = "0.4", default-features = false }
2827
spin = "0.10.0"
28+
libc_alloc = "1.0.7"
2929

3030
[lints]
3131
workspace = true

src/hyperlight_guest_bin/build.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,10 +211,11 @@ fn cc_build(picolibc_dir: &PathBuf, target: &str) -> Result<cc::Build> {
211211
.flag("-fdiagnostics-color=always")
212212
.flag("-fno-common")
213213
.flag("-Wall")
214+
.flag("-Wextra")
214215
.flag("-Winvalid-pch")
215216
.flag("-Wno-unused-command-line-argument")
216217
.flag("-Wno-unsupported-floating-point-opt")
217-
.flag("-Wextra")
218+
.flag("-Wno-unused-parameter")
218219
// We don't support stack protectors at the moment, but Arch Linux clang
219220
// auto-enables them for -linux platforms, so explicitly disable them.
220221
.flag("-fno-stack-protector")
@@ -273,6 +274,16 @@ fn cc_build(picolibc_dir: &PathBuf, target: &str) -> Result<cc::Build> {
273274
Ok(build)
274275
}
275276

277+
fn add_mimalloc(build: &mut cc::Build, mimalloc_dir: &Path, _target: &str) -> Result<()> {
278+
build.define("MI_MALLOC_OVERRIDE", "1");
279+
build.define("__wasi__", "1");
280+
build.include(mimalloc_dir.join("include"));
281+
build.include(mimalloc_dir.join("src"));
282+
build.file(mimalloc_dir.join("src/static.c"));
283+
284+
Ok(())
285+
}
286+
276287
fn add_libc(build: &mut cc::Build, picolibc_dir: &Path, target: &str) -> Result<()> {
277288
let base = LIBC_FILES.iter();
278289
let files = match target {
@@ -285,7 +296,7 @@ fn add_libc(build: &mut cc::Build, picolibc_dir: &Path, target: &str) -> Result<
285296
build.file(&source_path);
286297
}
287298

288-
build.file("c/clock.c");
299+
build.files(&["c/clock.c", "c/mimalloc.c"]);
289300
Ok(())
290301
}
291302

@@ -335,10 +346,12 @@ fn cargo_main() -> Result<()> {
335346
}
336347

337348
let picolibc_dir = PathBuf::from("third_party/picolibc");
349+
let mimalloc_dir = PathBuf::from("third_party/mimalloc");
338350
let mut build = cc_build(&picolibc_dir, &target)?;
339351

340352
add_libc(&mut build, &picolibc_dir, &target)?;
341353
add_libm(&mut build, &picolibc_dir, &target)?;
354+
add_mimalloc(&mut build, &mimalloc_dir, &target)?;
342355

343356
if cfg!(windows) {
344357
unsafe { env::set_var("AR_x86_64_unknown_none", "llvm-ar") };

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 =
@@ -156,6 +99,8 @@ unsafe extern "C" {
15699

157100
#[cfg(feature = "libc")]
158101
fn srand(seed: u32);
102+
fn init_sbrk(donated_ptr: *const c_void, donated_size: usize);
103+
fn init_arena(donated_ptr: *const c_void, donated_size: usize);
159104
}
160105

161106
static INIT: Once = Once::new();
@@ -192,16 +137,10 @@ pub extern "C" fn entrypoint(peb_address: u64, _seed: u64, ops: u64, max_log_lev
192137
load_idt();
193138
}
194139

195-
let heap_start = (*peb_ptr).guest_heap.ptr as usize;
140+
let heap_start = (*peb_ptr).guest_heap.ptr as *const c_void;
196141
let heap_size = (*peb_ptr).guest_heap.size as usize;
197-
#[cfg(not(feature = "mem_profile"))]
198-
let heap_allocator = &HEAP_ALLOCATOR;
199-
#[cfg(feature = "mem_profile")]
200-
let heap_allocator = &HEAP_ALLOCATOR.0;
201-
heap_allocator
202-
.try_lock()
203-
.expect("Failed to access HEAP_ALLOCATOR")
204-
.init(heap_start, heap_size);
142+
init_arena(heap_start, heap_size);
143+
init_sbrk(heap_start, heap_size);
205144

206145
OS_PAGE_SIZE = ops as u32;
207146

0 commit comments

Comments
 (0)