From ebc8f56b52a465622a511967d06e64cfd4a3c8b0 Mon Sep 17 00:00:00 2001 From: Raito Bezarius Date: Mon, 9 Jun 2025 19:55:37 +0200 Subject: [PATCH] libexpr/primops: pass the underlying `Value` of symbols if possible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of allocating a new Value and copy the symbol string representation inside of it, we can pass along the underlying Value, which avoids (garbage collected) allocations. This results in: * a ~8 % reduction for `gc.totalBytes` over `nixos.ec2.closures.x86_64-linux` for NixOS 24.11. (920MiB → 842MiB) * a slight reduction in CPU time due to less allocations being performed at all Change-Id: I097f586dbc98f889fbc62d0a5f80c9d76ddedfd2 Signed-off-by: Raito Bezarius --- lix/libexpr/primops.cc | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lix/libexpr/primops.cc b/lix/libexpr/primops.cc index 3ed9c68c9..93fbc7c5b 100644 --- a/lix/libexpr/primops.cc +++ b/lix/libexpr/primops.cc @@ -1582,7 +1582,7 @@ static void prim_attrNames(EvalState & state, Value * * args, Value & v) size_t n = 0; for (auto & i : *args[0]->attrs) - (v.listElems()[n++] = state.ctx.mem.allocValue())->mkString(state.ctx.symbols[i.name]); + v.listElems()[n++] = const_cast(state.ctx.symbols[i.name].toValuePtr()); std::sort(v.listElems(), v.listElems() + n, [](Value * v1, Value * v2) { return strcmp(v1->string.s, v2->string.s) < 0; }); @@ -1881,9 +1881,8 @@ static void prim_mapAttrs(EvalState & state, Value * * args, Value & v) auto attrs = state.ctx.buildBindings(args[1]->attrs->size()); for (auto & i : *args[1]->attrs) { - Value * vName = state.ctx.mem.allocValue(); Value * vFun2 = state.ctx.mem.allocValue(); - vName->mkString(state.ctx.symbols[i.name]); + auto vName = const_cast(state.ctx.symbols[i.name].toValuePtr()); vFun2->mkApp(args[0], vName); attrs.alloc(i.name).mkApp(vFun2, i.value); } @@ -1929,8 +1928,7 @@ static void prim_zipAttrsWith(EvalState & state, Value * * args, Value & v) } for (auto & attr : *v.attrs) { - auto name = state.ctx.mem.allocValue(); - name->mkString(state.ctx.symbols[attr.name]); + auto name = const_cast(state.ctx.symbols[attr.name].toValuePtr()); auto call1 = state.ctx.mem.allocValue(); call1->mkApp(args[0], name); auto call2 = state.ctx.mem.allocValue();