Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[LUA] Adding C++ profiler for lua scripts. #1771

Open
wants to merge 24 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
181e483
Base implementation of profiler to improve / work on.
Neloreck Jan 14, 2025
2cb3928
Remove not needed spaces.
Neloreck Jan 14, 2025
8a2c7ac
Fix cmake list. Use profiler by value, remove allocation. Do not atta…
Neloreck Jan 15, 2025
f6acd96
Add placeholder profiler.script.
Neloreck Jan 15, 2025
5c96778
Implemented core for sampling profiler with luajit built-in methods.
Neloreck Jan 16, 2025
f1ebac8
Do not initialize profiler in editor mode. Use profiling type specifi…
Neloreck Jan 16, 2025
6c24633
Const expressions for args. Use interval param in sampling profiler.
Neloreck Jan 17, 2025
40e96c1
Separate hook start methods, simple generic start with defaults. Decl…
Neloreck Jan 17, 2025
6f8e6d4
Safer checking for luaIsJitProfilerDefined.
Neloreck Jan 17, 2025
3216e9f
Respect -nojit option on startup with profiling active. Corrected sto…
Neloreck Jan 17, 2025
4ba2681
Separate portions file. Collect portions instead of full stack for sa…
Neloreck Jan 17, 2025
e750582
Add comment with tracy exports.
Neloreck Jan 17, 2025
92203aa
Missing end line added.
Neloreck Jan 17, 2025
b8b348e
Corrected hook profiler to make more sense. Add `luaDebugStackInfo`.
Neloreck Jan 18, 2025
7831405
Adjust report generation format/building.
Neloreck Jan 18, 2025
b7200ae
Add lua profiler console commands.
Neloreck Jan 18, 2025
3011943
Post-review fixes. Code comments. Adjusted profiling methods to simpl…
Neloreck Jan 18, 2025
3510632
Reset type on profiler stop. Respect cases with 0 total duration. Use…
Neloreck Jan 18, 2025
d115c61
Export `PROFILER_TYPE_NONE`. Export `get_type`. Do not reset data on …
Neloreck Jan 18, 2025
5fec597
Adjusted exported functions to use separate overloads for start.
Neloreck Jan 19, 2025
af68a66
Spacing removed from switch-cases.
Neloreck Jan 19, 2025
ee95305
Corrected wrong parameter name in profiler export.
Neloreck Jan 19, 2025
5b40a7a
Exported variant of `log_report` without parameters.
Neloreck Jan 19, 2025
f0ee679
Export `start_sampling_mode` as variant with and without interval par…
Neloreck Jan 19, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions res/gamedata/scripts/profiler.script
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
-- Original profiler was not working and caused game to crash when jit parameter is disabled.
-- For safety reasons there is mock setup function and empty module without original code.
--
-- 1) LUA does not allow setting up multiple hooks, adding hooks here instead of C++ codebase is problematic
-- 2) Luabind/Luajit already injects complex logics, C++ codebase adds error callbacks and custom logics.
-- As result, stack and state may be corrupted and cause random logics/memory errors.
--
-- See: https://github.com/OpenXRay/xray-16/issues/1436

-- Mock placeholder.
function setup_hook() end
2 changes: 1 addition & 1 deletion src/xrGame/ai_space.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ void CAI_Space::init()
m_moving_objects = xr_make_unique<::moving_objects>();

VERIFY(!GEnv.ScriptEngine);
GEnv.ScriptEngine = xr_new<CScriptEngine>();
GEnv.ScriptEngine = xr_new<CScriptEngine>(false, true);
RestartScriptEngine();
}

Expand Down
138 changes: 138 additions & 0 deletions src/xrGame/console_commands.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1992,6 +1992,135 @@ class CCC_UI_Time_Factor : public IConsole_Command
}
};

