From c1370bc81c102a8d4ed605b299a9508d121e7c5b Mon Sep 17 00:00:00 2001 From: Seth Flynn Date: Sun, 7 Jun 2026 18:55:24 -0400 Subject: [PATCH] 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 Change-Id: I3ad92eacc075efeaf3d9f7730ada7b29835536a4 --- doc/manual/rl-next/mimalloc.md | 16 ++++++++++++++++ lix/nix/meson.build | 1 + meson.build | 2 ++ meson.options | 4 ++++ package.nix | 8 +++++++- 5 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 doc/manual/rl-next/mimalloc.md diff --git a/doc/manual/rl-next/mimalloc.md b/doc/manual/rl-next/mimalloc.md new file mode 100644 index 000000000..b16c290d8 --- /dev/null +++ b/doc/manual/rl-next/mimalloc.md @@ -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 **5–12% 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. diff --git a/lix/nix/meson.build b/lix/nix/meson.build index 1e25ea143..155920a32 100644 --- a/lix/nix/meson.build +++ b/lix/nix/meson.build @@ -172,6 +172,7 @@ nix = executable( dependencies : [ liblix, boehm, + mimalloc, capnp_rpc, nlohmann_json, kj, diff --git a/meson.build b/meson.build index f306d74df..a5833eaaa 100644 --- a/meson.build +++ b/meson.build @@ -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') configdata.set('HAVE_BOEHMGC', boehm.found().to_int()) +mimalloc = dependency('mimalloc', required: get_option('mimalloc')) + boost = dependency('boost', required : true, include_type : 'system') kj = dependency('kj-async', required : true, include_type : 'system') capnp = dependency('capnp', required : true, include_type : 'system') diff --git a/meson.options b/meson.options index 573589d16..6c194ccaf 100644 --- a/meson.options +++ b/meson.options @@ -8,6 +8,10 @@ option('gc', type : 'feature', 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, description : 'include the sandbox shell in the Nix binary', ) diff --git a/package.nix b/package.nix index a7e67d353..f893e7c22 100644 --- a/package.nix +++ b/package.nix @@ -42,6 +42,7 @@ cacert, mercurial, meson, + mimalloc, ninja, openssl, passt, @@ -75,6 +76,9 @@ # Support garbage collection in the evaluator. 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. # "address", "undefined", "thread". # 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 # dependencies for. (lib.mesonEnable "gc" enableGC) + (lib.mesonEnable "mimalloc" useMimalloc) (lib.mesonEnable "internal-api-docs" internalApiDocs) (lib.mesonEnable "dtrace-probes" withDtrace) (lib.mesonBool "enable-tests" (finalAttrs.finalPackage.doCheck || lintInsteadOfBuild)) @@ -574,7 +579,8 @@ stdenv.mkDerivation (finalAttrs: { ++ lib.optionals (finalAttrs.dontBuild) maybePropagatedInputs # I am so sorry. This is because checkInputs are required to pass # 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 = [ gtest