diff --git a/rts/Lua/CMakeLists.txt b/rts/Lua/CMakeLists.txt index 5e6eb62be5..8f8a9e4008 100644 --- a/rts/Lua/CMakeLists.txt +++ b/rts/Lua/CMakeLists.txt @@ -43,6 +43,7 @@ set(sources_engine_Lua "${CMAKE_CURRENT_SOURCE_DIR}/LuaSyncedTable.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/LuaTableExtra.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/LuaTextures.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/LuaTracyExtra.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/LuaAtlasTextures.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/LuaUI.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/LuaUICommand.cpp" diff --git a/rts/Lua/LuaHandle.cpp b/rts/Lua/LuaHandle.cpp index 1925f142d0..d3ba5f3ef8 100644 --- a/rts/Lua/LuaHandle.cpp +++ b/rts/Lua/LuaHandle.cpp @@ -13,6 +13,7 @@ #include "LuaBitOps.h" #include "LuaMathExtra.h" #include "LuaTableExtra.h" +#include "LuaTracyExtra.h" #include "LuaUtils.h" #include "LuaZip.h" #include "Game/Game.h" @@ -149,6 +150,11 @@ CLuaHandle::CLuaHandle(const string& _name, int _order, bool _userMode, bool _sy // register tracy functions in global scope tracy::LuaRegister(L); + #ifdef TRACY_ENABLE + lua_getglobal(L, "tracy"); + LuaTracyExtra::PushEntries(L); + lua_pop(L, 1); + #endif } @@ -498,7 +504,7 @@ bool CLuaHandle::LoadCode(lua_State* L, std::string code, const string& debug) const LuaUtils::ScopedDebugTraceBack traceBack(L); - tracy::LuaRemove(code.data()); + LuaUtils::TracyRemoveAlsoExtras(code.data()); const int error = luaL_loadbuffer(L, code.c_str(), code.size(), debug.c_str()); if (error != 0) { diff --git a/rts/Lua/LuaParser.cpp b/rts/Lua/LuaParser.cpp index 1db0f0178c..101f1dce3d 100644 --- a/rts/Lua/LuaParser.cpp +++ b/rts/Lua/LuaParser.cpp @@ -236,7 +236,7 @@ bool LuaParser::Execute() char errorBuf[4096] = {0}; int errorNum = 0; - tracy::LuaRemove(code.data()); + LuaUtils::TracyRemoveAlsoExtras(code.data()); if ((errorNum = luaL_loadbuffer(L, code.c_str(), code.size(), codeLabel.c_str())) != 0) { SNPRINTF(errorBuf, sizeof(errorBuf), "[loadbuf] error %d (\"%s\") in %s", errorNum, lua_tostring(L, -1), codeLabel.c_str()); LUA_CLOSE(&L); @@ -643,7 +643,7 @@ int LuaParser::Include(lua_State* L) lua_error(L); } - tracy::LuaRemove(code.data()); + LuaUtils::TracyRemoveAlsoExtras(code.data()); int error = luaL_loadbuffer(L, code.c_str(), code.size(), filename.c_str()); if (error != 0) { char buf[1024]; diff --git a/rts/Lua/LuaTracyExtra.cpp b/rts/Lua/LuaTracyExtra.cpp new file mode 100644 index 0000000000..d824a824c1 --- /dev/null +++ b/rts/Lua/LuaTracyExtra.cpp @@ -0,0 +1,90 @@ +/* This file is part of the Recoil engine (GPL v2 or later). */ + +#include "LuaTracyExtra.h" + +#include "LuaInclude.h" +#include "LuaUtils.h" + +#include "System/Misc/TracyDefs.h" +#include + +#include +#include +#include + +/* Tracy seems to want unique, unchanging strings to be passed to + * its API, so we need to immanentize the ephemeral Lua strings + * by storing them. + * + * NB: strings here are never really cleaned up, but the use case assumes + * that they live a long time and there's just a handful of them. */ +static std::set > tracyLuaPlots; + +static const std::string& GetImmanentPlotName(const char *plotName) +{ + const auto plot = tracyLuaPlots.find(plotName); + if (plot != tracyLuaPlots.end()) + return *plot; + + return *tracyLuaPlots.emplace(plotName).first; +} + +/*** Configure custom appearance for a Tracy plot for use in debugging or profiling + * + * @function tracy.LuaTracyPlotConfig + * @string plotName name of the plot to customize + * @string[opt="Number"] plotFormatType "Number"|"Percentage"|"Memory" + * @bool[opt=true] stepwise stepwise chart + * @bool[opt=false] fill whether to fill color + * @number[opt=white] color unit32 number as BGR color + * @treturn nil + */ + +static int LuaTracyPlotConfig(lua_State* L) +{ + const auto plotName = luaL_checkstring(L, 1); + const auto plotFormatTypeString = luaL_optstring(L, 2, ""); + const auto stepwise = luaL_optboolean(L, 3, true); + const auto fill = luaL_optboolean(L, 4, false); + const uint32_t color = luaL_optint(L, 5, 0xFFFFFF); // white + + tracy::PlotFormatType plotFormatType; + switch (plotFormatTypeString[0]) { + case 'p': case 'P': plotFormatType = tracy::PlotFormatType::Percentage; break; + case 'm': case 'M': plotFormatType = tracy::PlotFormatType::Memory; break; + default: plotFormatType = tracy::PlotFormatType::Number; break; + } + + TracyPlotConfig(GetImmanentPlotName(plotName).c_str(), plotFormatType, stepwise, fill, color); + return 0; +} + + +/*** Update a Tracy plot with a value + * + * @function tracy.LuaTracyPlot + * @string plotName which LuaPlot should be updated + * @number plotValue the number to show on the Tracy plot + * @treturn nil + */ +static int LuaTracyPlot(lua_State* L) +{ + const auto plotName = luaL_checkstring(L, 1); + const auto plotValue = luaL_checkfloat (L, 2); + + TracyPlot(GetImmanentPlotName(plotName).c_str(), plotValue); + return 0; +} + +/****************************************************************************** + * tracy extensions + * @module TracyExtra + * @see rts/Lua/LuaTracyExtra.cpp +******************************************************************************/ + +bool LuaTracyExtra::PushEntries(lua_State* L) +{ + LuaPushNamedCFunc(L, "LuaTracyPlot" , LuaTracyPlot ); + LuaPushNamedCFunc(L, "LuaTracyPlotConfig", LuaTracyPlotConfig); + return true; +} diff --git a/rts/Lua/LuaTracyExtra.h b/rts/Lua/LuaTracyExtra.h new file mode 100644 index 0000000000..092e793283 --- /dev/null +++ b/rts/Lua/LuaTracyExtra.h @@ -0,0 +1,9 @@ +/* This file is part of the Recoil engine (GPL v2 or later), see LICENSE.html */ + +#pragma once + +struct lua_State; + +namespace LuaTracyExtra { + bool PushEntries(lua_State* L); +}; diff --git a/rts/Lua/LuaUtils.cpp b/rts/Lua/LuaUtils.cpp index f38c8c42f4..e8e78556c0 100644 --- a/rts/Lua/LuaUtils.cpp +++ b/rts/Lua/LuaUtils.cpp @@ -32,6 +32,7 @@ #define SCOPED_TIMER(x) #endif +#include static const int maxDepth = 16; @@ -1821,3 +1822,45 @@ void LuaUtils::PushAttackerInfo(lua_State* L, const CUnit* const attacker) lua_pushnil(L); } #endif + + +void LuaUtils::TracyRemoveAlsoExtras(char* script) +{ + // tracy's built-in remover; does not handle our local TracyExtra functions + tracy::LuaRemove(script); + +#ifndef TRACY_ENABLE + // Our extras are handled manually below, the same way Tracy does. + // Code is on BSD-3 licence, (c) 2017 Bartosz Taudul aka wolfpld + + const auto FindEnd = [] (char *ptr) { + unsigned int cnt = 1; + while (cnt) { + if (*ptr == '(') ++ cnt; + else if (*ptr == ')') -- cnt; + ++ ptr; + } + return ptr; + }; + + const auto Wipe = [&script, FindEnd] (size_t offset) { + const auto end = FindEnd(script + offset); + memset(script, ' ', end - script); + script = end; + }; + + while (*script) { + if (strncmp(script, "tracy.LuaTracyPlot", 18)) { + ++ script; + continue; + } + + if (!strncmp(script + 18, "Config(", 7)) + Wipe(18 + 7); + else if (!strncmp(script + 18, "(", 1)) + Wipe(18 + 1); + else + script += 18; + } +#endif +} diff --git a/rts/Lua/LuaUtils.h b/rts/Lua/LuaUtils.h index 626c8067d4..3b7faccfe0 100644 --- a/rts/Lua/LuaUtils.h +++ b/rts/Lua/LuaUtils.h @@ -206,6 +206,8 @@ class LuaUtils { static const TObj* IdToObject(int id, const char* func = nullptr); template static const TObj* SolIdToObject(int id, const char* func = nullptr); + + static void TracyRemoveAlsoExtras(char *script); }; diff --git a/rts/Lua/LuaVFS.cpp b/rts/Lua/LuaVFS.cpp index bdc59febef..07769bd976 100644 --- a/rts/Lua/LuaVFS.cpp +++ b/rts/Lua/LuaVFS.cpp @@ -172,7 +172,7 @@ int LuaVFS::Include(lua_State* L, bool synced) lua_error(L); } - tracy::LuaRemove(fileData.data()); + LuaUtils::TracyRemoveAlsoExtras(fileData.data()); if ((luaError = luaL_loadbuffer(L, fileData.c_str(), fileData.size(), fileName.c_str())) != 0) { const auto buf = fmt::format("[LuaVFS::{}(synced={})][loadbuf] file={} error={} ({}) cenv={} vfsmode={}", __func__, synced, fileName, luaError, lua_tostring(L, -1), hasCustomEnv, mode); lua_pushlstring(L, buf.c_str(), buf.size()); @@ -229,6 +229,7 @@ int LuaVFS::LoadFile(lua_State* L, bool synced) string data; if (LoadFileWithModes(filename, data, GetModes(L, 2, synced)) == 1) { + LuaUtils::TracyRemoveAlsoExtras(data.data()); lua_pushsstring(L, data); return 1; }