mirror of
https://github.com/codewhale-hq/Codewhale.git
synced 2026-11-11 01:51:34 -10:00
fix(alloc): stop macOS reporting the mimalloc heap as IOAccelerator GPU memory
The 0.10.1 plan read the TUI's idle "61 MB IOAccelerator" as AppKit/ CoreAnimation initialising at startup. It is not: mimalloc tags its macOS VM regions with tag 100, which macOS names VM_MEMORY_IOACCELERATOR, so footprint, vmmap and Activity Monitor show the app's whole heap as GPU memory. Evidence on 0.10.0 release and current debug builds: - MIMALLOC_OS_TAG=254 relabels the same ~66 MB as "app-specific tag 15". - A dlopen interposer sees no Metal/AGX load; the only WindowServer touch is the one-shot CGMainDisplayID refresh probe, which allocates ~0 (a standalone probe of the same calls stays at 2.2 MB). - Linking AppKit/Vision/CoreGraphics alone costs <1 MB. Retag the heap to 254 (VM_MEMORY_APPLICATION_SPECIFIC_15) from a Mach-O initializer in both binaries (codewhale, codewhale-tui). This has to run from an initializer because setting the option from main is too late: the tag sticks to the arena reserved on the first allocation (checked in a scratch crate). An explicit MIMALLOC_OS_TAG still wins. The byte count is unchanged; this fixes the labelling only. MCP: boot is already lazy (#6033). Only required servers and servers covered by an explicit tool selection start at session start. Checks: cargo build -p codewhale-tui --bin codewhale-tui ok; cargo build -p codewhale-cli --bin codewhale ok; rustfmt --check on both files ok. Idle footprint in tmux 200x50: debug codewhale-tui 63 MB "app-specific tag 15" (control on the same binary with MIMALLOC_OS_TAG=100: 59 MB "IOAccelerator"); debug codewhale 71 MB "app-specific tag 15", 0 IOAccelerator. No unit test: the effect is a process-level VM tag, verified with footprint. No tracking issue exists. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
1 parent
2178e69ee0
commit
791b775f75
2 files changed
+64
No files matched your search
@@ -5,6 +5,38 @@
|
||||
#[global_allocator]
|
||||
static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
|
||||
|
||||
// mimalloc tags its macOS VM regions with tag 100 by default, which macOS
|
||||
// names `VM_MEMORY_IOACCELERATOR`. `footprint`, `vmmap` and Activity Monitor
|
||||
// then report the whole heap as GPU memory ("61 MB IOAccelerator" at idle),
|
||||
// which reads as AppKit/CoreAnimation initialising when nothing GPU-related
|
||||
// runs. Retag to 254 (VM_MEMORY_APPLICATION_SPECIFIC_15) so the heap is
|
||||
// labelled as the app's own memory. This must run before the first
|
||||
// allocation, because the tag sticks to the arena mimalloc reserves then;
|
||||
// setting it from `main` is already too late, so it runs as a Mach-O
|
||||
// initializer. An explicit `MIMALLOC_OS_TAG` still wins.
|
||||
#[cfg(all(
|
||||
target_os = "macos",
|
||||
feature = "mimalloc-allocator",
|
||||
not(feature = "rusty-alloc")
|
||||
))]
|
||||
#[used]
|
||||
#[unsafe(link_section = "__DATA,__mod_init_func")]
|
||||
static MIMALLOC_RETAG: extern "C" fn() = {
|
||||
extern "C" fn retag_mimalloc_heap() {
|
||||
unsafe extern "C" {
|
||||
fn mi_option_set(option: std::ffi::c_int, value: std::ffi::c_long);
|
||||
}
|
||||
/// `mi_option_os_tag` in mimalloc's `mi_option_e`.
|
||||
const MI_OPTION_OS_TAG: std::ffi::c_int = 18;
|
||||
if std::env::var_os("MIMALLOC_OS_TAG").is_none() {
|
||||
// SAFETY: mimalloc's option setter is callable before its own
|
||||
// initialisation; it only stores the value.
|
||||
unsafe { mi_option_set(MI_OPTION_OS_TAG, 254) };
|
||||
}
|
||||
}
|
||||
retag_mimalloc_heap
|
||||
};
|
||||
|
||||
#[cfg(feature = "rusty-alloc")]
|
||||
#[global_allocator]
|
||||
static GLOBAL: rusty_alloc_api::RustyAlloc = rusty_alloc_api::RustyAlloc;
|
||||
|
||||
@@ -5,6 +5,38 @@
|
||||
#[global_allocator]
|
||||
static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
|
||||
|
||||
// mimalloc tags its macOS VM regions with tag 100 by default, which macOS
|
||||
// names `VM_MEMORY_IOACCELERATOR`. `footprint`, `vmmap` and Activity Monitor
|
||||
// then report the whole heap as GPU memory ("61 MB IOAccelerator" at idle),
|
||||
// which reads as AppKit/CoreAnimation initialising when nothing GPU-related
|
||||
// runs. Retag to 254 (VM_MEMORY_APPLICATION_SPECIFIC_15) so the heap is
|
||||
// labelled as the app's own memory. This must run before the first
|
||||
// allocation, because the tag sticks to the arena mimalloc reserves then;
|
||||
// setting it from `main` is already too late, so it runs as a Mach-O
|
||||
// initializer. An explicit `MIMALLOC_OS_TAG` still wins.
|
||||
#[cfg(all(
|
||||
target_os = "macos",
|
||||
feature = "mimalloc-allocator",
|
||||
not(feature = "rusty-alloc")
|
||||
))]
|
||||
#[used]
|
||||
#[unsafe(link_section = "__DATA,__mod_init_func")]
|
||||
static MIMALLOC_RETAG: extern "C" fn() = {
|
||||
extern "C" fn retag_mimalloc_heap() {
|
||||
unsafe extern "C" {
|
||||
fn mi_option_set(option: std::ffi::c_int, value: std::ffi::c_long);
|
||||
}
|
||||
/// `mi_option_os_tag` in mimalloc's `mi_option_e`.
|
||||
const MI_OPTION_OS_TAG: std::ffi::c_int = 18;
|
||||
if std::env::var_os("MIMALLOC_OS_TAG").is_none() {
|
||||
// SAFETY: mimalloc's option setter is callable before its own
|
||||
// initialisation; it only stores the value.
|
||||
unsafe { mi_option_set(MI_OPTION_OS_TAG, 254) };
|
||||
}
|
||||
}
|
||||
retag_mimalloc_heap
|
||||
};
|
||||
|
||||
#[cfg(feature = "rusty-alloc")]
|
||||
#[global_allocator]
|
||||
static GLOBAL: rusty_alloc_api::RustyAlloc = rusty_alloc_api::RustyAlloc;
|
||||
|
||||
Reference in new issue
Block a user