1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-01-16 03:29:55 +00:00

Lua Profiler

This commit is contained in:
Petr Mikheev 2022-11-26 21:25:18 +01:00
parent 6fa65e4729
commit 02a9069a0e
14 changed files with 216 additions and 9 deletions

View file

@ -100,6 +100,8 @@ namespace MWBase
virtual void handleConsoleCommand(
const std::string& consoleMode, const std::string& command, const MWWorld::Ptr& selectedPtr)
= 0;
virtual std::string formatResourceUsageStats() const = 0;
};
}

View file

@ -159,6 +159,7 @@ namespace MWBase
virtual void updateSpellWindow() = 0;
virtual void setConsoleSelectedObject(const MWWorld::Ptr& object) = 0;
virtual MWWorld::Ptr getConsoleSelectedObject() const = 0;
virtual void setConsoleMode(const std::string& mode) = 0;
static constexpr std::string_view sConsoleColor_Default = "#FFFFFF";

View file

@ -23,6 +23,7 @@ namespace MWGui
public:
/// Set the implicit object for script execution
void setSelectedObject(const MWWorld::Ptr& object);
MWWorld::Ptr getSelectedObject() const { return mPtr; }
MyGUI::EditBox* mCommandLine;
MyGUI::EditBox* mHistory;

View file

@ -8,6 +8,9 @@
#include <components/debug/debugging.hpp>
#include <components/settings/settings.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/luamanager.hpp"
#include <mutex>
#ifndef BT_NO_PROFILE
@ -106,6 +109,12 @@ namespace MWGui
= itemLV->createWidgetReal<MyGUI::EditBox>("LogEdit", MyGUI::FloatCoord(0, 0, 1, 1), MyGUI::Align::Stretch);
mLogView->setEditReadOnly(true);
MyGUI::TabItem* itemLuaProfiler = mTabControl->addItem("Lua Profiler");
itemLuaProfiler->setCaptionWithReplacing(" #{DebugMenu:LuaProfiler} ");
mLuaProfiler = itemLuaProfiler->createWidgetReal<MyGUI::EditBox>(
"LogEdit", MyGUI::FloatCoord(0, 0, 1, 1), MyGUI::Align::Stretch);
mLuaProfiler->setEditReadOnly(true);
#ifndef BT_NO_PROFILE
MyGUI::TabItem* item = mTabControl->addItem("Physics Profiler");
item->setCaptionWithReplacing(" #{DebugMenu:PhysicsProfiler} ");
@ -206,6 +215,16 @@ namespace MWGui
mLogView->setVScrollPosition(scrollPos);
}
void DebugWindow::updateLuaProfile()
{
if (mLuaProfiler->isTextSelection())
return;
size_t previousPos = mLuaProfiler->getVScrollPosition();
mLuaProfiler->setCaption(MWBase::Environment::get().getLuaManager()->formatResourceUsageStats());
mLuaProfiler->setVScrollPosition(std::min(previousPos, mLuaProfiler->getVScrollRange() - 1));
}
void DebugWindow::updateBulletProfile()
{
#ifndef BT_NO_PROFILE
@ -229,9 +248,18 @@ namespace MWGui
return;
timer = 0.25;
if (mTabControl->getIndexSelected() == 0)
updateLogView();
else
updateBulletProfile();
switch (mTabControl->getIndexSelected())
{
case 0:
updateLogView();
break;
case 1:
updateLuaProfile();
break;
case 2:
updateBulletProfile();
break;
default:;
}
}
}

View file

@ -17,10 +17,12 @@ namespace MWGui
private:
void updateLogView();
void updateLuaProfile();
void updateBulletProfile();
MyGUI::TabControl* mTabControl;
MyGUI::EditBox* mLogView;
MyGUI::EditBox* mLuaProfiler;
MyGUI::EditBox* mBulletProfilerEdit;
};

View file