class CCC_LuaProfiler : public IConsole_Command
{
public:
constexpr static cpcstr COMMAND_LUA_PROFILER_STATUS = "lua_profiler_status";
constexpr static cpcstr COMMAND_LUA_PROFILER_START = "lua_profiler_start";
constexpr static cpcstr COMMAND_LUA_PROFILER_START_HOOK_MODE = "lua_profiler_start_hook_mode";
constexpr static cpcstr COMMAND_LUA_PROFILER_START_SAMPLING_MODE = "lua_profiler_start_sampling_mode";
constexpr static cpcstr COMMAND_LUA_PROFILER_STOP = "lua_profiler_stop";
constexpr static cpcstr COMMAND_LUA_PROFILER_RESET = "lua_profiler_reset";
constexpr static cpcstr COMMAND_LUA_PROFILER_LOG = "lua_profiler_log";
constexpr static cpcstr COMMAND_LUA_PROFILER_SAVE = "lua_profiler_save";

CCC_LuaProfiler(LPCSTR N) : IConsole_Command(N) { bEmptyArgsHandled = true; };
virtual void Execute(LPCSTR args)
{
CScriptProfiler* profiler = GEnv.ScriptEngine->m_profiler;

if (strstr(cName, COMMAND_LUA_PROFILER_STATUS) == cName)
{
Msg("[P] Profiler status: %s, type - %s", profiler->isActive() ? "on" : "off",
profiler->getTypeString().c_str());
}
else if (strstr(cName, COMMAND_LUA_PROFILER_START_HOOK_MODE) == cName)
{
profiler->startHookMode();
}
else if (strstr(cName, COMMAND_LUA_PROFILER_START_SAMPLING_MODE) == cName)
{
u32 interval = atoi(args);

profiler->startSamplingMode(interval ? interval : CScriptProfiler::PROFILE_SAMPLING_INTERVAL_DEFAULT);
}
else if (strstr(cName, COMMAND_LUA_PROFILER_START) == cName)
{
u32 profiler_type = atoi(args);

profiler->start(
(profiler_type ? (CScriptProfilerType)profiler_type : CScriptProfiler::PROFILE_TYPE_DEFAULT));
}
else if (strstr(cName, COMMAND_LUA_PROFILER_STOP) == cName)
{
profiler->stop();
}
else if (strstr(cName, COMMAND_LUA_PROFILER_RESET) == cName)
{
profiler->reset();
}
else if (strstr(cName, COMMAND_LUA_PROFILER_LOG) == cName)
{
u32 limit = atoi(args);

profiler->logReport(limit ? limit : CScriptProfiler::PROFILE_ENTRIES_LOG_LIMIT_DEFAULT);
}
else if (strstr(cName, COMMAND_LUA_PROFILER_SAVE) == cName)
{
profiler->saveReport();
}
};

void fill_tips(vecTips& tips, u32 /*mode*/) override
{
CScriptProfiler* profiler = GEnv.ScriptEngine->m_profiler;
TStatus status_buffer;

if (strstr(cName, COMMAND_LUA_PROFILER_STATUS) == cName)
{
// No arguments.
}
else if (strstr(cName, COMMAND_LUA_PROFILER_START_HOOK_MODE) == cName)
{
// No arguments.
}
else if (strstr(cName, COMMAND_LUA_PROFILER_START_SAMPLING_MODE) == cName)
{
xr_sprintf(status_buffer, "%d (default) [1-%d] - sampling interval",
CScriptProfiler::PROFILE_SAMPLING_INTERVAL_DEFAULT, CScriptProfiler::PROFILE_SAMPLING_INTERVAL_MAX);
tips.push_back(status_buffer);
}
else if (strstr(cName, COMMAND_LUA_PROFILER_START) == cName)
{
xr_sprintf(status_buffer, "%d - hooks based profiler", CScriptProfilerType::Hook);
tips.push_back(status_buffer);

xr_sprintf(status_buffer, "%d - sampling based profiler", CScriptProfilerType::Sampling);
tips.push_back(status_buffer);
}
else if (strstr(cName, COMMAND_LUA_PROFILER_STOP) == cName)
{
// No arguments.
}
else if (strstr(cName, COMMAND_LUA_PROFILER_RESET) == cName)
{
// No arguments.
}
else if (strstr(cName, COMMAND_LUA_PROFILER_LOG) == cName)
{
xr_sprintf(status_buffer, "%d (default) - count of profiling entries to print",
CScriptProfiler::PROFILE_ENTRIES_LOG_LIMIT_DEFAULT, CScriptProfiler::PROFILE_SAMPLING_INTERVAL_MAX);
tips.push_back(status_buffer);
}
else if (strstr(cName, COMMAND_LUA_PROFILER_SAVE) == cName)
{
// No arguments.
}
}

void Info(TInfo& I) override
{
if (strstr(cName, COMMAND_LUA_PROFILER_STATUS) == cName)
xr_strcpy(I, "no arguments : print lua profiler status");
else if (strstr(cName, COMMAND_LUA_PROFILER_START_HOOK_MODE) == cName)
xr_strcpy(I, "no arguments : start lua script profiling in hook mode");
else if (strstr(cName, COMMAND_LUA_PROFILER_START_SAMPLING_MODE) == cName)
xr_strcpy(I,
"integer value in range [1,1000] : start lua script profiling in sampling mode with provided sampling "
"interval");
else if (strstr(cName, COMMAND_LUA_PROFILER_START) == cName)
xr_strcpy(I, "integer value in range [0,2] : start lua script profiling in provided mode");
else if (strstr(cName, COMMAND_LUA_PROFILER_STOP) == cName)
xr_strcpy(I, "no arguments : stop lua script profiling");
else if (strstr(cName, COMMAND_LUA_PROFILER_RESET) == cName)
xr_strcpy(I, "no arguments : reset lua script profiling stats");
else if (strstr(cName, COMMAND_LUA_PROFILER_LOG) == cName)
xr_strcpy(I, "integer value : log lua script profiling stats, limit entries with argument");
else if (strstr(cName, COMMAND_LUA_PROFILER_SAVE) == cName)
xr_strcpy(I, "no arguments : save lua script profiling stats in a file");
}
};

