1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2025-06-27 12:41:15 +02:00

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.
This commit is contained in:
Sergei Zimmerman 2025-05-25 14:58:31 +00:00
parent 543cee1c92
commit 128750225d
No known key found for this signature in database
GPG key ID: A9B0B557CA632325
4 changed files with 20 additions and 29 deletions

View file

@ -5,18 +5,14 @@
namespace nix { namespace nix {
void EvalProfiler::preFunctionCallHook( void EvalProfiler::preFunctionCallHook(EvalState & state, const Value & v, std::span<Value *> args, const PosIdx pos) {}
const EvalState & state, const Value & v, std::span<Value *> args, const PosIdx pos)
{
}
void EvalProfiler::postFunctionCallHook( void EvalProfiler::postFunctionCallHook(EvalState & state, const Value & v, std::span<Value *> args, const PosIdx pos)
const EvalState & state, const Value & v, std::span<Value *> args, const PosIdx pos)
{ {
} }
void MultiEvalProfiler::preFunctionCallHook( void MultiEvalProfiler::preFunctionCallHook(
const EvalState & state, const Value & v, std::span<Value *> args, const PosIdx pos) EvalState & state, const Value & v, std::span<Value *> args, const PosIdx pos)
{ {
for (auto & profiler : profilers) { for (auto & profiler : profilers) {
if (profiler->getNeededHooks().test(Hook::preFunctionCall)) if (profiler->getNeededHooks().test(Hook::preFunctionCall))
@ -25,7 +21,7 @@ void MultiEvalProfiler::preFunctionCallHook(
} }
void MultiEvalProfiler::postFunctionCallHook( void MultiEvalProfiler::postFunctionCallHook(
const EvalState & state, const Value & v, std::span<Value *> args, const PosIdx pos) EvalState & state, const Value & v, std::span<Value *> args, const PosIdx pos)
{ {
for (auto & profiler : profilers) { for (auto & profiler : profilers) {
if (profiler->getNeededHooks().test(Hook::postFunctionCall)) if (profiler->getNeededHooks().test(Hook::postFunctionCall))
@ -126,7 +122,7 @@ class SampleStack : public EvalProfiler
} }
public: 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) : state(state)
, sampleInterval(period) , sampleInterval(period)
, profileFd([&]() { , profileFd([&]() {
@ -140,9 +136,9 @@ public:
} }
[[gnu::noinline]] void [[gnu::noinline]] void
preFunctionCallHook(const EvalState & state, const Value & v, std::span<Value *> args, const PosIdx pos) override; preFunctionCallHook(EvalState & state, const Value & v, std::span<Value *> args, const PosIdx pos) override;
[[gnu::noinline]] void [[gnu::noinline]] void
postFunctionCallHook(const EvalState & state, const Value & v, std::span<Value *> args, const PosIdx pos) override; postFunctionCallHook(EvalState & state, const Value & v, std::span<Value *> args, const PosIdx pos) override;
void maybeSaveProfile(std::chrono::time_point<std::chrono::high_resolution_clock> now); void maybeSaveProfile(std::chrono::time_point<std::chrono::high_resolution_clock> now);
void saveProfile(); void saveProfile();
@ -156,7 +152,7 @@ public:
private: private:
/** Hold on to an instance of EvalState for symbolizing positions. */ /** Hold on to an instance of EvalState for symbolizing positions. */
const EvalState & state; EvalState & state;
std::chrono::nanoseconds sampleInterval; std::chrono::nanoseconds sampleInterval;
AutoCloseFD profileFd; AutoCloseFD profileFd;
FrameStack stack; FrameStack stack;
@ -191,7 +187,7 @@ FrameInfo SampleStack::getFrameInfoFromValueAndPos(const Value & v, PosIdx pos)
} }
[[gnu::noinline]] void SampleStack::preFunctionCallHook( [[gnu::noinline]] void SampleStack::preFunctionCallHook(
const EvalState & state, const Value & v, [[maybe_unused]] std::span<Value *> args, const PosIdx pos) EvalState & state, const Value & v, [[maybe_unused]] std::span<Value *> args, const PosIdx pos)
{ {
stack.push_back(getFrameInfoFromValueAndPos(v, pos)); stack.push_back(getFrameInfoFromValueAndPos(v, pos));
@ -208,9 +204,8 @@ FrameInfo SampleStack::getFrameInfoFromValueAndPos(const Value & v, PosIdx pos)
} }
[[gnu::noinline]] void [[gnu::noinline]] void
SampleStack::postFunctionCallHook(const EvalState & state, const Value & v, std::span<Value *> args, const PosIdx pos) SampleStack::postFunctionCallHook(EvalState & state, const Value & v, std::span<Value *> args, const PosIdx pos)
{ {
if (!stack.empty()) if (!stack.empty())
stack.pop_back(); stack.pop_back();
} }
@ -300,8 +295,7 @@ SampleStack::~SampleStack()
} // namespace } // namespace
ref<EvalProfiler> ref<EvalProfiler> makeSampleStackProfiler(EvalState & state, std::filesystem::path profileFile, uint64_t frequency)
makeSampleStackProfiler(const EvalState & state, std::filesystem::path profileFile, uint64_t frequency)
{ {
/* 0 is a special value for sampling stack after each call. */ /* 0 is a special value for sampling stack after each call. */
std::chrono::nanoseconds period = frequency == 0 std::chrono::nanoseconds period = frequency == 0

View file

@ -4,7 +4,7 @@
namespace nix { namespace nix {
void FunctionCallTrace::preFunctionCallHook( void FunctionCallTrace::preFunctionCallHook(
const EvalState & state, const Value & v, std::span<Value *> args, const PosIdx pos) EvalState & state, const Value & v, std::span<Value *> args, const PosIdx pos)
{ {
auto duration = std::chrono::high_resolution_clock::now().time_since_epoch(); auto duration = std::chrono::high_resolution_clock::now().time_since_epoch();
auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(duration); auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(duration);
@ -12,7 +12,7 @@ void FunctionCallTrace::preFunctionCallHook(
} }
void FunctionCallTrace::postFunctionCallHook( void FunctionCallTrace::postFunctionCallHook(
const EvalState & state, const Value & v, std::span<Value *> args, const PosIdx pos) EvalState & state, const Value & v, std::span<Value *> args, const PosIdx pos)
{ {
auto duration = std::chrono::high_resolution_clock::now().time_since_epoch(); auto duration = std::chrono::high_resolution_clock::now().time_since_epoch();
auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(duration); auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(duration);

View file

@ -62,8 +62,7 @@ public:
* @param args Function arguments. * @param args Function arguments.
* @param pos Function position. * @param pos Function position.
*/ */
virtual void virtual void preFunctionCallHook(EvalState & state, const Value & v, std::span<Value *> args, const PosIdx pos);
preFunctionCallHook(const EvalState & state, const Value & v, std::span<Value *> args, const PosIdx pos);
/** /**
* Hook called on EvalState::callFunction exit. * Hook called on EvalState::callFunction exit.
@ -74,8 +73,7 @@ public:
* @param args Function arguments. * @param args Function arguments.
* @param pos Function position. * @param pos Function position.
*/ */
virtual void virtual void postFunctionCallHook(EvalState & state, const Value & v, std::span<Value *> args, const PosIdx pos);
postFunctionCallHook(const EvalState & state, const Value & v, std::span<Value *> args, const PosIdx pos);
virtual ~EvalProfiler() = default; virtual ~EvalProfiler() = default;
@ -106,12 +104,11 @@ public:
void addProfiler(ref<EvalProfiler> profiler); void addProfiler(ref<EvalProfiler> profiler);
[[gnu::noinline]] void [[gnu::noinline]] void
preFunctionCallHook(const EvalState & state, const Value & v, std::span<Value *> args, const PosIdx pos) override; preFunctionCallHook(EvalState & state, const Value & v, std::span<Value *> args, const PosIdx pos) override;
[[gnu::noinline]] void [[gnu::noinline]] void
postFunctionCallHook(const EvalState & state, const Value & v, std::span<Value *> args, const PosIdx pos) override; postFunctionCallHook(EvalState & state, const Value & v, std::span<Value *> args, const PosIdx pos) override;
}; };
ref<EvalProfiler> ref<EvalProfiler> makeSampleStackProfiler(EvalState & state, std::filesystem::path profileFile, uint64_t frequency);
makeSampleStackProfiler(const EvalState & state, std::filesystem::path profileFile, uint64_t frequency);
} }

View file

@ -17,9 +17,9 @@ public:
FunctionCallTrace() = default; FunctionCallTrace() = default;
[[gnu::noinline]] void [[gnu::noinline]] void
preFunctionCallHook(const EvalState & state, const Value & v, std::span<Value *> args, const PosIdx pos) override; preFunctionCallHook(EvalState & state, const Value & v, std::span<Value *> args, const PosIdx pos) override;
[[gnu::noinline]] void [[gnu::noinline]] void
postFunctionCallHook(const EvalState & state, const Value & v, std::span<Value *> args, const PosIdx pos) override; postFunctionCallHook(EvalState & state, const Value & v, std::span<Value *> args, const PosIdx pos) override;
}; };
} }