diff options
-rw-r--r-- | src/CMakeLists.txt | 3 | ||||
-rw-r--r-- | src/Makefile.am | 3 | ||||
-rw-r--r-- | src/const/utils/perfstat.h | 29 | ||||
-rw-r--r-- | src/game.cpp | 3 | ||||
-rw-r--r-- | src/gui/widgets/tabs/statdebugtab.cpp | 60 | ||||
-rw-r--r-- | src/gui/widgets/tabs/statdebugtab.h | 14 | ||||
-rw-r--r-- | src/progs/manaplus/client.cpp | 34 | ||||
-rw-r--r-- | src/utils/perfstat.cpp | 127 | ||||
-rw-r--r-- | src/utils/perfstat.h | 62 |
9 files changed, 333 insertions, 2 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6bd5cb8a8..b4433b8cc 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -940,6 +940,8 @@ SET(SRCS fs/paths.h utils/perfomance.cpp utils/perfomance.h + utils/perfstat.cpp + utils/perfstat.h utils/pnglib.cpp utils/pnglib.h fs/virtfs/fsfuncs.h @@ -1128,6 +1130,7 @@ SET(SRCS const/equipment.h const/itemshortcut.h const/spells.h + const/utils/perfstat.h const/utils/timer.h const/utils/utf8.h const/gui/chat.h diff --git a/src/Makefile.am b/src/Makefile.am index b55b7a237..ef905997e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -641,6 +641,8 @@ BASE_SRC += client.h \ fs/paths.h \ utils/perfomance.cpp \ utils/perfomance.h \ + utils/perfstat.cpp \ + utils/perfstat.h \ utils/pnglib.cpp \ utils/pnglib.h \ fs/virtfs/fsfuncs.h \ @@ -719,6 +721,7 @@ BASE_SRC += client.h \ const/equipment.h \ const/itemshortcut.h \ const/spells.h \ + const/utils/perfstat.h \ const/utils/timer.h \ const/utils/utf8.h \ const/gui/chat.h \ diff --git a/src/const/utils/perfstat.h b/src/const/utils/perfstat.h new file mode 100644 index 000000000..9f7430516 --- /dev/null +++ b/src/const/utils/perfstat.h @@ -0,0 +1,29 @@ +/* + * The ManaPlus Client + * Copyright (C) 2018 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef CONST_UTILS_PERFSTAT_H +#define CONST_UTILS_PERFSTAT_H + +#include "localconsts.h" + +static const int PERFSTAT_MAX = 120; +static const int PERFSTAT_LAST_STAT = 13; + +#endif // CONST_UTILS_PERFSTAT_H diff --git a/src/game.cpp b/src/game.cpp index bfbaba353..eadfda7f6 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -125,6 +125,7 @@ #include "utils/delete2.h" #include "utils/foreach.h" #include "utils/gettext.h" +#include "utils/perfstat.h" #include "utils/pnglib.h" #include "utils/sdlcheckutils.h" #include "utils/timer.h" @@ -1092,6 +1093,7 @@ void Game::changeMap(const std::string &mapPath) { BLOCK_START("Game::changeMap") + skipPerfFrames = 3; resetAdjustLevel(); ResourceManager::cleanProtected(); @@ -1182,6 +1184,7 @@ void Game::changeMap(const std::string &mapPath) localPlayer->recreateItemParticles(); gameHandler->mapLoadedEvent(); + Perf::init(); BLOCK_END("Game::changeMap") } diff --git a/src/gui/widgets/tabs/statdebugtab.cpp b/src/gui/widgets/tabs/statdebugtab.cpp index 29fca62de..6d4f8afa4 100644 --- a/src/gui/widgets/tabs/statdebugtab.cpp +++ b/src/gui/widgets/tabs/statdebugtab.cpp @@ -20,11 +20,17 @@ #include "gui/widgets/tabs/statdebugtab.h" +#include "const/utils/timer.h" + +#include "gui/widgets/button.h" #include "gui/widgets/containerplacer.h" #include "gui/widgets/label.h" #include "gui/widgets/layouthelper.h" +#include "gui/windows/chatwindow.h" + #include "utils/gettext.h" +#include "utils/perfstat.h" #include "utils/stringutils.h" #include "utils/timer.h" @@ -33,12 +39,27 @@ StatDebugTab::StatDebugTab(const Widget2 *const widget) : DebugTab(widget), // TRANSLATORS: debug window label, logic per second - mLPSLabel(new Label(this, strprintf(_("LPS: %d"), 0))) + mLPSLabel(new Label(this, strprintf(_("LPS: %d"), 0))), + // TRANSLATORS: debug window stats reset button + mResetButton(new Button(this, _("Reset"), "reset", BUTTON_SKIN, this)), + // TRANSLATORS: debug window stats copy button + mCopyButton(new Button(this, _("Copy"), "copy", BUTTON_SKIN, this)), + mStatLabels(), + mDrawIndex(0) { LayoutHelper h(this); ContainerPlacer place = h.getPlacer(0, 0); place(0, 0, mLPSLabel, 2, 1); + place(0, 1, mResetButton, 1, 1); + place(1, 1, mCopyButton, 1, 1); + for (int f = 1; f < PERFSTAT_LAST_STAT; f ++) + { + mStatLabels[f - 1] = new Label(this, + // TRANSLATORS: debug window stat label + strprintf(_("stat%d: %d (%d) ms"), f, 0, 0)); + place(0, f + 1, mStatLabels[f - 1], 2, 1); + } place.getCell().matchColWidth(0, 0); place = h.getPlacer(0, 1); @@ -50,5 +71,42 @@ void StatDebugTab::logic() BLOCK_START("StatDebugTab::logic") // TRANSLATORS: debug window label, logic per second mLPSLabel->setCaption(strprintf(_("LPS: %d"), lps)); + + for (int f = 1; f < PERFSTAT_LAST_STAT; f ++) + { + mStatLabels[f - 1]->setCaption( + // TRANSLATORS: debug window stat label + strprintf(_("stat%d: %d (%d) ms"), + f, + Perf::getTime(prevPerfFrameId, f) * MILLISECONDS_IN_A_TICK, + Perf::getWorstTime(f) * MILLISECONDS_IN_A_TICK)); + } + mDrawIndex = prevPerfFrameId; BLOCK_END("StatDebugTab::logic") } + +void StatDebugTab::action(const ActionEvent &event) +{ + const std::string &eventId = event.getId(); + if (eventId == "reset") + { + Perf::init(); + } + else if (eventId == "copy") + { + std::string data("perf:"); + for (int f = 1; f < PERFSTAT_LAST_STAT; f ++) + { + data.append(strprintf(" %d", + Perf::getTime(mDrawIndex, f) * MILLISECONDS_IN_A_TICK)); + } + data.append(","); + for (int f = 1; f < PERFSTAT_LAST_STAT; f ++) + { + data.append(strprintf(" %d", + Perf::getWorstTime(f) * MILLISECONDS_IN_A_TICK)); + } + chatWindow->addInputText(data, + true); + } +} diff --git a/src/gui/widgets/tabs/statdebugtab.h b/src/gui/widgets/tabs/statdebugtab.h index d52ff63af..57b2e9f4a 100644 --- a/src/gui/widgets/tabs/statdebugtab.h +++ b/src/gui/widgets/tabs/statdebugtab.h @@ -23,9 +23,15 @@ #include "gui/widgets/tabs/debugtab.h" +#include "const/utils/perfstat.h" + +#include "listeners/actionlistener.h" + +class Button; class Label; -class StatDebugTab final : public DebugTab +class StatDebugTab final : public DebugTab, + public ActionListener { friend class DebugWindow; @@ -36,8 +42,14 @@ class StatDebugTab final : public DebugTab void logic() override final; + void action(const ActionEvent &event) override; + private: Label *mLPSLabel A_NONNULLPOINTER; + Button *mResetButton A_NONNULLPOINTER; + Button *mCopyButton A_NONNULLPOINTER; + Label *mStatLabels[PERFSTAT_LAST_STAT - 1] A_NONNULLPOINTER; + size_t mDrawIndex; }; #endif // GUI_WIDGETS_TABS_STATDEBUGTAB_H diff --git a/src/progs/manaplus/client.cpp b/src/progs/manaplus/client.cpp index 880f05a0b..01348db2d 100644 --- a/src/progs/manaplus/client.cpp +++ b/src/progs/manaplus/client.cpp @@ -127,6 +127,7 @@ #ifdef ANDROID #include "fs/paths.h" #endif // ANDROID +#include "utils/perfstat.h" #include "utils/sdlcheckutils.h" #include "utils/sdlhelper.h" #include "utils/timer.h" @@ -952,20 +953,30 @@ int Client::gameExec() { int lastTickTime = tick_time; + Perf::init(); + while (mState != State::EXIT) { PROFILER_START(); + PERF_STAT(0); if (eventsManager.handleEvents()) continue; + PERF_STAT(1); + BLOCK_START("Client::gameExec 3") if (generalHandler != nullptr) generalHandler->flushNetwork(); BLOCK_END("Client::gameExec 3") + PERF_STAT(2); + BLOCK_START("Client::gameExec 4") if (gui != nullptr) gui->logic(); + + PERF_STAT(3); + cur_time = time(nullptr); int k = 0; while (lastTickTime != tick_time && @@ -979,14 +990,28 @@ int Client::gameExec() ++lastTickTime; k ++; } + + PERF_STAT(4); + soundManager.logic(); + PERF_STAT(5); + logic_count += k; if (gui != nullptr) gui->slowLogic(); + + PERF_STAT(6); + if (mGame != nullptr) mGame->slowLogic(); + + PERF_STAT(7); + slowLogic(); + + PERF_STAT(8); + BLOCK_END("Client::gameExec 4") // This is done because at some point tick_time will wrap. @@ -1005,11 +1030,15 @@ int Client::gameExec() SDL_Delay(100); } + PERF_STAT(9); + BLOCK_START("~Client::SDL_framerateDelay") if (settings.limitFps) SDL_framerateDelay(&fpsManager); BLOCK_END("~Client::SDL_framerateDelay") + PERF_STAT(10); + BLOCK_START("Client::gameExec 6") if (mState == State::CONNECT_GAME) { @@ -1034,6 +1063,8 @@ int Client::gameExec() } BLOCK_END("Client::gameExec 6") + PERF_STAT(11); + if (mState != mOldState) { BLOCK_START("Client::gameExec 7") @@ -1373,6 +1404,7 @@ int Client::gameExec() if (mumbleManager) mumbleManager->setPlayer(localPlayer->getName()); #endif // USE_MUMBLE + Perf::init(); } // Fade out logon-music here too to give the desired effect @@ -1656,6 +1688,8 @@ int Client::gameExec() } BLOCK_END("Client::gameExec 8") } + PERF_STAT(12); + PERF_NEXTFRAME(); PROFILER_END(); } diff --git a/src/utils/perfstat.cpp b/src/utils/perfstat.cpp new file mode 100644 index 000000000..839fc7291 --- /dev/null +++ b/src/utils/perfstat.cpp @@ -0,0 +1,127 @@ +/* + * The ManaPlus Client + * Copyright (C) 2018 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "utils/perfstat.h" + +#include "logger.h" + +#include "utils/timer.h" + +#include "debug.h" + +PerfStats perfStats[PERFSTAT_MAX]; + +size_t perfFrameId = 0; +size_t prevPerfFrameId = PERFSTAT_MAX; +int *perfFrame = &perfStats[perfFrameId].ticks[0]; +PerfStats worstFrameStats; +int worstTime = -1; +int skipPerfFrames = -1; + +namespace Perf +{ + void init() + { + logger->log("perf stats init"); + worstTime = -1; + perfFrameId = 0; + prevPerfFrameId = 0; + for (size_t f = 0; f < PERFSTAT_LAST_STAT; f ++) + { + worstFrameStats.ticks[f] = 0; + } + for (size_t f = 0; f < PERFSTAT_MAX; f ++) + { + PerfStats &perf = perfStats[f]; + for (size_t d = 0; d < PERFSTAT_LAST_STAT; d ++) + { + perf.ticks[d] = 0; + } + } + skipPerfFrames = 0; + } + + void nextFrame() + { + if (skipPerfFrames > 0) + { + skipPerfFrames --; +// logger->log("skip frames: %d", skipPerfFrames); + return; + } + else if (skipPerfFrames < 0) + { + return; + } + prevPerfFrameId = perfFrameId; + perfFrameId ++; + if (perfFrameId >= PERFSTAT_MAX) + { + perfFrameId = 0; + selectWorstFrame(); + } + perfFrame = &perfStats[perfFrameId].ticks[0]; + } + + void selectWorstFrame() + { + int time = worstTime; + int index = -1; + for (size_t f = 0; f < PERFSTAT_MAX; f ++) + { + if (f == perfFrameId) + continue; + const int time1 = Perf::getTime(f, PERFSTAT_LAST_STAT - 1); + if (time1 > time) + { + time = time1; + index = f; + } + } + if (index >= 0) + { + worstFrameStats = perfStats[index]; + logger->log("worst frame: %d, %d", + perfStats[index].ticks[PERFSTAT_LAST_STAT - 1], + worstFrameStats.ticks[PERFSTAT_LAST_STAT - 1]); + worstTime = time; + } + } + + int getTime(const size_t frameId, + const size_t counterId) + { + const PerfStats &perf = perfStats[frameId]; + const int val1 = perf.ticks[0]; + const int val2 = perf.ticks[counterId]; + if (val2 >= val1) + return val2 - val1; + return val1 - val1; + } + + int getWorstTime(const size_t counterId) + { + const int val1 = worstFrameStats.ticks[0]; + const int val2 = worstFrameStats.ticks[counterId]; + if (val2 >= val1) + return val2 - val1; + return val1 - val1; + } +} diff --git a/src/utils/perfstat.h b/src/utils/perfstat.h new file mode 100644 index 000000000..97e5e1a07 --- /dev/null +++ b/src/utils/perfstat.h @@ -0,0 +1,62 @@ +/* + * The ManaPlus Client + * Copyright (C) 2018 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef UTILS_PERFSTAT_H +#define UTILS_PERFSTAT_H + +#include "const/utils/perfstat.h" + +#include "localconsts.h" + +struct PerfStats +{ + PerfStats() + { + for (int f = 0; f < 16; f ++) + ticks[f] = -1; + } + + int ticks[16]; +}; + +namespace Perf +{ + void init(); + void nextFrame(); + void selectWorstFrame(); + int getTime(const size_t frameId, + const size_t counterId); + int getWorstTime(const size_t counterId); +} + +extern PerfStats perfStats[PERFSTAT_MAX]; +extern size_t perfFrameId; +extern size_t prevPerfFrameId; +extern int *perfFrame; +extern PerfStats worstFrameStats; +extern int skipPerfFrames; + +#define PERF_STAT(n) \ + perfFrame[n] = tick_time + +#define PERF_NEXTFRAME() \ + Perf::nextFrame() + +#endif // UTILS_PERFSTAT_H |