From b9e576f7c13c837f12de547a41af9a015dcf25e8 Mon Sep 17 00:00:00 2001 From: Neloreck Date: Wed, 15 Jan 2025 03:20:21 +0200 Subject: [PATCH] Fix cmake list. Use profiler by value, remove allocation. Do not attach hook by default, use original logics for script engine, add attach methods. Update profiler exports, add profiler type global variables. Add profiler type separation / additional methods for hook/jit based profiling. Separate env vars for different profiling. --- src/xrScriptEngine/CMakeLists.txt | 4 +- src/xrScriptEngine/ScriptEngineScript.cpp | 68 +++++----- src/xrScriptEngine/script_engine.cpp | 12 +- src/xrScriptEngine/script_engine.hpp | 2 +- src/xrScriptEngine/script_profiler.cpp | 158 +++++++++++++++++----- src/xrScriptEngine/script_profiler.hpp | 36 ++++- 6 files changed, 192 insertions(+), 88 deletions(-) diff --git a/src/xrScriptEngine/CMakeLists.txt b/src/xrScriptEngine/CMakeLists.txt index cb6e6121033..5ce29f29e17 100644 --- a/src/xrScriptEngine/CMakeLists.txt +++ b/src/xrScriptEngine/CMakeLists.txt @@ -14,8 +14,8 @@ target_sources_grouped( script_debugger_threads.hpp script_lua_helper.cpp script_lua_helper.hpp - script_profiler.cpp, - script_profiler.hpp, + script_profiler.cpp + script_profiler.hpp ) target_sources_grouped( diff --git a/src/xrScriptEngine/ScriptEngineScript.cpp b/src/xrScriptEngine/ScriptEngineScript.cpp index 2bd3499ab81..5c7bab48833 100644 --- a/src/xrScriptEngine/ScriptEngineScript.cpp +++ b/src/xrScriptEngine/ScriptEngineScript.cpp @@ -66,36 +66,6 @@ bool is_editor() return GEnv.ScriptEngine->is_editor(); } -void isProfilerActive() -{ - GEnv.ScriptEngine->m_profiler->isActive(); -} - -void startProfiler() -{ - GEnv.ScriptEngine->m_profiler->start(); -} - -void stopProfiler() -{ - GEnv.ScriptEngine->m_profiler->stop(); -} - -void resetProfiler() -{ - GEnv.ScriptEngine->m_profiler->reset(); -} - -void saveProfiler() -{ - GEnv.ScriptEngine->m_profiler->save(); -} - -void logProfiler() -{ - GEnv.ScriptEngine->m_profiler->log(); -} - inline int bit_and(const int i, const int j) { return i & j; } inline int bit_or(const int i, const int j) { return i | j; } inline int bit_xor(const int i, const int j) { return i ^ j; } @@ -169,6 +139,10 @@ std::ostream& operator<<(std::ostream& os, const profile_timer_script& pt) { ret SCRIPT_EXPORT(CScriptEngine, (), { using namespace luabind; + + globals(luaState) ["PROFILER_TYPE_HOOK"] = (u32) CScriptProfilerType::Hook; + globals(luaState) ["PROFILER_TYPE_JIT"] = (u32) CScriptProfilerType::Jit; + module(luaState) [ class_("profile_timer") @@ -197,11 +171,33 @@ SCRIPT_EXPORT(CScriptEngine, (), module(luaState, "profiler") [ - def("isActive", &isProfilerActive), - def("start", &startProfiler), - def("stop", &stopProfiler), - def("reset", &resetProfiler), - def("log", &logProfiler), - def("save", &saveProfiler) + def("is_active", +[]() + { + GEnv.ScriptEngine->m_profiler.isActive(); + }), + def("start", +[]() + { + GEnv.ScriptEngine->m_profiler.start(); + }), + def("start", +[](CScriptProfilerType hook_type) + { + GEnv.ScriptEngine->m_profiler.start(hook_type); + }), + def("stop", +[]() + { + GEnv.ScriptEngine->m_profiler.stop(); + }), + def("reset", +[]() + { + GEnv.ScriptEngine->m_profiler.reset(); + }), + def("log_report", +[]() + { + GEnv.ScriptEngine->m_profiler.logReport(); + }), + def("save_report", +[]() + { + GEnv.ScriptEngine->m_profiler.saveReport(); + }) ]; }); diff --git a/src/xrScriptEngine/script_engine.cpp b/src/xrScriptEngine/script_engine.cpp index 1e787d51bf4..2872348766a 100644 --- a/src/xrScriptEngine/script_engine.cpp +++ b/src/xrScriptEngine/script_engine.cpp @@ -748,7 +748,7 @@ void CScriptEngine::disconnect_from_debugger() } #endif -CScriptEngine::CScriptEngine(bool is_editor) +CScriptEngine::CScriptEngine(bool is_editor) : m_profiler(this) { luabind::allocator = &luabind_allocator; luabind::allocator_context = nullptr; @@ -770,7 +770,6 @@ CScriptEngine::CScriptEngine(bool is_editor) #endif #endif m_is_editor = is_editor; - m_profiler = xr_new(); } CScriptEngine::~CScriptEngine() @@ -791,8 +790,6 @@ CScriptEngine::~CScriptEngine() #endif if (scriptBuffer) xr_free(scriptBuffer); - - xr_free(m_profiler); } void CScriptEngine::unload() @@ -888,7 +885,7 @@ void CScriptEngine::lua_hook_call(lua_State* L, lua_Debug* dbg) else scriptEngine->m_stack_is_ready = true; - scriptEngine->m_profiler->onLuaHookCall(L, dbg); + scriptEngine->m_profiler.onLuaHookCall(L, dbg); } #endif @@ -1069,11 +1066,6 @@ void CScriptEngine::init(ExporterFunc exporterFunc, bool loadGlobalNamespace) } m_stack_level = lua_gettop(lua()); - // todo: Hook on activation wich check. - // todo: Hook on activation wich check. - // todo: Hook on activation wich check. - lua_sethook(lua(), CScriptEngine::lua_hook_call, LUA_MASKLINE | LUA_MASKCALL | LUA_MASKRET, 0); - setvbuf(stderr, g_ca_stdout, _IOFBF, sizeof(g_ca_stdout)); } diff --git a/src/xrScriptEngine/script_engine.hpp b/src/xrScriptEngine/script_engine.hpp index f91a61a7b5e..8344428594a 100644 --- a/src/xrScriptEngine/script_engine.hpp +++ b/src/xrScriptEngine/script_engine.hpp @@ -154,7 +154,7 @@ class XRSCRIPTENGINE_API CScriptEngine } public: - CScriptProfiler* m_profiler; + CScriptProfiler m_profiler; lua_State* lua() { return m_virtual_machine; } void current_thread(CScriptThread* thread) diff --git a/src/xrScriptEngine/script_profiler.cpp b/src/xrScriptEngine/script_profiler.cpp index 5a5258ac57a..bae820ff27f 100644 --- a/src/xrScriptEngine/script_profiler.cpp +++ b/src/xrScriptEngine/script_profiler.cpp @@ -1,26 +1,34 @@ #include "pch.hpp" #include "script_profiler.hpp" +#include "xrScriptEngine/script_engine.hpp" -CScriptProfiler::CScriptProfiler() +CScriptProfiler::CScriptProfiler(CScriptEngine* engine) { + R_ASSERT(engine != NULL); + + m_engine = engine; + m_active = false; m_profile_level = 1; + m_profiler_type = CScriptProfilerType::None; - // todo: Configuration of profile levels. - // todo: Configuration of profile levels. - // todo: Configuration of profile levels. + // todo: Configuration of profile levels for hook profiler. + // todo: Configuration of profile levels for hook profiler. + // todo: Configuration of profile levels for hook profiler. if (strstr(Core.Params, "-lua_profiler")) - { start(); - } + else if (strstr(Core.Params, "-lua_hook_profiler")) + start(CScriptProfilerType::Hook); + else if (strstr(Core.Params, "-lua_jit_profiler")) + start(CScriptProfilerType::Jit); } CScriptProfiler::~CScriptProfiler() { } -void CScriptProfiler::start() +void CScriptProfiler::start(CScriptProfilerType profiler_type) { if (m_active) { @@ -28,58 +36,107 @@ void CScriptProfiler::start() return; } - Msg("Starting lua scripts profiler"); - - m_active = true; - - // todo: Reset? - // todo: Reset? - // todo: Reset? + if (profiler_type == CScriptProfilerType::None) + { + Msg("Tried to start none profiler type"); + return; + } // todo: Check JIT and warn? Allow turn it off with parameter? // todo: Check JIT and warn? Allow turn it off with parameter? // todo: Check JIT and warn? Allow turn it off with parameter? - // todo: Attach hook? - // todo: Attach hook? - // todo: Attach hook? + m_profiling_portions.clear(); + m_active = true; + m_profiler_type = profiler_type; + + switch (profiler_type) + { + case CScriptProfilerType::Hook: + Msg("Starting lua scripts hook profiler"); + + attachLuaHook(); + + return; + case CScriptProfilerType::Jit: + { + Msg("Starting lua scripts jit profiler"); + + return; + } + + default: NODEFAULT; + } } void CScriptProfiler::stop() { if (!m_active) { - Msg("Tried to stop inactive profiler, operation ignored"); + Msg("Tried to stop inactive profiler"); + return; + } + + if (m_profiler_type == CScriptProfilerType::None) + { + Msg("Tried to stop none profiler type"); return; } - Msg("Stopping lua scripts profiler"); + switch (m_profiler_type) + { + case CScriptProfilerType::Hook: + Msg("Stopping lua scripts hook profiler"); + + // Do not detach hook here, adding it means that it is already test run in the first place. + + break; + case CScriptProfilerType::Jit: + { + Msg("Stopping lua scripts jit profiler"); + + break; + } - // todo: Reset? - // todo: Reset? - // todo: Reset? + default: NODEFAULT; + } - // todo: Detach hook? - // todo: Detach hook? - // todo: Detach hook? + m_active = false; } void CScriptProfiler::reset() { Msg("Reset profiler"); - // todo; - // todo; - // todo; + m_profiling_portions.clear(); +} + +void CScriptProfiler::logReport() +{ + switch (m_profiler_type) + { + case CScriptProfilerType::Hook: + return logHookReport(); + case CScriptProfilerType::Jit: + return logJitReport(); + default: + Msg("Nothing to report for profiler"); + return; + } } -void CScriptProfiler::log() +void CScriptProfiler::logHookReport() { + if (m_profiling_portions.empty()) + { + Msg("Nothing to report for hook profiler, data is missing"); + return; + } u64 total_count = 0; u64 total_duration = 0; - std::vector entries; + xr_vector entries; entries.reserve(m_profiling_portions.size()); for (auto it = m_profiling_portions.begin(); it != m_profiling_portions.end(); it++) @@ -90,9 +147,8 @@ void CScriptProfiler::log() total_duration += it->second.duration(); } - Msg("=================================================================="); - Msg("= Log profiler report, %d entries", entries.size()); + Msg("= Log hook profiler report, %d entries", entries.size()); Msg("=================================================================="); Msg("= By calls duration:"); Msg("===="); @@ -148,7 +204,14 @@ void CScriptProfiler::log() // todo; } -void CScriptProfiler::save() +void CScriptProfiler::logJitReport() +{ + // todo; + // todo; + // todo; +} + +void CScriptProfiler::saveReport() { Log("Save profiler report"); @@ -157,6 +220,25 @@ void CScriptProfiler::save() // todo; } +void CScriptProfiler::attachLuaHook() +{ + lua_State* L = lua(); + lua_Hook hook = lua_gethook(L); + + if (hook) + { + if (hook != CScriptEngine::lua_hook_call) + { + Msg("Warning: hook already defined by something else, cannot take ownership as CScriptEngine"); + } + } + else + { + Msg("Attaching lua scripts hook"); + lua_sethook(L, CScriptEngine::lua_hook_call, LUA_MASKLINE | LUA_MASKCALL | LUA_MASKRET, 0); + } +} + void CScriptProfiler::onLuaHookCall(lua_State* L, lua_Debug* dbg) { if (!m_active || dbg->event == LUA_HOOKLINE) @@ -243,6 +325,16 @@ void CScriptProfiler::onLuaHookCall(lua_State* L, lua_Debug* dbg) } } +lua_State* CScriptProfiler::lua() const +{ + return this->m_engine->lua(); +} + +bool CScriptProfiler::luaIsJitProfilerDefined(lua_State* L) +{ + return true; +} + // todo: Add util to get frame info // todo: Add util to get frame info // todo: Add util to get frame info diff --git a/src/xrScriptEngine/script_profiler.hpp b/src/xrScriptEngine/script_profiler.hpp index 368cb070658..29a17cd224c 100644 --- a/src/xrScriptEngine/script_profiler.hpp +++ b/src/xrScriptEngine/script_profiler.hpp @@ -62,28 +62,52 @@ class CScriptProfilerPortion { } }; +enum class CScriptProfilerType : u32 +{ + None = 0, + Hook = 1, + Jit = 2, +}; + class XRSCRIPTENGINE_API CScriptProfiler { + using Clock = std::chrono::high_resolution_clock; + using Time = Clock::time_point; + using Duration = Clock::duration; + private: static const u32 PROFILE_ENTRIES_LOG_LIMIT = 128; - + + CScriptEngine* m_engine; + + bool m_active; + // Profiling level - number of stacks to check before each function call. // Helps validating results of same functions called from different places vs totals by specific function. u8 m_profile_level; - bool m_active; + CScriptProfilerType m_profiler_type; xr_unordered_map m_profiling_portions; public: - CScriptProfiler(); + CScriptProfiler(CScriptEngine* engine); virtual ~CScriptProfiler(); bool isActive() const { return m_active; }; - void start(); + void start(CScriptProfilerType profiler_type = CScriptProfilerType::Hook); void stop(); void reset(); - void log(); - void save(); + void logReport(); + void logHookReport(); + void logJitReport(); + void saveReport(); + + void attachLuaHook(); void onLuaHookCall(lua_State* L, lua_Debug* dbg); + +private: + lua_State* lua() const; + + static bool luaIsJitProfilerDefined(lua_State* L); };