From 5bbb045e862540fee965c9b5e8c10ecbfb9287d8 Mon Sep 17 00:00:00 2001 From: MatthewBeshay <92357869+MatthewBeshay@users.noreply.github.com> Date: Fri, 3 Apr 2026 17:28:06 +1100 Subject: [PATCH] refactor: consolidate timing utilities into header-only Timer.h --- targets/app/common/Consoles_App.cpp | 33 +++--- targets/app/common/Consoles_App.h | 10 +- targets/app/common/src/Tutorial/Tutorial.cpp | 60 +++++----- targets/app/common/src/Tutorial/Tutorial.h | 9 +- .../app/common/src/Tutorial/TutorialMode.cpp | 2 +- targets/app/common/src/UI/UIController.cpp | 29 +++-- targets/app/common/src/UI/UIController.h | 4 +- .../console_helpers/PerformanceTimer.h | 14 --- .../include/console_helpers/PlatformTime.h | 38 ------- .../include/console_helpers/Timer.h | 107 ++++++++++++++++++ targets/console_helpers/meson.build | 2 - .../console_helpers/src/PerformanceTimer.cpp | 21 ---- targets/minecraft/client/Minecraft.cpp | 5 +- .../client/multiplayer/ClientConnection.cpp | 8 +- .../client/multiplayer/ClientConnection.h | 3 +- targets/minecraft/server/MinecraftServer.cpp | 29 ++--- targets/minecraft/server/MinecraftServer.h | 3 +- .../level/levelgen/RandomLevelSource.cpp | 13 +-- .../ConsoleSaveFileSplit.cpp | 27 ++--- 19 files changed, 214 insertions(+), 203 deletions(-) delete mode 100644 targets/console_helpers/include/console_helpers/PerformanceTimer.h delete mode 100644 targets/console_helpers/include/console_helpers/PlatformTime.h create mode 100644 targets/console_helpers/include/console_helpers/Timer.h delete mode 100644 targets/console_helpers/src/PerformanceTimer.cpp diff --git a/targets/app/common/Consoles_App.cpp b/targets/app/common/Consoles_App.cpp index 444f47ef8..694fd065f 100644 --- a/targets/app/common/Consoles_App.cpp +++ b/targets/app/common/Consoles_App.cpp @@ -81,7 +81,7 @@ #include "app/common/src/UI/All Platforms/ArchiveFile.h" #include "app/common/src/UI/Scenes/In-Game Menu Screens/UIScene_PauseMenu.h" #include "Minecraft_Macros.h" -#include "console_helpers/PlatformTime.h" +#include "console_helpers/Timer.h" #include "console_helpers/StringHelpers.h" #include "console_helpers/compression.h" #include "minecraft/client/User.h" @@ -203,7 +203,7 @@ CMinecraftApp::CMinecraftApp() { m_iTotalDLC = 0; m_iTotalDLCInstalled = 0; mfTrialPausedTime = 0.0f; - m_uiAutosaveTimer = 0; + m_uiAutosaveTimer = {}; memset(m_pszUniqueMapName, 0, 14); m_bNewDLCAvailable = false; @@ -4383,15 +4383,11 @@ void CMinecraftApp::HandleDLC(DLCPack* pack) { // Desc: Initializes the timer variables //------------------------------------------------------------------------------------- void CMinecraftApp::InitTime() { - // Get the frequency of the timer - auto freq = PlatformTime::QueryPerformanceFrequency(); - m_Time.fSecsPerTick = 1.0f / static_cast(freq); - // Save the start time - m_Time.qwTime = PlatformTime::QueryPerformanceCounter(); + m_Time.qwTime = time_util::clock::now(); // Zero out the elapsed and total time - m_Time.qwAppTime = 0; + m_Time.qwAppTime = {}; m_Time.fAppTime = 0.0f; m_Time.fElapsedTime = 0.0f; } @@ -4401,15 +4397,14 @@ void CMinecraftApp::InitTime() { // Desc: Updates the elapsed time since our last frame. //------------------------------------------------------------------------------------- void CMinecraftApp::UpdateTime() { - auto qwNewTime = PlatformTime::QueryPerformanceCounter(); + auto qwNewTime = time_util::clock::now(); auto qwDeltaTime = qwNewTime - m_Time.qwTime; m_Time.qwAppTime += qwDeltaTime; m_Time.qwTime = qwNewTime; - m_Time.fElapsedTime = m_Time.fSecsPerTick * static_cast(qwDeltaTime); - m_Time.fAppTime = - m_Time.fSecsPerTick * static_cast(m_Time.qwAppTime); + m_Time.fElapsedTime = std::chrono::duration(qwDeltaTime).count(); + m_Time.fAppTime = std::chrono::duration(m_Time.qwAppTime).count(); } bool CMinecraftApp::isXuidNotch(PlayerUID xuid) { @@ -7175,18 +7170,18 @@ int CMinecraftApp::GetDLCInfoTexturesOffersCount() { // AUTOSAVE void CMinecraftApp::SetAutosaveTimerTime(void) { + int settingValue = GetGameSettings(ProfileManager.GetPrimaryPad(), eGameSetting_Autosave); m_uiAutosaveTimer = - PlatformTime::GetTickCount() + - GetGameSettings(ProfileManager.GetPrimaryPad(), eGameSetting_Autosave) * - 1000 * 60 * 15; -} // value x 15 to get mins, x60 for secs + time_util::clock::now() + + std::chrono::minutes(settingValue * 15); +} // value x 15 to get mins bool CMinecraftApp::AutosaveDue(void) { - return (PlatformTime::GetTickCount() > m_uiAutosaveTimer); + return (time_util::clock::now() > m_uiAutosaveTimer); } -unsigned int CMinecraftApp::SecondsToAutosave() { - return (m_uiAutosaveTimer - PlatformTime::GetTickCount()) / 1000; +int64_t CMinecraftApp::SecondsToAutosave() { + return std::chrono::duration_cast(m_uiAutosaveTimer - time_util::clock::now()).count(); } void CMinecraftApp::SetTrialTimerStart(void) { diff --git a/targets/app/common/Consoles_App.h b/targets/app/common/Consoles_App.h index d8145afed..4a81e8ece 100644 --- a/targets/app/common/Consoles_App.h +++ b/targets/app/common/Consoles_App.h @@ -3,6 +3,7 @@ #include #include +#include "console_helpers/Timer.h" #include "platform/sdl2/Profile.h" #include "platform/sdl2/Storage.h" @@ -610,12 +611,11 @@ private: // Trial timer float m_fTrialTimerStart, mfTrialPausedTime; typedef struct TimeInfo { - std::int64_t qwTime; - std::int64_t qwAppTime; + time_util::time_point qwTime; + time_util::clock::duration qwAppTime{}; float fAppTime; float fElapsedTime; - float fSecsPerTick; } TIMEINFO; TimeInfo m_Time; @@ -749,10 +749,10 @@ public: public: void SetAutosaveTimerTime(void); bool AutosaveDue(void); - unsigned int SecondsToAutosave(); + int64_t SecondsToAutosave(); private: - unsigned int m_uiAutosaveTimer; + time_util::time_point m_uiAutosaveTimer; unsigned int m_uiOpacityCountDown[XUSER_MAX_COUNT]; // DLC diff --git a/targets/app/common/src/Tutorial/Tutorial.cpp b/targets/app/common/src/Tutorial/Tutorial.cpp index 4191f9852..4a97e30b9 100644 --- a/targets/app/common/src/Tutorial/Tutorial.cpp +++ b/targets/app/common/src/Tutorial/Tutorial.cpp @@ -25,7 +25,7 @@ #include "app/linux/Linux_App.h" #include "app/linux/Linux_UIController.h" #include "TutorialMessage.h" -#include "console_helpers/PlatformTime.h" +#include "console_helpers/Timer.h" #include "console_helpers/StringHelpers.h" #include "java/Class.h" #include "minecraft/client/Minecraft.h" @@ -397,14 +397,14 @@ Tutorial::Tutorial(int iPad, bool isFullTutorial /*= false*/) : m_iPad(iPad) { m_UIScene = nullptr; m_allowShow = true; m_bHasTickedOnce = false; - m_firstTickTime = 0; + m_firstTickTime = {}; // 4jcraft added, not initialized m_bSceneIsSplitscreen = false; m_lastMessage = nullptr; - lastMessageTime = 0; + lastMessageTime = {}; m_iTaskReminders = 0; m_lastMessageState = e_Tutorial_State_Gameplay; @@ -2079,10 +2079,10 @@ void Tutorial::tick() { // Don't do anything for the first 2 seconds so that the loading screen is // gone if (!m_bHasTickedOnce) { - int time = PlatformTime::GetTickCount(); - if (m_firstTickTime == 0) { - m_firstTickTime = time; - } else if (time - m_firstTickTime > 1500) { + auto now = time_util::clock::now(); + if (m_firstTickTime == time_util::time_point{}) { + m_firstTickTime = now; + } else if (now - m_firstTickTime > std::chrono::milliseconds(1500)) { m_bHasTickedOnce = true; } } @@ -2132,8 +2132,8 @@ void Tutorial::tick() { if (!m_allowShow) { if (currentTask[m_CurrentState] != nullptr && (!currentTask[m_CurrentState]->AllowFade() || - (lastMessageTime + m_iTutorialDisplayMessageTime) > - PlatformTime::GetTickCount())) { + (lastMessageTime + std::chrono::milliseconds(m_iTutorialDisplayMessageTime)) > + time_util::clock::now())) { uiTempDisabled = true; } ui.SetTutorialVisible(m_iPad, false); @@ -2153,8 +2153,8 @@ void Tutorial::tick() { if (ui.IsPauseMenuDisplayed(m_iPad)) { if (currentTask[m_CurrentState] != nullptr && (!currentTask[m_CurrentState]->AllowFade() || - (lastMessageTime + m_iTutorialDisplayMessageTime) > - PlatformTime::GetTickCount())) { + (lastMessageTime + std::chrono::milliseconds(m_iTutorialDisplayMessageTime)) > + time_util::clock::now())) { uiTempDisabled = true; } ui.SetTutorialVisible(m_iPad, false); @@ -2162,7 +2162,7 @@ void Tutorial::tick() { } if (uiTempDisabled) { ui.SetTutorialVisible(m_iPad, true); - lastMessageTime = PlatformTime::GetTickCount(); + lastMessageTime = time_util::clock::now(); uiTempDisabled = false; } @@ -2233,8 +2233,8 @@ void Tutorial::tick() { isCurrentTask = false; if ((!task->ShowMinimumTime() || (task->hasBeenActivated() && - (lastMessageTime + m_iTutorialMinimumDisplayMessageTime) < - PlatformTime::GetTickCount())) && + (lastMessageTime + std::chrono::milliseconds(m_iTutorialMinimumDisplayMessageTime)) < + time_util::clock::now())) && task->isCompleted()) { eTutorial_CompletionAction compAction = task->getCompletionAction(); @@ -2324,8 +2324,8 @@ void Tutorial::tick() { } if (task != nullptr && task->ShowMinimumTime() && task->hasBeenActivated() && - (lastMessageTime + m_iTutorialMinimumDisplayMessageTime) < - PlatformTime::GetTickCount()) { + (lastMessageTime + std::chrono::milliseconds(m_iTutorialMinimumDisplayMessageTime)) < + time_util::clock::now()) { task->setShownForMinimumTime(); if (!m_hintDisplayed) { @@ -2393,15 +2393,15 @@ void Tutorial::tick() { } } - if (m_hintDisplayed && (lastMessageTime + m_iTutorialDisplayMessageTime) < - PlatformTime::GetTickCount()) { + if (m_hintDisplayed && (lastMessageTime + std::chrono::milliseconds(m_iTutorialDisplayMessageTime)) < + time_util::clock::now()) { m_hintDisplayed = false; } if (currentFailedConstraint[m_CurrentState] == nullptr && currentTask[m_CurrentState] != nullptr && (m_iTaskReminders != 0) && - (lastMessageTime + (m_iTaskReminders * m_iTutorialReminderTime)) < - PlatformTime::GetTickCount()) { + (lastMessageTime + std::chrono::milliseconds(m_iTaskReminders * m_iTutorialReminderTime)) < + time_util::clock::now()) { // Reminder PopupMessageDetails* message = new PopupMessageDetails(); message->m_messageId = currentTask[m_CurrentState]->getDescriptionId(); @@ -2429,8 +2429,8 @@ bool Tutorial::setMessage(PopupMessageDetails* message) { m_lastMessageState == m_CurrentState && message->isSameContent(m_lastMessage) && (!message->m_isReminder || - ((lastMessageTime + m_iTutorialReminderTime) > - PlatformTime::GetTickCount() && + ((lastMessageTime + std::chrono::milliseconds(m_iTutorialReminderTime)) > + time_util::clock::now() && message->m_isReminder))) { delete message; return false; @@ -2441,7 +2441,7 @@ bool Tutorial::setMessage(PopupMessageDetails* message) { m_lastMessageState = m_CurrentState; if (!message->m_replaceCurrent) - lastMessageTime = PlatformTime::GetTickCount(); + lastMessageTime = time_util::clock::now(); std::wstring text; if (!message->m_messageString.empty()) { @@ -2501,7 +2501,7 @@ bool Tutorial::setMessage(PopupMessageDetails* message) { } else if ((m_lastMessage != nullptr && m_lastMessage->m_messageId != -1)) //&& (lastMessageTime + m_iTutorialReminderTime ) > - // PlatformTime::GetTickCount() ) + // time_util::tick_count32() ) { // This should cause the popup to dissappear TutorialPopupInfo popupInfo; @@ -2524,17 +2524,17 @@ bool Tutorial::setMessage(TutorialHint* hint, PopupMessageDetails* message) { app.GetGameSettings(m_iPad, eGameSetting_DisplayHUD)); bool messageShown = false; - std::uint32_t time = PlatformTime::GetTickCount(); + auto now = time_util::clock::now(); if (message != nullptr && (message->m_forceDisplay || hintsOn) && (!message->m_delay || ((m_hintDisplayed && - (time - m_lastHintDisplayedTime) > m_iTutorialHintDelayTime) || + (now - m_lastHintDisplayedTime) > std::chrono::milliseconds(m_iTutorialHintDelayTime)) || (!m_hintDisplayed && - (time - lastMessageTime) > m_iTutorialMinimumDisplayMessageTime)))) { + (now - lastMessageTime) > std::chrono::milliseconds(m_iTutorialMinimumDisplayMessageTime))))) { messageShown = setMessage(message); if (messageShown) { - m_lastHintDisplayedTime = time; + m_lastHintDisplayedTime = now; m_hintDisplayed = true; if (hint != nullptr) setHintCompleted(hint); } @@ -2559,8 +2559,8 @@ void Tutorial::showTutorialPopup(bool show) { if (!show) { if (currentTask[m_CurrentState] != nullptr && (!currentTask[m_CurrentState]->AllowFade() || - (lastMessageTime + m_iTutorialDisplayMessageTime) > - PlatformTime::GetTickCount())) { + (lastMessageTime + std::chrono::milliseconds(m_iTutorialDisplayMessageTime)) > + time_util::clock::now())) { uiTempDisabled = true; } ui.SetTutorialVisible(m_iPad, show); diff --git a/targets/app/common/src/Tutorial/Tutorial.h b/targets/app/common/src/Tutorial/Tutorial.h index c70f87725..453fc3029 100644 --- a/targets/app/common/src/Tutorial/Tutorial.h +++ b/targets/app/common/src/Tutorial/Tutorial.h @@ -1,5 +1,6 @@ #pragma once // using namespace std; +#include #include #include #include @@ -8,6 +9,8 @@ #include #include +#include "console_helpers/Timer.h" + #include "app/common/src/Tutorial/Constraints/TutorialConstraint.h" #include "app/common/src/Tutorial/Hints/TutorialHint.h" #include "app/common/src/Tutorial/Tasks/TutorialTask.h" @@ -87,7 +90,7 @@ private: bool m_bSceneIsSplitscreen; bool m_bHasTickedOnce; - int m_firstTickTime; + time_util::time_point m_firstTickTime; protected: std::unordered_map messages; @@ -108,8 +111,8 @@ protected: // D3DXVECTOR3 m_OriginalPosition; public: - std::uint32_t lastMessageTime; - std::uint32_t m_lastHintDisplayedTime; + time_util::time_point lastMessageTime; + time_util::time_point m_lastHintDisplayedTime; private: PopupMessageDetails* m_lastMessage; diff --git a/targets/app/common/src/Tutorial/TutorialMode.cpp b/targets/app/common/src/Tutorial/TutorialMode.cpp index 7dcdb68d4..0f936d73a 100644 --- a/targets/app/common/src/Tutorial/TutorialMode.cpp +++ b/targets/app/common/src/Tutorial/TutorialMode.cpp @@ -63,7 +63,7 @@ void TutorialMode::tick() { /* if( tutorial.m_allTutorialsComplete && (tutorial.lastMessageTime + - m_iTutorialDisplayMessageTime) < PlatformTime::GetTickCount() ) + m_iTutorialDisplayMessageTime) < time_util::tick_count32() ) { // Exit tutorial minecraft->gameMode = new SurvivalMode( this ); diff --git a/targets/app/common/src/UI/UIController.cpp b/targets/app/common/src/UI/UIController.cpp index 3085a107b..f0cbcaed7 100644 --- a/targets/app/common/src/UI/UIController.cpp +++ b/targets/app/common/src/UI/UIController.cpp @@ -39,8 +39,8 @@ #include "UIFontData.h" #include "XboxStubs.h" #include "console_helpers/C4JThread.h" -#include "console_helpers/PerformanceTimer.h" -#include "console_helpers/PlatformTime.h" +#include "console_helpers/Timer.h" + #include "console_helpers/StringHelpers.h" #include "java/System.h" @@ -235,7 +235,7 @@ UIController::UIController() { m_bMenuToBeClosed[i] = false; for (unsigned int key = 0; key <= ACTION_MAX_MENU; ++key) { - m_actionRepeatTimer[i][key] = 0; + m_actionRepeatTimer[i][key] = {}; } } @@ -627,7 +627,6 @@ void UIController::ReloadSkin() { m_reloadSkinThread = new C4JThread(reloadSkinThreadProc, (void*)this, "Reload skin thread"); - m_reloadSkinThread->setProcessor(CPU_CORE_UI_SCENE); // Navigate to the timer scene so that we can display something while the // loading is happening @@ -776,19 +775,19 @@ void UIController::handleKeyPress(unsigned int iPad, unsigned int key) { if (pressed) { // Start repeat timer m_actionRepeatTimer[iPad][key] = - PlatformTime::GetTickCount() + UI_REPEAT_KEY_DELAY_MS; + time_util::clock::now() + std::chrono::milliseconds(UI_REPEAT_KEY_DELAY_MS); } else if (released) { // Stop repeat timer - m_actionRepeatTimer[iPad][key] = 0; + m_actionRepeatTimer[iPad][key] = {}; } else if (down) { // Check is enough time has elapsed to be a repeat key - std::uint32_t currentTime = PlatformTime::GetTickCount(); - if (m_actionRepeatTimer[iPad][key] > 0 && - currentTime > m_actionRepeatTimer[iPad][key]) { + auto now = time_util::clock::now(); + if (m_actionRepeatTimer[iPad][key] != time_util::time_point{} && + now > m_actionRepeatTimer[iPad][key]) { repeat = true; pressed = true; m_actionRepeatTimer[iPad][key] = - currentTime + UI_REPEAT_KEY_REPEAT_RATE_MS; + now + std::chrono::milliseconds(UI_REPEAT_KEY_REPEAT_RATE_MS); } } @@ -1275,7 +1274,7 @@ bool UIController::NavigateToScene(int iPad, EUIScene scene, void* initData, } } - PerformanceTimer timer; + time_util::Timer timer; bool success; { @@ -1287,7 +1286,8 @@ bool UIController::NavigateToScene(int iPad, EUIScene scene, void* initData, setFullscreenMenuDisplayed(true); } - timer.PrintElapsedTime(L"Navigate to scene"); + std::println(stderr, "TIMER: Navigate to scene: Elapsed time {:.6f}", + timer.elapsed_seconds()); return success; // return true; @@ -1404,9 +1404,8 @@ UIScene* UIController::GetTopScene(int iPad, EUILayer layer, EUIGroup group) { size_t UIController::RegisterForCallbackId(UIScene* scene) { std::lock_guard lock(m_registeredCallbackScenesCS); - size_t newId = PlatformTime::GetTickCount(); - newId &= 0xFFFFFF; // Chop off the top byte, we don't need any more - // accuracy than that + static std::atomic s_nextId{1}; + size_t newId = s_nextId.fetch_add(1, std::memory_order_relaxed) & 0xFFFFFF; newId |= (scene->getSceneType() << 24); // Add in the scene's type to help keep this unique m_registeredCallbackScenes[newId] = scene; diff --git a/targets/app/common/src/UI/UIController.h b/targets/app/common/src/UI/UIController.h index 8db798a0a..7f4a008e6 100644 --- a/targets/app/common/src/UI/UIController.h +++ b/targets/app/common/src/UI/UIController.h @@ -8,6 +8,8 @@ #include #include +#include "console_helpers/Timer.h" + #ifdef __linux__ #include "app/linux/Iggy/include/iggy.h" #ifndef _ENABLEIGGY @@ -60,7 +62,7 @@ private: 300; // How long from press until the first repeat static const int UI_REPEAT_KEY_REPEAT_RATE_MS = 100; // How long in between repeats - std::uint32_t m_actionRepeatTimer[XUSER_MAX_COUNT][ACTION_MAX_MENU + 1]; + time_util::time_point m_actionRepeatTimer[XUSER_MAX_COUNT][ACTION_MAX_MENU + 1]; float m_fScreenWidth; float m_fScreenHeight; diff --git a/targets/console_helpers/include/console_helpers/PerformanceTimer.h b/targets/console_helpers/include/console_helpers/PerformanceTimer.h deleted file mode 100644 index fda491a6a..000000000 --- a/targets/console_helpers/include/console_helpers/PerformanceTimer.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include -#include - -class PerformanceTimer { -private: - std::chrono::steady_clock::time_point m_startTime; - -public: - PerformanceTimer(); - void Reset(); - void PrintElapsedTime(const std::wstring& description); -}; diff --git a/targets/console_helpers/include/console_helpers/PlatformTime.h b/targets/console_helpers/include/console_helpers/PlatformTime.h deleted file mode 100644 index 8246d38dd..000000000 --- a/targets/console_helpers/include/console_helpers/PlatformTime.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -#include -#include - -// Portable replacements for Win32 time APIs. -// GetTickCount() → PlatformTime::GetTickCount() -// QueryPerformanceCounter() → PlatformTime::QueryPerformanceCounter() -// QueryPerformanceFrequency() → PlatformTime::QueryPerformanceFrequency() - -namespace PlatformTime { - -// Returns milliseconds since an unspecified epoch (like Win32 GetTickCount). -inline std::uint32_t GetTickCount() { - auto now = std::chrono::steady_clock::now().time_since_epoch(); - return static_cast( - std::chrono::duration_cast(now).count()); -} - -// High-resolution counter value (like Win32 QueryPerformanceCounter). -// Returns a count in ticks of steady_clock. -inline std::int64_t QueryPerformanceCounter() { - return std::chrono::steady_clock::now().time_since_epoch().count(); -} - -// Ticks per second for the high-resolution counter. -inline std::int64_t QueryPerformanceFrequency() { - return static_cast(std::chrono::steady_clock::period::den) / - static_cast(std::chrono::steady_clock::period::num); -} - -// Elapsed seconds between two counter values. -inline double ElapsedSeconds(std::int64_t start, std::int64_t end) { - return static_cast(end - start) / - static_cast(QueryPerformanceFrequency()); -} - -} // namespace PlatformTime diff --git a/targets/console_helpers/include/console_helpers/Timer.h b/targets/console_helpers/include/console_helpers/Timer.h new file mode 100644 index 000000000..71ca5e398 --- /dev/null +++ b/targets/console_helpers/include/console_helpers/Timer.h @@ -0,0 +1,107 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace time_util { + +using clock = std::chrono::steady_clock; +using time_point = clock::time_point; + +template +concept Duration = requires { typename T::rep; typename T::period; }; + +namespace detail { + +[[nodiscard]] constexpr auto base_name(std::string_view path) noexcept + -> std::string_view { + const auto pos = path.find_last_of("/\\"); + return pos == std::string_view::npos ? path : path.substr(pos + 1); +} + +} // namespace detail + +class Timer final { +public: + Timer() noexcept : start_(clock::now()) {} + + void reset() noexcept { start_ = clock::now(); } + + [[nodiscard]] auto elapsed() const noexcept -> clock::duration { + return clock::now() - start_; + } + + template > + [[nodiscard]] auto elapsed_as() const noexcept -> D { + return std::chrono::duration_cast(elapsed()); + } + + [[nodiscard]] auto elapsed_seconds() const noexcept -> double { + return elapsed_as>().count(); + } + + [[nodiscard]] auto elapsed_millis() const noexcept -> double { + return elapsed_as>().count(); + } + +private: + time_point start_; +}; + +class [[nodiscard]] ScopedTimer final { +public: + explicit ScopedTimer( + std::string_view name, + std::source_location where = std::source_location::current()) + : name_(name), + file_(detail::base_name(where.file_name())), + line_(where.line()) {} + + template + ScopedTimer( + std::string_view name, + D min_duration_to_log, + std::source_location where = std::source_location::current()) + : name_(name), + file_(detail::base_name(where.file_name())), + line_(where.line()), + min_duration_to_log_( + std::chrono::duration_cast(min_duration_to_log)) { + } + + ~ScopedTimer() noexcept { + const auto elapsed = timer_.elapsed(); + if (elapsed < min_duration_to_log_) return; + + const auto ms = + std::chrono::duration(elapsed).count(); + + try { + name_.empty() + ? std::println(stderr, "[TIMER] {:.3f} ms ({}:{})", + ms, file_, line_) + : std::println(stderr, "[TIMER] {} - {:.3f} ms ({}:{})", + name_, ms, file_, line_); + } catch (...) { + std::fprintf(stderr, "[TIMER] %.3f ms\n", ms); + } + } + + ScopedTimer(const ScopedTimer&) = delete; + auto operator=(const ScopedTimer&) -> ScopedTimer& = delete; + ScopedTimer(ScopedTimer&&) = delete; + auto operator=(ScopedTimer&&) -> ScopedTimer& = delete; + +private: + std::string_view name_; + std::string_view file_; + std::uint_least32_t line_; + clock::duration min_duration_to_log_{clock::duration::zero()}; + Timer timer_; +}; + +} // namespace time_util diff --git a/targets/console_helpers/meson.build b/targets/console_helpers/meson.build index 24e08671a..7c2e09ae0 100644 --- a/targets/console_helpers/meson.build +++ b/targets/console_helpers/meson.build @@ -1,8 +1,6 @@ console_helpers_sources = files( 'src/C4JThread.cpp', - 'src/PerformanceTimer.cpp', 'src/StringHelpers.cpp', - 'src/ThreadName.cpp', 'src/compression.cpp', ) diff --git a/targets/console_helpers/src/PerformanceTimer.cpp b/targets/console_helpers/src/PerformanceTimer.cpp deleted file mode 100644 index 615b12f19..000000000 --- a/targets/console_helpers/src/PerformanceTimer.cpp +++ /dev/null @@ -1,21 +0,0 @@ - -#include "console_helpers/PerformanceTimer.h" - -#include - -#include -#include - -PerformanceTimer::PerformanceTimer() { Reset(); } - -void PerformanceTimer::Reset() { - m_startTime = std::chrono::steady_clock::now(); -} - -void PerformanceTimer::PrintElapsedTime(const std::wstring& description) { - const std::chrono::duration elapsedTime = - std::chrono::steady_clock::now() - m_startTime; - - fprintf(stderr, "TIMER: %ls: Elapsed time %f\n", description.c_str(), - elapsedTime.count()); -} diff --git a/targets/minecraft/client/Minecraft.cpp b/targets/minecraft/client/Minecraft.cpp index 4304a7d61..52f0586f6 100644 --- a/targets/minecraft/client/Minecraft.cpp +++ b/targets/minecraft/client/Minecraft.cpp @@ -271,7 +271,6 @@ Minecraft::Minecraft(Component* mouseComponent, Canvas* parent, levelTickEventQueue = new C4JThread::EventQueue(levelTickUpdateFunc, levelTickThreadInitFunc, "LevelTick_EventQueuePoll"); - levelTickEventQueue->setProcessor(3); levelTickEventQueue->setPriority(C4JThread::ThreadPriority::Normal); #endif } @@ -1146,7 +1145,7 @@ void Minecraft::run_middle() { } #endif } else { - unsigned int uiTimeToAutosave = + int64_t uiTimeToAutosave = app.SecondsToAutosave(); if (uiTimeToAutosave < 6) { @@ -3960,7 +3959,7 @@ void Minecraft::fileDownloaded(const std::wstring& name, File* file) { std::wstring Minecraft::gatherStats1() { // return levelRenderer->gatherStats1(); return L"Time to autosave: " + - _toString(app.SecondsToAutosave()) + L"s"; + _toString(app.SecondsToAutosave()) + L"s"; } std::wstring Minecraft::gatherStats2() { diff --git a/targets/minecraft/client/multiplayer/ClientConnection.cpp b/targets/minecraft/client/multiplayer/ClientConnection.cpp index befc3994d..844cf49f9 100644 --- a/targets/minecraft/client/multiplayer/ClientConnection.cpp +++ b/targets/minecraft/client/multiplayer/ClientConnection.cpp @@ -35,7 +35,7 @@ #include "app/linux/Stubs/winapi_stubs.h" #include "MultiPlayerLevel.h" #include "ReceivingLevelScreen.h" -#include "console_helpers/PlatformTime.h" +#include "console_helpers/Timer.h" #include "console_helpers/StringHelpers.h" #include "java/Class.h" #include "java/InputOutputStream/ByteArrayInputStream.h" @@ -3575,8 +3575,8 @@ void ClientConnection::checkDeferredEntityLinkPackets(int newEntityId) { bool remove = false; // Only consider recently deferred packets - int tickInterval = - PlatformTime::GetTickCount() - deferred->m_recievedTick; + auto tickInterval = + std::chrono::duration_cast(time_util::clock::now() - deferred->m_recievedTick).count(); if (tickInterval < MAX_ENTITY_LINK_DEFERRAL_INTERVAL) { // Note: we assume it's the destination entity if (deferred->m_packet->destId == newEntityId) { @@ -3599,6 +3599,6 @@ void ClientConnection::checkDeferredEntityLinkPackets(int newEntityId) { ClientConnection::DeferredEntityLinkPacket::DeferredEntityLinkPacket( std::shared_ptr packet) { - m_recievedTick = PlatformTime::GetTickCount(); + m_recievedTick = time_util::clock::now(); m_packet = packet; } diff --git a/targets/minecraft/client/multiplayer/ClientConnection.h b/targets/minecraft/client/multiplayer/ClientConnection.h index 2a873397c..ebd7b7fb1 100644 --- a/targets/minecraft/client/multiplayer/ClientConnection.h +++ b/targets/minecraft/client/multiplayer/ClientConnection.h @@ -5,6 +5,7 @@ #include #include +#include "console_helpers/Timer.h" #include "platform/sdl2/Storage.h" #include "minecraft/network/Connection.h" @@ -216,7 +217,7 @@ private: // 4J: Entity link packet deferred class DeferredEntityLinkPacket { public: - uint32_t m_recievedTick; + time_util::time_point m_recievedTick; std::shared_ptr m_packet; DeferredEntityLinkPacket(std::shared_ptr packet); diff --git a/targets/minecraft/server/MinecraftServer.cpp b/targets/minecraft/server/MinecraftServer.cpp index 3a0466b3f..c33e88c4c 100644 --- a/targets/minecraft/server/MinecraftServer.cpp +++ b/targets/minecraft/server/MinecraftServer.cpp @@ -23,7 +23,7 @@ #include "app/linux/Linux_App.h" #include "PlayerList.h" #include "Settings.h" -#include "console_helpers/PlatformTime.h" +#include "console_helpers/Timer.h" #include "java/Class.h" #include "java/File.h" #include "java/InputOutputStream/DataOutputStream.h" @@ -102,7 +102,7 @@ int64_t MinecraftServer::s_tickStartTime = 0; std::vector MinecraftServer::s_sentTo; #else int MinecraftServer::s_slowQueuePlayerIndex = 0; -int MinecraftServer::s_slowQueueLastTime = 0; +time_util::time_point MinecraftServer::s_slowQueueLastTime = {}; bool MinecraftServer::s_slowQueuePacketSent = false; #endif @@ -528,7 +528,6 @@ bool MinecraftServer::loadLevel(LevelStorageSource* storageSource, new C4JThread(runPostUpdate, this, "Post processing", 256 * 1024); m_postUpdateTerminate = false; - m_postUpdateThread->setProcessor(CPU_CORE_POST_PROCESSING); m_postUpdateThread->setPriority(C4JThread::ThreadPriority::AboveNormal); m_postUpdateThread->run(); @@ -858,10 +857,7 @@ void MinecraftServer::saveGameRules() { void MinecraftServer::Suspend() { m_suspending = true; - // Get the frequency of the timer - float fElapsedTime = 0.0f; - // Save the start time - auto qwTime = PlatformTime::QueryPerformanceCounter(); + time_util::Timer timer; if (m_bLoaded && (!StorageManager.GetSaveDisabled())) { if (players != nullptr) { players->saveAll(nullptr); @@ -880,13 +876,10 @@ void MinecraftServer::Suspend() { levels[0]->saveToDisc(nullptr, true); } } - auto qwNewTime = PlatformTime::QueryPerformanceCounter(); - - fElapsedTime = - static_cast(PlatformTime::ElapsedSeconds(qwTime, qwNewTime)); m_suspending = false; - app.DebugPrintf("Suspend server: Elapsed time %f\n", fElapsedTime); + app.DebugPrintf("Suspend server: Elapsed time %f\n", + static_cast(timer.elapsed_seconds())); } bool MinecraftServer::IsSuspending() { return m_suspending; } @@ -1644,9 +1637,9 @@ void MinecraftServer::chunkPacketManagement_PostTick() {} bool MinecraftServer::chunkPacketManagement_CanSendTo(INetworkPlayer* player) { if (player == nullptr) return false; - int time = PlatformTime::GetTickCount(); + auto now = time_util::clock::now(); if (player->GetSessionIndex() == s_slowQueuePlayerIndex && - (time - s_slowQueueLastTime) > MINECRAFT_SERVER_SLOW_QUEUE_DELAY) { + (now - s_slowQueueLastTime) > std::chrono::milliseconds(MINECRAFT_SERVER_SLOW_QUEUE_DELAY)) { // app.DebugPrintf("Slow queue OK for player #%d\n", // player->GetSessionIndex()); return true; @@ -1664,15 +1657,15 @@ void MinecraftServer::chunkPacketManagement_PreTick() {} void MinecraftServer::chunkPacketManagement_PostTick() { // 4J Ensure that the slow queue owner keeps cycling if it's not been used // in a while - int time = PlatformTime::GetTickCount(); - if ((s_slowQueuePacketSent) || ((time - s_slowQueueLastTime) > - (2 * MINECRAFT_SERVER_SLOW_QUEUE_DELAY))) { + auto now = time_util::clock::now(); + if ((s_slowQueuePacketSent) || ((now - s_slowQueueLastTime) > + std::chrono::milliseconds(2 * MINECRAFT_SERVER_SLOW_QUEUE_DELAY))) { // app.DebugPrintf("Considering cycling: (%d) %d - %d -> %d //> %d\n",s_slowQueuePacketSent, time, s_slowQueueLastTime, (time - // s_slowQueueLastTime), (2*MINECRAFT_SERVER_SLOW_QUEUE_DELAY)); MinecraftServer::cycleSlowQueueIndex(); s_slowQueuePacketSent = false; - s_slowQueueLastTime = time; + s_slowQueueLastTime = now; } // else // { diff --git a/targets/minecraft/server/MinecraftServer.h b/targets/minecraft/server/MinecraftServer.h index 099a9b464..841cd3277 100644 --- a/targets/minecraft/server/MinecraftServer.h +++ b/targets/minecraft/server/MinecraftServer.h @@ -8,6 +8,7 @@ #include "ConsoleInputSource.h" #include "console_helpers/C4JThread.h" +#include "console_helpers/Timer.h" #include "minecraft/SharedConstants.h" #include "minecraft/world/level/chunk/ChunkSource.h" #include "minecraft/world/level/storage/ConsoleSaveFileIO/FileHeader.h" @@ -293,7 +294,7 @@ private: static const int MAX_TICK_TIME_FOR_PACKET_SENDS = 35; #else static int s_slowQueuePlayerIndex; - static int s_slowQueueLastTime; + static time_util::time_point s_slowQueueLastTime; static bool s_slowQueuePacketSent; #endif diff --git a/targets/minecraft/world/level/levelgen/RandomLevelSource.cpp b/targets/minecraft/world/level/levelgen/RandomLevelSource.cpp index db69d0e96..8428d2db4 100644 --- a/targets/minecraft/world/level/levelgen/RandomLevelSource.cpp +++ b/targets/minecraft/world/level/levelgen/RandomLevelSource.cpp @@ -7,7 +7,7 @@ #include "app/common/src/GameRules/LevelGeneration/LevelGenerationOptions.h" #include "app/linux/Linux_App.h" -#include "console_helpers/PlatformTime.h" +#include "console_helpers/Timer.h" #include "java/Random.h" #include "minecraft/util/Mth.h" #include "minecraft/world/entity/MobCategory.h" @@ -102,8 +102,8 @@ RandomLevelSource::~RandomLevelSource() { } int g_numPrepareHeightCalls = 0; -std::int64_t g_totalPrepareHeightsTime = 0; -std::int64_t g_averagePrepareHeightsTime = 0; +time_util::clock::duration g_totalPrepareHeightsTime{}; +time_util::clock::duration g_averagePrepareHeightsTime{}; #if defined(_LARGE_WORLDS) @@ -243,7 +243,6 @@ float RandomLevelSource::getHeightFalloff(int xxx, int zzz, int* pEMin) { void RandomLevelSource::prepareHeights(int xOffs, int zOffs, std::vector& blocks) { - std::int64_t startTime; int xChunks = 16 / CHUNK_WIDTH; int yChunks = Level::genDepth / CHUNK_HEIGHT; int waterHeight = level->seaLevel; @@ -265,7 +264,7 @@ void RandomLevelSource::prepareHeights(int xOffs, int zOffs, buffer = getHeights(buffer, xOffs * xChunks, 0, zOffs * xChunks, xSize, ySize, zSize, biomes); - startTime = PlatformTime::QueryPerformanceCounter(); + time_util::Timer timer; for (int xc = 0; xc < xChunks; xc++) { for (int zc = 0; zc < xChunks; zc++) { for (int yc = 0; yc < yChunks; yc++) { @@ -377,10 +376,8 @@ void RandomLevelSource::prepareHeights(int xOffs, int zOffs, } } } - auto endTime = PlatformTime::QueryPerformanceCounter(); - auto timeInFunc = endTime - startTime; g_numPrepareHeightCalls++; - g_totalPrepareHeightsTime += timeInFunc; + g_totalPrepareHeightsTime += timer.elapsed(); g_averagePrepareHeightsTime = g_totalPrepareHeightsTime / g_numPrepareHeightCalls; } diff --git a/targets/minecraft/world/level/storage/ConsoleSaveFileIO/ConsoleSaveFileSplit.cpp b/targets/minecraft/world/level/storage/ConsoleSaveFileIO/ConsoleSaveFileSplit.cpp index ab78f75eb..a88230b8d 100644 --- a/targets/minecraft/world/level/storage/ConsoleSaveFileIO/ConsoleSaveFileSplit.cpp +++ b/targets/minecraft/world/level/storage/ConsoleSaveFileIO/ConsoleSaveFileSplit.cpp @@ -19,7 +19,7 @@ #include "app/common/src/GameRules/LevelGeneration/LevelGenerationOptions.h" #include "app/linux/Linux_App.h" #include "app/linux/Stubs/winapi_stubs.h" -#include "console_helpers/PlatformTime.h" +#include "console_helpers/Timer.h" #include "console_helpers/StringHelpers.h" #include "console_helpers/compression.h" #include "java/File.h" @@ -1282,10 +1282,7 @@ void ConsoleSaveFileSplit::Flush(bool autosave, bool updateThumbnail) { m_autosave = autosave; if (!m_autosave) processSubfilesForWrite(); - // Get the frequency of the timer - auto qwTime = PlatformTime::QueryPerformanceCounter(); - auto qwNewTime = qwTime; - float fElapsedTime = 0.0f; + time_util::Timer timer; unsigned int fileSize = header.GetFileSize(); @@ -1311,16 +1308,12 @@ void ConsoleSaveFileSplit::Flush(bool autosave, bool updateThumbnail) { compLength = 0; // Pre-calculate the buffer size required for the compressed data - // Save the start time - qwTime = PlatformTime::QueryPerformanceCounter(); + timer.reset(); Compression::getCompression()->Compress(nullptr, &compLength, pvSaveMem, fileSize); - qwNewTime = PlatformTime::QueryPerformanceCounter(); - fElapsedTime = - static_cast(PlatformTime::ElapsedSeconds(qwTime, qwNewTime)); - - app.DebugPrintf("Check buffer size: Elapsed time %f\n", fElapsedTime); + app.DebugPrintf("Check buffer size: Elapsed time %f\n", + static_cast(timer.elapsed_seconds())); // We add 4 bytes to the start so that we can signal compressed data // And another 4 bytes to store the decompressed data size @@ -1332,16 +1325,12 @@ void ConsoleSaveFileSplit::Flush(bool autosave, bool updateThumbnail) { if (compData != nullptr) { // Re-compress all save data before we save it to disk - // Save the start time - qwTime = PlatformTime::QueryPerformanceCounter(); + timer.reset(); Compression::getCompression()->Compress(compData + 8, &compLength, pvSaveMem, fileSize); - qwNewTime = PlatformTime::QueryPerformanceCounter(); - fElapsedTime = - static_cast(PlatformTime::ElapsedSeconds(qwTime, qwNewTime)); - - app.DebugPrintf("Compress: Elapsed time %f\n", fElapsedTime); + app.DebugPrintf("Compress: Elapsed time %f\n", + static_cast(timer.elapsed_seconds())); memset(compData, 0, 8); int saveVer = 0;