build: use mimalloc

mimalloc is a compact general purpose allocator from Microsoft. It
consistently outperforms glibc's `malloc()` in allocation-heavy
workloads, such as Lix's evaluator

It's currently only linked in the main `nix` executable, as Boehm's GC
uses its own allocator. Other allocations that *do* go through glibc's
`malloc()` are still much faster, though

Benchmarked on x86_64-linux against Nixpkgs `bd07873`:

| attribute         | thunks  | lix@`1396012` | mimalloc | uplift |
|-------------------|---------|---------------|----------|--------|
| hello             | 206444  | 0.726s        | 0.620s   | 1.17x  |
| chromium          | 1177382 | 2.273s        | 2.136s   | 1.06x  |
| firefox-unwrapped | 1394797 | 2.521s        | 2.378s   | 1.06x  |
| texliveFull       | 3186440 | 4.992s        | 4.672s   | 1.07x  |
| nixosTests.gnome  | 7905808 | 6.115s        | 5.723s   | 1.07x  |

Based-on: https://github.com/NixOS/nix/pull/15596
Co-authored-by: Bernardo Meurer Costa <beme@anthropic.com>
Change-Id: I3ad92eacc075efeaf3d9f7730ada7b29835536a4
This commit is contained in:
Seth Flynn
2026-07-04 10:39:30 +00:00
committed by seth
co-authored by Bernardo Meurer Costa
parent 12f10fca7e
commit c1370bc81c
5 changed files with 30 additions and 1 deletions
+16
View File
@@ -0,0 +1,16 @@
---
synopsis: "Use mimalloc for faster evaluation"
cls: [5645]
category: Features
credits: [getchoo, lovesegfault]
---
Lix now links with [mimalloc](https://github.com/microsoft/mimalloc),
replacing the system's default `malloc()` for all non-GC allocations.
This yields a **512% wall-clock improvement** on evaluation workloads,
ranging from `nix-instantiate hello` to `nix-env -qa` and full NixOS
configurations.
The allocator can be disabled at build time with `-Dmimalloc=disabled`,
or by passing the `useMimalloc = false` override to the `lix` package.
+1
View File
@@ -172,6 +172,7 @@ nix = executable(
dependencies : [ dependencies : [
liblix, liblix,
boehm, boehm,
mimalloc,
capnp_rpc, capnp_rpc,
nlohmann_json, nlohmann_json,
kj, kj,
+2
View File
@@ -352,6 +352,8 @@ gc_opt = get_option('gc').disable_if(
boehm = dependency('bdw-gc', required : gc_opt, version : '>=8.2.6', include_type : 'system') boehm = dependency('bdw-gc', required : gc_opt, version : '>=8.2.6', include_type : 'system')
configdata.set('HAVE_BOEHMGC', boehm.found().to_int()) configdata.set('HAVE_BOEHMGC', boehm.found().to_int())
mimalloc = dependency('mimalloc', required: get_option('mimalloc'))
boost = dependency('boost', required : true, include_type : 'system') boost = dependency('boost', required : true, include_type : 'system')
kj = dependency('kj-async', required : true, include_type : 'system') kj = dependency('kj-async', required : true, include_type : 'system')
capnp = dependency('capnp', required : true, include_type : 'system') capnp = dependency('capnp', required : true, include_type : 'system')
+4
View File
@@ -8,6 +8,10 @@ option('gc', type : 'feature',
description : 'enable garbage collection in the Nix expression evaluator (requires Boehm GC)', description : 'enable garbage collection in the Nix expression evaluator (requires Boehm GC)',
) )
option('mimalloc', type: 'feature', value: 'auto',
description: 'link against mimalloc to override the default memory allocator',
)
option('enable-embedded-sandbox-shell', type : 'boolean', value : false, option('enable-embedded-sandbox-shell', type : 'boolean', value : false,
description : 'include the sandbox shell in the Nix binary', description : 'include the sandbox shell in the Nix binary',
) )
+7 -1
View File
@@ -42,6 +42,7 @@
cacert, cacert,
mercurial, mercurial,
meson, meson,
mimalloc,
ninja, ninja,
openssl, openssl,
passt, passt,
@@ -75,6 +76,9 @@
# Support garbage collection in the evaluator. # Support garbage collection in the evaluator.
enableGC ? sanitize == null || !builtins.elem "address" sanitize, enableGC ? sanitize == null || !builtins.elem "address" sanitize,
# Whether to use mimalloc over the default `malloc`
# Significantly improves evaluation performance on allocation-heavy workloads
useMimalloc ? true,
# List of Meson sanitize options. Accepts values of b_sanitize, e.g. # List of Meson sanitize options. Accepts values of b_sanitize, e.g.
# "address", "undefined", "thread". # "address", "undefined", "thread".
# Enabling the "address" sanitizer will disable garbage collection in the evaluator. # Enabling the "address" sanitizer will disable garbage collection in the evaluator.
@@ -467,6 +471,7 @@ stdenv.mkDerivation (finalAttrs: {
# so we must explicitly enable or disable features that we are not passing # so we must explicitly enable or disable features that we are not passing
# dependencies for. # dependencies for.
(lib.mesonEnable "gc" enableGC) (lib.mesonEnable "gc" enableGC)
(lib.mesonEnable "mimalloc" useMimalloc)
(lib.mesonEnable "internal-api-docs" internalApiDocs) (lib.mesonEnable "internal-api-docs" internalApiDocs)
(lib.mesonEnable "dtrace-probes" withDtrace) (lib.mesonEnable "dtrace-probes" withDtrace)
(lib.mesonBool "enable-tests" (finalAttrs.finalPackage.doCheck || lintInsteadOfBuild)) (lib.mesonBool "enable-tests" (finalAttrs.finalPackage.doCheck || lintInsteadOfBuild))
@@ -574,7 +579,8 @@ stdenv.mkDerivation (finalAttrs: {
++ lib.optionals (finalAttrs.dontBuild) maybePropagatedInputs ++ lib.optionals (finalAttrs.dontBuild) maybePropagatedInputs
# I am so sorry. This is because checkInputs are required to pass # I am so sorry. This is because checkInputs are required to pass
# configure, but we don't actually want to *run* the checks here. # configure, but we don't actually want to *run* the checks here.
++ lib.optionals lintInsteadOfBuild finalAttrs.checkInputs; ++ lib.optionals lintInsteadOfBuild finalAttrs.checkInputs
++ lib.optional useMimalloc mimalloc;
checkInputs = [ checkInputs = [
gtest gtest