From 46d1c4a3aab6b1ad8ab72b8d6c1d0f909e27b9c4 Mon Sep 17 00:00:00 2001 From: Quentin Bazin Date: Fri, 21 May 2021 15:28:21 +0200 Subject: [PATCH] [ClientProfiler] Added. [external/gamekit] Updated. --- external/gamekit | 2 +- source/client/core/ClientProfiler.cpp | 87 +++++++++++++++++++++++++++ source/client/core/ClientProfiler.hpp | 65 ++++++++++++++++++++ 3 files changed, 153 insertions(+), 1 deletion(-) create mode 100644 source/client/core/ClientProfiler.cpp create mode 100644 source/client/core/ClientProfiler.hpp diff --git a/external/gamekit b/external/gamekit index 88aee22d..ca65aed9 160000 --- a/external/gamekit +++ b/external/gamekit @@ -1 +1 @@ -Subproject commit 88aee22de2424b4b9238642a487a8f0094f700b2 +Subproject commit ca65aed9949a166e846bec09777ef821cf1949dc diff --git a/source/client/core/ClientProfiler.cpp b/source/client/core/ClientProfiler.cpp new file mode 100644 index 00000000..5985c151 --- /dev/null +++ b/source/client/core/ClientProfiler.cpp @@ -0,0 +1,87 @@ +/* + * ===================================================================================== + * + * OpenMiner + * + * Copyright (C) 2018-2020 Unarelith, Quentin Bazin + * Copyright (C) 2019-2020 the OpenMiner contributors (see CONTRIBUTORS.md) + * + * This file is part of OpenMiner. + * + * OpenMiner 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. + * + * OpenMiner 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 OpenMiner; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * ===================================================================================== + */ +#include +#include + +#include "ClientProfiler.hpp" + +ClientProfiler *ClientProfiler::s_instance = nullptr; + +void ClientProfiler::onBeginTick() { + m_ticks.emplace_back(); + m_ticks.back().begin = gk::GameClock::getInstance().getTicks(true); +} + +void ClientProfiler::onEndTick() { + m_ticks.back().end = gk::GameClock::getInstance().getTicks(true); +} + +void ClientProfiler::startAction(const std::string &name) { + m_ticks.back().actions[name].durations.emplace_back(); + m_ticks.back().actions[name].durations.back().first = gk::GameClock::getInstance().getTicks(true); +} + +void ClientProfiler::endAction(const std::string &name) { + m_ticks.back().actions[name].durations.back().second = gk::GameClock::getInstance().getTicks(true); +} + +void ClientProfiler::dump(u64 tickDurationMin) { + std::unordered_map> maxActionDuration; + + u64 i = 0; + for (auto &tick : m_ticks) { + u64 tickDuration = tick.end - tick.begin; + if (tickDuration < tickDurationMin) continue; + + gkDebug() << "Tick" << i++ << "took" << tickDuration << "ms"; + + if (tickDuration > 0) { + for (auto &[actionName, action] : tick.actions) { + u64 j = 0; + for (auto &[begin, end] : action.durations) { + u64 actionDuration = end - begin; + + if (maxActionDuration.find(actionName) == maxActionDuration.end()) + maxActionDuration.emplace(actionName, std::make_pair(actionDuration, 0)); + + maxActionDuration[actionName].first = std::max(maxActionDuration[actionName].first, actionDuration); + + float actionPercentTotal = actionDuration / (float)tickDuration * 100.f; + + gkDebug() << "Action" << actionName << j++ << "took" << actionDuration << "ms -" << actionPercentTotal << "% of tick"; + } + + maxActionDuration[actionName].second = std::max(maxActionDuration[actionName].second, j); + } + } + } + + for (auto &[actionName, pair] : maxActionDuration) { + gkDebug() << "Max duration for action" << actionName << ":" << pair.first << "ms (" << pair.second << ")"; + } +} + diff --git a/source/client/core/ClientProfiler.hpp b/source/client/core/ClientProfiler.hpp new file mode 100644 index 00000000..c8026364 --- /dev/null +++ b/source/client/core/ClientProfiler.hpp @@ -0,0 +1,65 @@ +/* + * ===================================================================================== + * + * OpenMiner + * + * Copyright (C) 2018-2020 Unarelith, Quentin Bazin + * Copyright (C) 2019-2020 the OpenMiner contributors (see CONTRIBUTORS.md) + * + * This file is part of OpenMiner. + * + * OpenMiner 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. + * + * OpenMiner 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 OpenMiner; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * ===================================================================================== + */ +#ifndef CLIENTPROFILER_HPP_ +#define CLIENTPROFILER_HPP_ + +#include +#include +#include + +#include + +struct ClientAction { + std::deque> durations; +}; + +struct ClientTick { + u64 begin; + u64 end; + std::unordered_map actions; +}; + +class ClientProfiler { + public: + void onBeginTick(); + void onEndTick(); + + void dump(u64 tickDurationMin = 0); + + void startAction(const std::string &name); + void endAction(const std::string &name); + + static ClientProfiler &getInstance() { return *s_instance; } + static void setInstance(ClientProfiler *instance) { s_instance = instance; } + + private: + static ClientProfiler *s_instance; + + std::deque m_ticks; +}; + +#endif // CLIENTPROFILER_HPP_