From f1ef994f120a723839a6d837cc2b33914a30a4db Mon Sep 17 00:00:00 2001 From: Seth Flynn Date: Thu, 7 Aug 2025 19:42:37 -0400 Subject: [PATCH] libexpr: enable parallel marking in boehm-gc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using parallel marking in GC speeds up evaluation a fair bit ``` Benchmark 1: ./lix-main/bin/nix search nixpkgs hello --no-eval-cache Time (mean ± σ): 20.740 s ± 0.046 s [User: 17.583 s, System: 3.062 s] Range (min … max): 20.678 s … 20.794 s 10 runs Benchmark 2: ./lix-parallel-marking/bin/nix search nixpkgs hello --no-eval-cache Time (mean ± σ): 15.037 s ± 0.080 s [User: 19.602 s, System: 3.125 s] Range (min … max): 14.960 s … 15.227 s 10 runs Summary ./lix-parallel-marking/bin/nix search nixpkgs hello --no-eval-cache ran 1.38 ± 0.01 times faster than ./lix-main/bin/nix search nixpkgs hello --no-eval-cache ``` Based-on: https://github.com/NixOS/nix/pull/13708 Co-authored-by: Eelco Dolstra Change-Id: Ibc7625f21e0ee7c8ad66203eeb3aca5d83977731 --- doc/manual/change-authors.yml | 5 +++++ doc/manual/rl-next/parallel-marking.md | 9 +++++++++ lix/libexpr/eval.cc | 18 ++++++++++++++++++ package.nix | 19 +++++++++++++++++-- 4 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 doc/manual/rl-next/parallel-marking.md diff --git a/doc/manual/change-authors.yml b/doc/manual/change-authors.yml index 1a8eddcd2..313e0647c 100644 --- a/doc/manual/change-authors.yml +++ b/doc/manual/change-authors.yml @@ -86,6 +86,11 @@ ericson: display_name: John Ericson github: ericson2314 +getchoo: + display_name: Seth Flynn + forgejo: getchoo + github: getchoo + gilice: forgejo: gilice diff --git a/doc/manual/rl-next/parallel-marking.md b/doc/manual/rl-next/parallel-marking.md new file mode 100644 index 000000000..0b646595b --- /dev/null +++ b/doc/manual/rl-next/parallel-marking.md @@ -0,0 +1,9 @@ +--- +synopsis: Lix now enables parallel marking in boehm-gc +issues: [fj#983] +cls: [3880] +category: Improvements +credits: [edolstra, getchoo] +--- + +This brings a fairly modest performance improvement (~38% for `nixpkgs search hello`) to evaluation, especially in scenarios that necessitate larger heap sizes. diff --git a/lix/libexpr/eval.cc b/lix/libexpr/eval.cc index 139b42c21..e43af5aa4 100644 --- a/lix/libexpr/eval.cc +++ b/lix/libexpr/eval.cc @@ -43,6 +43,21 @@ #include #include +// Ignore all internal signals boehm uses for parallel marking +// FIXME: Find out how to do this with LLDB for macOS! +#ifndef __APPLE__ +[[gnu::section(".debug_gdb_scripts"), gnu::used]] +// TODO: We should use `SECTION_SCRIPT_ID_PYTHON_TEXT` from +// `` instead of hardcoding 4. +// But why isn't this header exported by GDB? +static const char printer_script[] = + "\4" + R"(lix-ignore-boehm-signals +import gdb +gdb.execute("handle SIGPWR SIGXCPU ignore") +)"; +#endif + #if HAVE_BOEHMGC #define GC_INCLUDE_NEW @@ -161,6 +176,9 @@ void initLibExpr() GC_INIT(); + // Enable parallel marking + GC_start_mark_threads(); + GC_set_oom_fn(oomHandler); /* Set the initial heap size to something fairly big (25% of diff --git a/package.nix b/package.nix index eb0e5c602..cdc7f1228 100644 --- a/package.nix +++ b/package.nix @@ -95,7 +95,20 @@ versionJson = builtins.fromJSON (builtins.readFile ./version.json); - boehmgc-nix = boehmgc.override { enableLargeConfig = true; }; + boehmgc-nix = (boehmgc.override { enableLargeConfig = true; }).overrideAttrs (oldAttrs: { + /* + TODO: Use the `initialMarkStackSize` override when + https://github.com/NixOS/nixpkgs/pull/439943 hits a stable branch + + Increase the initial mark stack size to avoid stack + overflows, since these inhibit parallel marking (see + GC_mark_some()). To check whether the mark stack is too + small, run Nix with GC_PRINT_STATS=1 and look for messages + such as `Mark stack overflow`, `No room to copy back mark + stack`, and `Grew mark stack to ... frames`. + */ + NIX_CFLAGS_COMPILE = (oldAttrs.NIX_CFLAGS_COMPILE or "") + " -DINITIAL_MARK_STACK_SIZE=1048576"; + }); editline-lix = editline.overrideAttrs (prev: { configureFlags = (prev.configureFlags or [ ]) ++ [ @@ -469,7 +482,9 @@ stdenv.mkDerivation (finalAttrs: { runHook postInstallCheck ''; - separateDebugInfo = !hostPlatform.isStatic && !finalAttrs.dontBuild; + # NOTE: This is disabled everywhere except Darwin due to Nixpkgs + # corrupting `.debug_gdb_scripts` segments (which currently aren't used on Darwin) + separateDebugInfo = !hostPlatform.isStatic && !finalAttrs.dontBuild && hostPlatform.isDarwin; strictDeps = true;