next.js
4425414a - turbo-tasks-malloc: report memory from mimalloc (#97761)

Commit
4 hours ago
turbo-tasks-malloc: report memory from mimalloc (#97761) ### What? `turbo-tasks-malloc` keeps a process-wide `ALLOCATED` atomic to answer `memory_usage()`. To optimize performance thread local buffers were maintained but this lead to code size issues. So instead we rely on mimalloc apis saving 1.6M of binary size ### Why not ask the OS? That was the obvious alternative, and it does not work well. The natural per-platform figures are not the same quantity: macOS `phys_footprint` and Windows `PrivateUsage` account for compressed and swapped pages, but Linux `VmRSS` does not — so under swap or zram the Linux number can read flat, or fall, while real consumption climbs. Closing that gap means `/proc/self/smaps_rollup` (`Pss + SwapPss`), which is not the cheap one-line read it looks like, it takes on the order of [100ms per 4GB](https://github.com/ncabatoff/process-exporter/issues/246), and it would contend with other allocations in our process. ### How? `memory_usage()` reads `current_commit` from `mi_process_info`. We fall back to the `ALLOCATED` atomic only when `custom_allocator` is off. ### Behaviour changes **It does not track frees in lock step.** mimalloc reuses and purges pages on its own schedule or when eviction calls `collect` ### Size Rust inlines `#[global_allocator]` methods into every allocation site, so the buffer arithmetic and the branch guarding it were duplicated across the whole binary. Dropping them from the default build is where the win comes from. `libnext_napi_bindings.dylib`, release profile as shipped (thin LTO, `codegen-units = 1`). | Section | canary | this PR | Δ | |---|---:|---:|---:| | `__text` | 64,833,760 | 63,319,776 | **−1,513,984** | | `__eh_frame` | 8,966,904 | 8,748,464 | −218,440 | | `__gcc_except_tab` | 2,234,428 | 2,229,484 | −4,944 | | `__unwind_info` | 1,489,072 | 1,484,644 | −4,428 | | **Total** | | | **−1,741,796 = −1.66 MiB** | ### Performance `cargo bench -p turbo-tasks-malloc --bench allocation`, macOS aarch64, revisions interleaved across 3 rounds so drift hits both arms equally. Figures are the paired per-round deltas. | benchmark | canary | this PR | mean Δ | per-round | |---|---:|---:|---:|---| | `alloc_dealloc` | 6.65 ns | 6.45 ns | **−2.9%** | −3.7% .. −2.4% | | `alloc_realloc_dealloc` | 18.62 ns | 16.76 ns | **−10.0%** | −10.2% .. −9.7% | Removing the counter takes the buffer arithmetic and its guarding branch out of every allocation, and a realloc pays that twice — which is roughly the shape of the result. That said, the absolute numbers are small (a couple of hundred picoseconds on `alloc_dealloc`) and this benchmark is noisy, so treat the direction as the signal rather than the magnitude.
Author
Parents
Loading