void CCC_RegisterCommands()
{
ZoneScoped;
Expand Down Expand Up @@ -2076,6 +2205,15 @@ void CCC_RegisterCommands()
CMD3(CCC_Mask, "lua_debug", &g_LuaDebug, 1);
#endif // MASTER_GOLD

CMD1(CCC_LuaProfiler, CCC_LuaProfiler::COMMAND_LUA_PROFILER_STATUS);
CMD1(CCC_LuaProfiler, CCC_LuaProfiler::COMMAND_LUA_PROFILER_START);
CMD1(CCC_LuaProfiler, CCC_LuaProfiler::COMMAND_LUA_PROFILER_START_SAMPLING_MODE);
CMD1(CCC_LuaProfiler, CCC_LuaProfiler::COMMAND_LUA_PROFILER_START_HOOK_MODE);
CMD1(CCC_LuaProfiler, CCC_LuaProfiler::COMMAND_LUA_PROFILER_STOP);
CMD1(CCC_LuaProfiler, CCC_LuaProfiler::COMMAND_LUA_PROFILER_RESET);
CMD1(CCC_LuaProfiler, CCC_LuaProfiler::COMMAND_LUA_PROFILER_LOG);
CMD1(CCC_LuaProfiler, CCC_LuaProfiler::COMMAND_LUA_PROFILER_SAVE);

#ifdef DEBUG
CMD4(CCC_Integer, "lua_gcstep", &psLUA_GCSTEP, 1, 1000);
CMD3(CCC_Mask, "ai_debug", &psAI_Flags, aiDebug);
Expand Down
3 changes: 3 additions & 0 deletions src/xrScriptEngine/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ target_sources_grouped(
script_debugger_threads.hpp
script_lua_helper.cpp
script_lua_helper.hpp
script_profiler.cpp
script_profiler.hpp
script_profiler_portions.hpp
)

target_sources_grouped(
Expand Down
85 changes: 80 additions & 5 deletions src/xrScriptEngine/ScriptEngineScript.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
////////////////////////////////////////////////////////////////////////////
// Module : script_engine_script.cpp
// Created : 25.12.2002
// Modified : 13.05.2004
// Author : Dmitriy Iassenev
// Description : ALife Simulator script engine export
// Module : script_engine_script.cpp
// Created : 25.12.2002
// Modified : 13.05.2004
// Author : Dmitriy Iassenev
// Description : ALife Simulator script engine export
////////////////////////////////////////////////////////////////////////////

#include "pch.hpp"
Expand Down Expand Up @@ -139,6 +139,11 @@ std::ostream& operator<<(std::ostream& os, const profile_timer_script& pt) { ret
SCRIPT_EXPORT(CScriptEngine, (),
{
using namespace luabind;

globals(luaState) ["PROFILER_TYPE_NONE"] = (u32) CScriptProfilerType::None;
globals(luaState) ["PROFILER_TYPE_HOOK"] = (u32) CScriptProfilerType::Hook;
globals(luaState) ["PROFILER_TYPE_SAMPLING"] = (u32) CScriptProfilerType::Sampling;

module(luaState)
[
class_<profile_timer_script>("profile_timer")
Expand All @@ -164,4 +169,74 @@ SCRIPT_EXPORT(CScriptEngine, (),
def("editor", &is_editor),
def("user_name", &user_name)
];

module(luaState, "profiler")
[
def("is_active", +[]() -> bool
{
return GEnv.ScriptEngine->m_profiler->isActive();
}),
def("get_type", +[]()-> u32
{
return static_cast<u32>(GEnv.ScriptEngine->m_profiler->getType());
}),
def("start", +[]()
{
GEnv.ScriptEngine->m_profiler->start();
}),
def("start", +[](CScriptProfilerType profiler_type)
{
GEnv.ScriptEngine->m_profiler->start(profiler_type);
}),
def("start_hook_mode", +[]()
{
GEnv.ScriptEngine->m_profiler->startHookMode();
}),
def("start_sampling_mode", +[]()
{
GEnv.ScriptEngine->m_profiler->startSamplingMode();
}),
def("start_sampling_mode", +[](u32 sampling_interval = CScriptProfiler::PROFILE_SAMPLING_INTERVAL_DEFAULT)
{
GEnv.ScriptEngine->m_profiler->startSamplingMode(sampling_interval);
}),
def("stop", +[]()
{
GEnv.ScriptEngine->m_profiler->stop();
}),
def("reset", +[]()
{
GEnv.ScriptEngine->m_profiler->reset();
}),
def("log_report", +[]()
{
GEnv.ScriptEngine->m_profiler->logReport();
}),
def("log_report", +[](u32 entries_limit)
{
GEnv.ScriptEngine->m_profiler->logReport(entries_limit);
}),
def("save_report", +[]()
{
GEnv.ScriptEngine->m_profiler->saveReport();
})
];

/**
* Exports injected from tracy profiler:
*
* https://github.com/wolfpld/tracy/blob/da60684b9f61b34afa5aa243a7838d6e79096783/manual/tracy.tex#L1932
* https://github.com/wolfpld/tracy/blob/da60684b9f61b34afa5aa243a7838d6e79096783/public/tracy/TracyLua.hpp#L18
*
* global tracy {
* function ZoneBegin;
* function ZoneBeginN;
* function ZoneBeginS;
* function ZoneBeginNS;
* function ZoneEnd;
* function ZoneText;
* function ZoneName;
* function Message;
* }
*/
});
6 changes: 3 additions & 3 deletions src/xrScriptEngine/script_debugger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,9 @@ BOOL CScriptDebugger::Active() { return m_bIdePresent; }
CScriptDebugger::CScriptDebugger(CScriptEngine* scriptEngine)
{
this->scriptEngine = scriptEngine;
m_threads = new CDbgScriptThreads(scriptEngine, this);
m_callStack = new CScriptCallStack(this);
m_lua = new CDbgLuaHelper(this);
m_threads = xr_new<CDbgScriptThreads>(scriptEngine, this);
m_callStack = xr_new<CScriptCallStack>(this);
m_lua = xr_new<CDbgLuaHelper>(this);
ZeroMemory(m_curr_connected_mslot, sizeof(m_curr_connected_mslot));
// m_pDebugger = this;
m_nLevel = 0;
Expand Down
Loading
Loading