@ -2158,6 +2158,11 @@ namespace MWGui
mConsole->setSelectedObject(object);
}
MWWorld::Ptr WindowManager::getConsoleSelectedObject() const
{
return mConsole->getSelectedObject();
}
void WindowManager::printToConsole(const std::string& msg, std::string_view color)
{
mConsole->print(msg, color);

View file

@ -188,6 +188,7 @@ namespace MWGui
void updateSpellWindow() override;
void setConsoleSelectedObject(const MWWorld::Ptr& object) override;
MWWorld::Ptr getConsoleSelectedObject() const override;
void printToConsole(const std::string& msg, std::string_view color) override;
void setConsoleMode(const std::string& mode) override;

View file

@ -37,8 +37,16 @@
namespace MWLua
{
static LuaUtil::LuaStateSettings createLuaStateSettings()
{
return { .mInstructionLimit = Settings::Manager::getUInt64("instruction limit per call", "Lua"),
.mMemoryLimit = Settings::Manager::getUInt64("memory limit", "Lua"),
.mSmallAllocMaxSize = Settings::Manager::getUInt64("small alloc max size", "Lua"),
.mLogMemoryUsage = Settings::Manager::getBool("log memory usage", "Lua") };
}
LuaManager::LuaManager(const VFS::Manager* vfs, const std::filesystem::path& libsDir)
: mLua(vfs, &mConfiguration)
: mLua(vfs, &mConfiguration, createLuaStateSettings())
, mUiResourceManager(vfs)
{
Log(Debug::Info) << "Lua version: " << LuaUtil::getLuaVersion();
@ -605,9 +613,90 @@ namespace MWLua
mActionQueue.push_back(std::make_unique<FunctionAction>(&mLua, std::move(action), name));
}
void LuaManager::reportStats(unsigned int frameNumber, osg::Stats& stats)
void LuaManager::reportStats(unsigned int frameNumber, osg::Stats& stats) const
{
const sol::state_view state(mLua.sol());
stats.setAttribute(frameNumber, "Lua UsedMemory", state.memory_used());
stats.setAttribute(frameNumber, "Lua UsedMemory", mLua.getTotalMemoryUsage());
}
std::string LuaManager::formatResourceUsageStats() const
{
std::stringstream out;
static const uint64_t smallAllocSize = Settings::Manager::getUInt64("small alloc max size", "Lua");
out << "Total memory usage: " << mLua.getTotalMemoryUsage() << "\n";
out << "small alloc max size = " << smallAllocSize << " (section [Lua] in settings.cfg)\n";
out << "Smaller values give more information for the profiler, but increase performance overhead.\n";
out << " Memory allocations <= " << smallAllocSize << " bytes: " << mLua.getSmallAllocMemoryUsage()
<< " (not tracked)\n";
out << " Memory allocations > " << smallAllocSize
<< " bytes: " << mLua.getTotalMemoryUsage() - mLua.getSmallAllocMemoryUsage() << " (see the table below)\n";
out << "\n";
using Stats = LuaUtil::ScriptsContainer::ScriptStats;
std::vector<Stats> activeStats;
mGlobalScripts.collectStats(activeStats);
for (LocalScripts* scripts : mActiveLocalScripts)
scripts->collectStats(activeStats);
std::vector<Stats> selectedStats;
MWWorld::Ptr selectedPtr = MWBase::Environment::get().getWindowManager()->getConsoleSelectedObject();
LocalScripts* selectedScripts = nullptr;
if (!selectedPtr.isEmpty())
{
selectedScripts = selectedPtr.getRefData().getLuaScripts();
if (selectedScripts)
selectedScripts->collectStats(selectedStats);
out << "Profiled object (selected in the in-game console): " << ptrToString(selectedPtr) << "\n";
}
else
out << "No selected object. Use the in-game console to select an object for detailed profile.\n";
out << "\n";
constexpr int nameW = 50;
constexpr int valueW = 12;
out << std::left;
out << " " << std::setw(nameW + 2) << "*** Resource usage per script";
out << std::right;
out << std::setw(valueW) << "CPU";
out << std::setw(valueW) << "memory";
out << std::setw(valueW) << "memory";
out << std::setw(valueW) << "CPU";
out << std::setw(valueW) << "memory";
out << "\n";
out << std::left << " " << std::setw(nameW + 2) << "[name]" << std::right;
out << std::setw(valueW) << "[all]";
out << std::setw(valueW) << "[active]";
out << std::setw(valueW) << "[inactive]";
out << std::setw(valueW * 2) << "[for selected object]";
out << "\n";
for (size_t i = 0; i < mConfiguration.size(); ++i)
{
bool isGlobal = mConfiguration[i].mFlags & ESM::LuaScriptCfg::sGlobal;
out << std::left;
out << " " << std::setw(nameW) << mConfiguration[i].mScriptPath;
if (mConfiguration[i].mScriptPath.size() > nameW)
out << "\n " << std::setw(nameW) << ""; // if path is too long, break line
out << std::right;
out << std::setw(valueW) << static_cast<int64_t>(activeStats[i].mCPUusage);
out << std::setw(valueW) << activeStats[i].mMemoryUsage;
out << std::setw(valueW) << mLua.getMemoryUsageByScriptIndex(i) - activeStats[i].mMemoryUsage;
if (isGlobal)
out << std::setw(valueW * 2) << "NA (global script)";
else if (selectedPtr.isEmpty())
out << std::setw(valueW * 2) << "NA (not selected) ";
else if (!selectedScripts || !selectedScripts->hasScript(i))
out << std::setw(valueW) << "-" << std::setw(valueW) << selectedStats[i].mMemoryUsage;
else
out << std::setw(valueW) << static_cast<int64_t>(selectedStats[i].mCPUusage) << std::setw(valueW)
<< selectedStats[i].mMemoryUsage;
out << "\n";
}
return out.str();
}
}

View file

@ -122,7 +122,8 @@ namespace MWLua
bool isProcessingInputEvents() const { return mProcessingInputEvents; }
void reportStats(unsigned int frameNumber, osg::Stats& stats);
void reportStats(unsigned int frameNumber, osg::Stats& stats) const;
std::string formatResourceUsageStats() const override;
private:
void initConfiguration();

View file

@ -26,3 +26,64 @@ If one, a separate thread is used.
Values >1 are not yet supported.
This setting can only be configured by editing the settings configuration file.
lua profiler
------------
:Type: boolean
:Range: True/False
:Default: True
Enables Lua profiler.
This setting can only be configured by editing the settings configuration file.
small alloc max size
--------------------
:Type: integer
:Range: >= 0
:Default: 1024
No ownership tracking for memory allocations below or equal this size (in bytes).
This setting is used only if ``lua profiler = true``.
With the default value (1024) the lua profiler will show almost no memory usage because allocation more than 1KB are rare.
Decrease the value of this setting (e.g. set it to 64) to have better memory tracking by the cost of higher overhead.
This setting can only be configured by editing the settings configuration file.
memory limit
------------
:Type: integer
:Range: > 0
:Default: 2147483648 (2GB)
Memory limit for Lua runtime (only if ``lua profiler = true``). If exceeded then only small allocations are allowed.
Small allocations are always allowed, so e.g. Lua console can function.
This setting can only be configured by editing the settings configuration file.
log memory usage
----------------
:Type: boolean
:Range: True/False
:Default: False
Print debug info about memory usage (only if ``lua profiler = true``).
This setting can only be configured by editing the settings configuration file.
instruction limit per call
--------------------------
:Type: integer
:Range: > 1000
:Default: 100000000
The maximal number of Lua instructions per function call (only if ``lua profiler = true``).
If exceeded (e.g. because of an infinite loop) the function will be terminated.
This setting can only be configured by editing the settings configuration file.

View file

@ -1,3 +1,4 @@
DebugWindow: "Debug"
LogViewer: "Protokollansicht"
LuaProfiler: "Lua-Profiler"
PhysicsProfiler: "Physik-Profiler"

View file

@ -1,3 +1,4 @@
DebugWindow: "Debug"
LogViewer: "Log Viewer"
LuaProfiler: "Lua Profiler"
PhysicsProfiler: "Physics Profiler"

View file

@ -1,3 +1,4 @@
DebugWindow: "Меню отладки"
LogViewer: "Журнал логов"
LuaProfiler: "Профилировщик Луа"
PhysicsProfiler: "Профилировщик физики"

View file

@ -1141,6 +1141,19 @@ lua debug = false
# If zero, Lua scripts are processed in the main thread.
lua num threads = 1
# No ownership tracking for allocations below or equal this size.
small alloc max size = 1024
# Memory limit for Lua runtime. If exceeded then only small allocations are allowed. Small allocations are always allowed, so e.g. Lua console can function.
# Default value is 2GB.
memory limit = 2147483648
# Print debug info about memory usage.
log memory usage = false
# The maximal number of Lua instructions per function call. If exceeded (e.g. because of an infinite loop) the function will be terminated.
instruction limit per call = 100000000
[Stereo]
# Enable/disable stereo view. This setting is ignored in VR.
stereo enabled = false