From 128750225d8ad8c23364a1e1051799530e786ac0 Mon Sep 17 00:00:00 2001 From: Sergei Zimmerman Date: Sun, 25 May 2025 14:58:31 +0000 Subject: [PATCH] libexpr: Pass mutable `EvalState` to `EvalProfiler` Sometimes the profiler might want to do evaluation (e.g. for getting derivation names). This is not ideal, but is really necessary to make the profiler stack traces useful for end users. --- src/libexpr/eval-profiler.cc | 28 ++++++++----------- src/libexpr/function-trace.cc | 4 +-- src/libexpr/include/nix/expr/eval-profiler.hh | 13 ++++----- .../include/nix/expr/function-trace.hh | 4 +-- 4 files changed, 20 insertions(+), 29 deletions(-) diff --git a/src/libexpr/eval-profiler.cc b/src/libexpr/eval-profiler.cc index f08b46e6b..bf2442c31 100644 --- a/src/libexpr/eval-profiler.cc +++ b/src/libexpr/eval-profiler.cc @@ -5,18 +5,14 @@ namespace nix { -void EvalProfiler::preFunctionCallHook( - const EvalState & state, const Value & v, std::span args, const PosIdx pos) -{ -} +void EvalProfiler::preFunctionCallHook(EvalState & state, const Value & v, std::span args, const PosIdx pos) {} -void EvalProfiler::postFunctionCallHook( - const EvalState & state, const Value & v, std::span args, const PosIdx pos) +void EvalProfiler::postFunctionCallHook(EvalState & state, const Value & v, std::span args, const PosIdx pos) { } void MultiEvalProfiler::preFunctionCallHook( - const EvalState & state, const Value & v, std::span args, const PosIdx pos) + EvalState & state, const Value & v, std::span args, const PosIdx pos) { for (auto & profiler : profilers) { if (profiler->getNeededHooks().test(Hook::preFunctionCall)) @@ -25,7 +21,7 @@ void MultiEvalProfiler::preFunctionCallHook( } void MultiEvalProfiler::postFunctionCallHook( - const EvalState & state, const Value & v, std::span args, const PosIdx pos) + EvalState & state, const Value & v, std::span args, const PosIdx pos) { for (auto & profiler : profilers) { if (profiler->getNeededHooks().test(Hook::postFunctionCall)) @@ -126,7 +122,7 @@ class SampleStack : public EvalProfiler } public: - SampleStack(const EvalState & state, std::filesystem::path profileFile, std::chrono::nanoseconds period) + SampleStack(EvalState & state, std::filesystem::path profileFile, std::chrono::nanoseconds period) : state(state) , sampleInterval(period) , profileFd([&]() { @@ -140,9 +136,9 @@ public: } [[gnu::noinline]] void - preFunctionCallHook(const EvalState & state, const Value & v, std::span args, const PosIdx pos) override; + preFunctionCallHook(EvalState & state, const Value & v, std::span args, const PosIdx pos) override; [[gnu::noinline]] void - postFunctionCallHook(const EvalState & state, const Value & v, std::span args, const PosIdx pos) override; + postFunctionCallHook(EvalState & state, const Value & v, std::span args, const PosIdx pos) override; void maybeSaveProfile(std::chrono::time_point now); void saveProfile(); @@ -156,7 +152,7 @@ public: private: /** Hold on to an instance of EvalState for symbolizing positions. */ - const EvalState & state; + EvalState & state; std::chrono::nanoseconds sampleInterval; AutoCloseFD profileFd; FrameStack stack; @@ -191,7 +187,7 @@ FrameInfo SampleStack::getFrameInfoFromValueAndPos(const Value & v, PosIdx pos) } [[gnu::noinline]] void SampleStack::preFunctionCallHook( - const EvalState & state, const Value & v, [[maybe_unused]] std::span args, const PosIdx pos) + EvalState & state, const Value & v, [[maybe_unused]] std::span args, const PosIdx pos) { stack.push_back(getFrameInfoFromValueAndPos(v, pos)); @@ -208,9 +204,8 @@ FrameInfo SampleStack::getFrameInfoFromValueAndPos(const Value & v, PosIdx pos) } [[gnu::noinline]] void -SampleStack::postFunctionCallHook(const EvalState & state, const Value & v, std::span args, const PosIdx pos) +SampleStack::postFunctionCallHook(EvalState & state, const Value & v, std::span args, const PosIdx pos) { - if (!stack.empty()) stack.pop_back(); } @@ -300,8 +295,7 @@ SampleStack::~SampleStack() } // namespace -ref -makeSampleStackProfiler(const EvalState & state, std::filesystem::path profileFile, uint64_t frequency) +ref makeSampleStackProfiler(EvalState & state, std::filesystem::path profileFile, uint64_t frequency) { /* 0 is a special value for sampling stack after each call. */ std::chrono::nanoseconds period = frequency == 0 diff --git a/src/libexpr/function-trace.cc b/src/libexpr/function-trace.cc index 993dd72d7..cda3bc2db 100644 --- a/src/libexpr/function-trace.cc +++ b/src/libexpr/function-trace.cc @@ -4,7 +4,7 @@ namespace nix { void FunctionCallTrace::preFunctionCallHook( - const EvalState & state, const Value & v, std::span args, const PosIdx pos) + EvalState & state, const Value & v, std::span args, const PosIdx pos) { auto duration = std::chrono::high_resolution_clock::now().time_since_epoch(); auto ns = std::chrono::duration_cast(duration); @@ -12,7 +12,7 @@ void FunctionCallTrace::preFunctionCallHook( } void FunctionCallTrace::postFunctionCallHook( - const EvalState & state, const Value & v, std::span args, const PosIdx pos) + EvalState & state, const Value & v, std::span args, const PosIdx pos) { auto duration = std::chrono::high_resolution_clock::now().time_since_epoch(); auto ns = std::chrono::duration_cast(duration); diff --git a/src/libexpr/include/nix/expr/eval-profiler.hh b/src/libexpr/include/nix/expr/eval-profiler.hh index 9fee4ef35..21629eebc 100644 --- a/src/libexpr/include/nix/expr/eval-profiler.hh +++ b/src/libexpr/include/nix/expr/eval-profiler.hh @@ -62,8 +62,7 @@ public: * @param args Function arguments. * @param pos Function position. */ - virtual void - preFunctionCallHook(const EvalState & state, const Value & v, std::span args, const PosIdx pos); + virtual void preFunctionCallHook(EvalState & state, const Value & v, std::span args, const PosIdx pos); /** * Hook called on EvalState::callFunction exit. @@ -74,8 +73,7 @@ public: * @param args Function arguments. * @param pos Function position. */ - virtual void - postFunctionCallHook(const EvalState & state, const Value & v, std::span args, const PosIdx pos); + virtual void postFunctionCallHook(EvalState & state, const Value & v, std::span args, const PosIdx pos); virtual ~EvalProfiler() = default; @@ -106,12 +104,11 @@ public: void addProfiler(ref profiler); [[gnu::noinline]] void - preFunctionCallHook(const EvalState & state, const Value & v, std::span args, const PosIdx pos) override; + preFunctionCallHook(EvalState & state, const Value & v, std::span args, const PosIdx pos) override; [[gnu::noinline]] void - postFunctionCallHook(const EvalState & state, const Value & v, std::span args, const PosIdx pos) override; + postFunctionCallHook(EvalState & state, const Value & v, std::span args, const PosIdx pos) override; }; -ref -makeSampleStackProfiler(const EvalState & state, std::filesystem::path profileFile, uint64_t frequency); +ref makeSampleStackProfiler(EvalState & state, std::filesystem::path profileFile, uint64_t frequency); } diff --git a/src/libexpr/include/nix/expr/function-trace.hh b/src/libexpr/include/nix/expr/function-trace.hh index 9187cac63..ed1fc6452 100644 --- a/src/libexpr/include/nix/expr/function-trace.hh +++ b/src/libexpr/include/nix/expr/function-trace.hh @@ -17,9 +17,9 @@ public: FunctionCallTrace() = default; [[gnu::noinline]] void - preFunctionCallHook(const EvalState & state, const Value & v, std::span args, const PosIdx pos) override; + preFunctionCallHook(EvalState & state, const Value & v, std::span args, const PosIdx pos) override; [[gnu::noinline]] void - postFunctionCallHook(const EvalState & state, const Value & v, std::span args, const PosIdx pos) override; + postFunctionCallHook(EvalState & state, const Value & v, std::span args, const PosIdx pos) override; }; }