1
0
Fork 0
mirror of https://github.com/luanti-org/luanti.git synced 2025-09-15 18:57:08 +00:00

Add support for Tracy profiler (#15113)

This commit is contained in:
DS 2024-09-15 13:47:45 +02:00 committed by GitHub
parent 6f23de41fb
commit 4aec4fbe6f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 379 additions and 4 deletions

View file

@ -648,6 +648,9 @@ if(BUILD_CLIENT)
if(BUILD_UNITTESTS OR BUILD_BENCHMARKS)
target_link_libraries(${PROJECT_NAME} Catch2::Catch2)
endif()
if(BUILD_WITH_TRACY)
target_link_libraries(${PROJECT_NAME} Tracy::TracyClient)
endif()
if(PRECOMPILE_HEADERS)
target_precompile_headers(${PROJECT_NAME} PRIVATE ${PRECOMPILED_HEADERS_LIST})
@ -715,6 +718,9 @@ if(BUILD_SERVER)
if(BUILD_UNITTESTS OR BUILD_BENCHMARKS)
target_link_libraries(${PROJECT_NAME}server Catch2::Catch2)
endif()
if(BUILD_WITH_TRACY)
target_link_libraries(${PROJECT_NAME}server Tracy::TracyClient)
endif()
if(PRECOMPILE_HEADERS)
target_precompile_headers(${PROJECT_NAME}server PRIVATE ${PRECOMPILED_HEADERS_LIST})

View file

@ -35,6 +35,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "version.h"
#include "renderingengine.h"
#include "network/networkexceptions.h"
#include "util/tracy_wrapper.h"
#include <IGUISpriteBank.h>
#include <ICameraSceneNode.h>
#include <unordered_map>
@ -544,15 +545,19 @@ void ClientLauncher::main_menu(MainMenuData *menudata)
video::IVideoDriver *driver = m_rendering_engine->get_video_driver();
infostream << "Waiting for other menus" << std::endl;
auto framemarker = FrameMarker("ClientLauncher::main_menu()-wait-frame").started();
while (m_rendering_engine->run() && !*kill) {
if (!isMenuActive())
break;
driver->beginScene(true, true, video::SColor(255, 128, 128, 128));
m_rendering_engine->get_gui_env()->drawAll();
driver->endScene();
framemarker.end();
// On some computers framerate doesn't seem to be automatically limited
sleep_ms(25);
framemarker.start();
}
framemarker.end();
infostream << "Waited for other menus" << std::endl;
auto *cur_control = m_rendering_engine->get_raw_device()->getCursorControl();

View file

@ -31,6 +31,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "settings.h"
#include "camera.h" // CameraModes
#include "util/basic_macros.h"
#include "util/tracy_wrapper.h"
#include "client/renderingengine.h"
#include <queue>
@ -714,6 +715,8 @@ void ClientMap::touchMapBlocks()
void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
{
ZoneScoped;
bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
std::string prefix;

View file

@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/basic_macros.h"
#include "util/numeric.h"
#include "util/directiontables.h"
#include "util/tracy_wrapper.h"
#include "mapblock_mesh.h"
#include "settings.h"
#include "nodedef.h"
@ -1750,6 +1751,8 @@ void MapblockMeshGenerator::drawNode()
void MapblockMeshGenerator::generate()
{
ZoneScoped;
for (cur_node.p.Z = 0; cur_node.p.Z < data->side_length; cur_node.p.Z++)
for (cur_node.p.Y = 0; cur_node.p.Y < data->side_length; cur_node.p.Y++)
for (cur_node.p.X = 0; cur_node.p.X < data->side_length; cur_node.p.X++) {

View file

@ -79,6 +79,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "hud.h"
#include "clientdynamicinfo.h"
#include <IAnimatedMeshSceneNode.h>
#include "util/tracy_wrapper.h"
#if USE_SOUND
#include "client/sound/sound_openal.h"
@ -1140,6 +1141,8 @@ bool Game::startup(bool *kill,
void Game::run()
{
ZoneScoped;
ProfilerGraph graph;
RunStats stats = {};
CameraOrientation cam_view_target = {};
@ -1167,15 +1170,21 @@ void Game::run()
const bool initial_window_maximized = !g_settings->getBool("fullscreen") &&
g_settings->getBool("window_maximized");
auto framemarker = FrameMarker("Game::run()-frame").started();
while (m_rendering_engine->run()
&& !(*kill || g_gamecallback->shutdown_requested
|| (server && server->isShutdownRequested()))) {
framemarker.end();
// Calculate dtime =
// m_rendering_engine->run() from this iteration
// + Sleep time until the wanted FPS are reached
draw_times.limit(device, &dtime, g_menumgr.pausesGame());
framemarker.start();
const auto current_dynamic_info = ClientDynamicInfo::getCurrent();
if (!current_dynamic_info.equal(client_display_info)) {
client_display_info = current_dynamic_info;
@ -1232,6 +1241,8 @@ void Game::run()
}
}
framemarker.end();
RenderingEngine::autosaveScreensizeAndCo(initial_screen_size, initial_window_maximized);
}
@ -1671,9 +1682,13 @@ bool Game::connectToServer(const GameStartData &start_data,
fps_control.reset();
auto framemarker = FrameMarker("Game::connectToServer()-frame").started();
while (m_rendering_engine->run()) {
framemarker.end();
fps_control.limit(device, &dtime);
framemarker.start();
// Update client and server
step(dtime);
@ -1719,6 +1734,7 @@ bool Game::connectToServer(const GameStartData &start_data,
// Update status
showOverlayMessage(N_("Connecting to server..."), dtime, 20);
}
framemarker.end();
} catch (con::PeerNotFoundException &e) {
warningstream << "This should not happen. Please report a bug." << std::endl;
return false;
@ -1736,9 +1752,11 @@ bool Game::getServerContent(bool *aborted)
fps_control.reset();
auto framemarker = FrameMarker("Game::getServerContent()-frame").started();
while (m_rendering_engine->run()) {
framemarker.end();
fps_control.limit(device, &dtime);
framemarker.start();
// Update client and server
step(dtime);
@ -1804,6 +1822,7 @@ bool Game::getServerContent(bool *aborted)
texture_src, dtime, progress);
}
}
framemarker.end();
*aborted = true;
infostream << "Connect aborted [device]" << std::endl;
@ -2773,6 +2792,8 @@ void Game::updatePauseState()
inline void Game::step(f32 dtime)
{
ZoneScoped;
if (server) {
float fps_max = (!device->isWindowFocused() || g_menumgr.pausesGame()) ?
g_settings->getFloat("fps_max_unfocused") :
@ -4052,6 +4073,7 @@ void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
const CameraOrientation &cam)
{
ZoneScoped;
TimeTaker tt_update("Game::updateFrame()");
LocalPlayer *player = client->getEnv().getLocalPlayer();
@ -4311,6 +4333,8 @@ void Game::updateShadows()
void Game::drawScene(ProfilerGraph *graph, RunStats *stats)
{
ZoneScoped;
const video::SColor fog_color = this->sky->getFogColor();
const video::SColor sky_color = this->sky->getSkyColor();

View file

@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "minimap.h"
#include "content_mapblock.h"
#include "util/directiontables.h"
#include "util/tracy_wrapper.h"
#include "client/meshgen/collector.h"
#include "client/renderingengine.h"
#include <array>
@ -611,6 +612,8 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs
m_last_crack(-1),
m_last_daynight_ratio((u32) -1)
{
ZoneScoped;
for (auto &m : m_mesh)
m = new scene::SMesh();
m_enable_shaders = data->m_use_shaders;

View file

@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "sound_singleton.h"
#include "util/numeric.h" // myrand()
#include "util/tracy_wrapper.h"
#include "filesys.h"
#include "porting.h"
@ -501,6 +502,8 @@ void *OpenALSoundManager::run()
u64 t_step_start = porting::getTimeMs();
while (true) {
auto framemarker = FrameMarker("OpenALSoundManager::run()-frame").started();
auto get_time_since_last_step = [&] {
return (f32)(porting::getTimeMs() - t_step_start);
};

View file

@ -41,3 +41,4 @@
#cmakedefine01 BUILD_UNITTESTS
#cmakedefine01 BUILD_BENCHMARKS
#cmakedefine01 USE_SDL2
#cmakedefine01 BUILD_WITH_TRACY

View file

@ -40,6 +40,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <ICameraSceneNode.h>
#include <IGUIStaticText.h>
#include "client/imagefilters.h"
#include "util/tracy_wrapper.h"
#if USE_SOUND
#include "client/sound/sound_openal.h"
@ -329,9 +330,12 @@ void GUIEngine::run()
fps_control.reset();
while (m_rendering_engine->run() && !m_startgame && !m_kill) {
auto framemarker = FrameMarker("GUIEngine::run()-frame").started();
while (m_rendering_engine->run() && !m_startgame && !m_kill) {
framemarker.end();
fps_control.limit(device, &dtime);
framemarker.start();
if (device->isWindowVisible()) {
// check if we need to update the "upper left corner"-text
@ -371,6 +375,7 @@ void GUIEngine::run()
m_menu->getAndroidUIInput();
#endif
}
framemarker.end();
m_script->beforeClose();

View file

@ -73,6 +73,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "filesys.h"
#include "log.h"
#include "util/string.h"
#include "util/tracy_wrapper.h"
#include <vector>
#include <cstdarg>
#include <cstdio>
@ -960,6 +961,8 @@ void TrackFreedMemory(size_t amount)
void TriggerMemoryTrim()
{
ZoneScoped;
constexpr auto MO = std::memory_order_relaxed;
if (memory_freed.load(MO) >= MEMORY_TRIM_THRESHOLD) {
// Synchronize call

View file

@ -32,6 +32,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "client/client.h"
#endif
#if BUILD_WITH_TRACY
#include "tracy/TracyLua.hpp"
#endif
extern "C" {
#include "lualib.h"
@ -95,6 +98,11 @@ ScriptApiBase::ScriptApiBase(ScriptingType type):
lua_pushstring(m_luastack, LUA_BITLIBNAME);
lua_call(m_luastack, 1, 0);
#if BUILD_WITH_TRACY
// Load tracy lua bindings
tracy::LuaRegister(m_luastack);
#endif
// Make the ScriptApiBase* accessible to ModApiBase
#if INDIRECT_SCRIPTAPI_RIDX
*(void **)(lua_newuserdata(m_luastack, sizeof(void *))) = this;

View file

@ -109,7 +109,12 @@ void ScriptApiSecurity::initializeSecurity()
"string",
"table",
"math",
"bit"
"bit",
// Not sure if completely safe. But if someone enables tracy, they'll
// know what they do.
#if BUILD_WITH_TRACY
"tracy",
#endif
};
static const char *io_whitelist[] = {
"close",
@ -303,6 +308,11 @@ void ScriptApiSecurity::initializeSecurityClient()
"table",
"math",
"bit",
// Not sure if completely safe. But if someone enables tracy, they'll
// know what they do.
#if BUILD_WITH_TRACY
"tracy",
#endif
};
static const char *os_whitelist[] = {
"clock",

View file

@ -75,6 +75,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "gameparams.h"
#include "particles.h"
#include "gettext.h"
#include "util/tracy_wrapper.h"
class ClientNotFoundException : public BaseException
{
@ -101,6 +102,8 @@ private:
void *ServerThread::run()
{
ZoneScoped;
BEGIN_DEBUG_EXCEPTION_HANDLER
/*
@ -110,6 +113,7 @@ void *ServerThread::run()
* server-step frequency. Receive() is used for waiting between the steps.
*/
auto framemarker = FrameMarker("ServerThread::run()-frame").started();
try {
m_server->AsyncRunStep(0.0f, true);
} catch (con::ConnectionBindFailed &e) {
@ -119,10 +123,12 @@ void *ServerThread::run()
} catch (ModError &e) {
m_server->setAsyncFatalError(e.what());
}
framemarker.end();
float dtime = 0.0f;
while (!stopRequested()) {
framemarker.start();
ScopeProfiler spm(g_profiler, "Server::RunStep() (max)", SPT_MAX);
u64 t0 = porting::getTimeUs();
@ -149,6 +155,7 @@ void *ServerThread::run()
}
dtime = 1e-6f * (porting::getTimeUs() - t0);
framemarker.end();
}
END_DEBUG_EXCEPTION_HANDLER
@ -607,6 +614,9 @@ void Server::step()
void Server::AsyncRunStep(float dtime, bool initial_step)
{
ZoneScoped;
auto framemarker = FrameMarker("Server::AsyncRunStep()-frame").started();
{
// Send blocks to clients
SendBlocks(dtime);
@ -1055,6 +1065,9 @@ void Server::AsyncRunStep(float dtime, bool initial_step)
void Server::Receive(float timeout)
{
ZoneScoped;
auto framemarker = FrameMarker("Server::Receive()-frame").started();
const u64 t0 = porting::getTimeUs();
const float timeout_us = timeout * 1e6f;
auto remaining_time_us = [&]() -> float {

200
src/util/tracy_wrapper.h Normal file
View file

@ -0,0 +1,200 @@
/*
Minetest
Copyright (C) 2024 DS
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*
* Wrapper for <tracy/Tracy.hpp>, so that we can use Tracy's macros without
* having it as mandatory dependency.
*
* For annotations that you don't intend to upstream, you can also include
* <tracy/Tracy.hpp> directly (which also works in irr/).
*/
#pragma once
#include "config.h"
#include "util/basic_macros.h"
#if BUILD_WITH_TRACY
#include <tracy/Tracy.hpp> // IWYU pragma: export
#else
// Copied from Tracy.hpp
#define TracyNoop
#define ZoneNamed(x,y)
#define ZoneNamedN(x,y,z)
#define ZoneNamedC(x,y,z)
#define ZoneNamedNC(x,y,z,w)
#define ZoneTransient(x,y)
#define ZoneTransientN(x,y,z)
#define ZoneScoped
#define ZoneScopedN(x)
#define ZoneScopedC(x)
#define ZoneScopedNC(x,y)
#define ZoneText(x,y)
#define ZoneTextV(x,y,z)
#define ZoneTextF(x,...)
#define ZoneTextVF(x,y,...)
#define ZoneName(x,y)
#define ZoneNameV(x,y,z)
#define ZoneNameF(x,...)
#define ZoneNameVF(x,y,...)
#define ZoneColor(x)
#define ZoneColorV(x,y)
#define ZoneValue(x)
#define ZoneValueV(x,y)
#define ZoneIsActive false
#define ZoneIsActiveV(x) false
#define FrameMark
#define FrameMarkNamed(x)
#define FrameMarkStart(x)
#define FrameMarkEnd(x)
#define FrameImage(x,y,z,w,a)
#define TracyLockable( type, varname ) type varname
#define TracyLockableN( type, varname, desc ) type varname
#define TracySharedLockable( type, varname ) type varname
#define TracySharedLockableN( type, varname, desc ) type varname
#define LockableBase( type ) type
#define SharedLockableBase( type ) type
#define LockMark(x) (void)x
#define LockableName(x,y,z)
#define TracyPlot(x,y)
#define TracyPlotConfig(x,y,z,w,a)
#define TracyMessage(x,y)
#define TracyMessageL(x)
#define TracyMessageC(x,y,z)
#define TracyMessageLC(x,y)
#define TracyAppInfo(x,y)
#define TracyAlloc(x,y)
#define TracyFree(x)
#define TracySecureAlloc(x,y)
#define TracySecureFree(x)
#define TracyAllocN(x,y,z)
#define TracyFreeN(x,y)
#define TracySecureAllocN(x,y,z)
#define TracySecureFreeN(x,y)
#define ZoneNamedS(x,y,z)
#define ZoneNamedNS(x,y,z,w)
#define ZoneNamedCS(x,y,z,w)
#define ZoneNamedNCS(x,y,z,w,a)
#define ZoneTransientS(x,y,z)
#define ZoneTransientNS(x,y,z,w)
#define ZoneScopedS(x)
#define ZoneScopedNS(x,y)
#define ZoneScopedCS(x,y)
#define ZoneScopedNCS(x,y,z)
#define TracyAllocS(x,y,z)
#define TracyFreeS(x,y)
#define TracySecureAllocS(x,y,z)
#define TracySecureFreeS(x,y)
#define TracyAllocNS(x,y,z,w)
#define TracyFreeNS(x,y,z)
#define TracySecureAllocNS(x,y,z,w)
#define TracySecureFreeNS(x,y,z)
#define TracyMessageS(x,y,z)
#define TracyMessageLS(x,y)
#define TracyMessageCS(x,y,z,w)
#define TracyMessageLCS(x,y,z)
#define TracySourceCallbackRegister(x,y)
#define TracyParameterRegister(x,y)
#define TracyParameterSetup(x,y,z,w)
#define TracyIsConnected false
#define TracyIsStarted false
#define TracySetProgramName(x)
#define TracyFiberEnter(x)
#define TracyFiberEnterHint(x,y)
#define TracyFiberLeave
#endif
// Helper for making sure frames end in all possible control flow path
class FrameMarker
{
const char *m_name;
bool m_started = false;
public:
FrameMarker(const char *name) : m_name(name) {}
~FrameMarker() { end(); }
DISABLE_CLASS_COPY(FrameMarker)
FrameMarker(FrameMarker &&other) noexcept :
m_name(other.m_name), m_started(other.m_started)
{
other.m_started = false;
}
FrameMarker &operator=(FrameMarker &&other) noexcept
{
if (&other != this) {
end();
m_name = other.m_name;
m_started = other.m_started;
other.m_started = false;
}
return *this;
}
FrameMarker &&started() &&
{
if (!m_started) {
FrameMarkStart(m_name);
m_started = true;
}
return std::move(*this);
}
void start()
{
// no move happens, because we drop the reference
(void)std::move(*this).started();
}
void end()
{
if (m_started) {
m_started = false;
FrameMarkEnd(m_name);
}
}
};