From 272378911d49c5ff888bd26c3054c866ca6b9697 Mon Sep 17 00:00:00 2001 From: "C. J. Howard" Date: Thu, 9 Feb 2023 02:36:11 +0800 Subject: [PATCH] Replace performance sampler with moving average --- CMakeLists.txt | 1 + src/debug/performance-sampler.cpp | 66 -------------- src/debug/performance-sampler.hpp | 69 --------------- src/game/context.hpp | 10 ++- src/game/settings.hpp | 2 +- src/game/state/boot.cpp | 7 +- src/math/moving-average.hpp | 138 ++++++++++++++++++++++++++++++ 7 files changed, 149 insertions(+), 144 deletions(-) delete mode 100644 src/debug/performance-sampler.cpp delete mode 100644 src/debug/performance-sampler.hpp create mode 100644 src/math/moving-average.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index baf682a..c9deac5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,6 @@ cmake_minimum_required(VERSION 3.25) + option(APPLICATION_NAME "Application name" "Antkeeper") option(APPLICATION_VERSION "Application version string" "0.0.0") option(APPLICATION_AUTHOR "Application author" "C. J. Howard") diff --git a/src/debug/performance-sampler.cpp b/src/debug/performance-sampler.cpp deleted file mode 100644 index 28d908c..0000000 --- a/src/debug/performance-sampler.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2023 Christopher J. Howard - * - * This file is part of Antkeeper source code. - * - * Antkeeper source code 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 3 of the License, or - * (at your option) any later version. - * - * Antkeeper source code 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 Antkeeper source code. If not, see . - */ - -#include "performance-sampler.hpp" -#include -#include - -namespace debug { - -performance_sampler::performance_sampler(): - sample_size(1), - sample_index(0) -{} - -void performance_sampler::sample(double duration) -{ - if (samples.size() < sample_size) - { - samples.push_back(duration); - } - else - { - samples[sample_index] = duration; - sample_index = (sample_index + 1) % samples.size(); - } -} - -void performance_sampler::reset() -{ - samples.clear(); - sample_index = 0; -} - -void performance_sampler::set_sample_size(std::size_t size) -{ - sample_size = size; - if (samples.size() > size) - { - samples.resize(size); - sample_index = 0; - } -} - -double performance_sampler::mean_frame_duration() const -{ - return std::accumulate(samples.begin(), samples.end(), 0.0) / static_cast(samples.size()); -} - -} // namespace debug - diff --git a/src/debug/performance-sampler.hpp b/src/debug/performance-sampler.hpp deleted file mode 100644 index 5614b5e..0000000 --- a/src/debug/performance-sampler.hpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2023 Christopher J. Howard - * - * This file is part of Antkeeper source code. - * - * Antkeeper source code 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 3 of the License, or - * (at your option) any later version. - * - * Antkeeper source code 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 Antkeeper source code. If not, see . - */ - -#ifndef ANTKEEPER_DEBUG_PERFORMANCE_SAMPLER_HPP -#define ANTKEEPER_DEBUG_PERFORMANCE_SAMPLER_HPP - -#include -#include - -namespace debug { - -/** - * Measures a rolling mean frame duration. - */ -class performance_sampler -{ -public: - /// Creates a performance sampler. - performance_sampler(); - - /** - * Adds a frame duration to the sample. - * - * @param duration Duration of the frame. - */ - void sample(double duration); - - /** - * Resets the sampling process. - */ - void reset(); - - /** - * Sets the number of frames in a sample. - * - * @param size Number of frames in a sample. - */ - void set_sample_size(std::size_t size); - - /** - * Returns the mean frame duration. - */ - [[nodiscard]] double mean_frame_duration() const; - -private: - std::vector samples; - std::size_t sample_size; - std::size_t sample_index; -}; - -} // namespace debug - -#endif // ANTKEEPER_DEBUG_PERFORMANCE_SAMPLER_HPP diff --git a/src/game/context.hpp b/src/game/context.hpp index 7758a1a..c2fb85c 100644 --- a/src/game/context.hpp +++ b/src/game/context.hpp @@ -23,7 +23,6 @@ #include "animation/tween.hpp" #include "app/input-manager.hpp" #include "app/window-manager.hpp" -#include "debug/performance-sampler.hpp" #include "entity/id.hpp" #include "entity/registry.hpp" #include "event/subscription.hpp" @@ -51,6 +50,7 @@ #include "utility/dict.hpp" #include "utility/fundamental-types.hpp" #include "utility/state-machine.hpp" +#include "math/moving-average.hpp" #include #include #include @@ -186,13 +186,15 @@ struct context input::control menu_modifier_control; std::forward_list> menu_control_subscriptions; + // Debugging + math::moving_average average_frame_time; + debug::cli* cli; + // Hierarchichal state machine hsm::state_machine state_machine; std::function resume_callback; - // Debugging - debug::performance_sampler performance_sampler; - debug::cli* cli; + // Queue for scheduling "next frame" function calls std::queue> function_queue; diff --git a/src/game/settings.hpp b/src/game/settings.hpp index c68887c..8e441e6 100644 --- a/src/game/settings.hpp +++ b/src/game/settings.hpp @@ -45,7 +45,7 @@ bool read_or_write_setting(game::context& ctx, std::uint32_t key, T& value) { value = std::any_cast(i->second); } - catch (const std::bad_any_cast& e) + catch (const std::bad_any_cast&) { debug::log::error("Setting type mismatch ({:x}={})", key, value); i->second = value; diff --git a/src/game/state/boot.cpp b/src/game/state/boot.cpp index cfa44a1..fce973a 100644 --- a/src/game/state/boot.cpp +++ b/src/game/state/boot.cpp @@ -1216,9 +1216,6 @@ void boot::setup_ui() void boot::setup_debugging() { - // Setup performance sampling - ctx.performance_sampler.set_sample_size(15); - ctx.cli = new debug::cli(); //debug::log::info(ctx.cli->interpret("echo hi 123")); } @@ -1313,12 +1310,14 @@ void boot::loop() ctx.loop.tick(); // Sample frame duration - ctx.performance_sampler.sample(ctx.loop.get_frame_duration()); + ctx.average_frame_time(static_cast(ctx.loop.get_frame_duration())); } // Exit all active game states while (!ctx.state_machine.empty()) + { ctx.state_machine.pop(); + } } void boot::shutdown_audio() diff --git a/src/math/moving-average.hpp b/src/math/moving-average.hpp new file mode 100644 index 0000000..370b99b --- /dev/null +++ b/src/math/moving-average.hpp @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2023 Christopher J. Howard + * + * This file is part of Antkeeper source code. + * + * Antkeeper source code 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 3 of the License, or + * (at your option) any later version. + * + * Antkeeper source code 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 Antkeeper source code. If not, see . + */ + +#ifndef ANTKEEPER_MATH_MOVING_AVERAGE_HPP +#define ANTKEEPER_MATH_MOVING_AVERAGE_HPP + +#include +#include +#include + +namespace math { + +/** + * Calculates a moving average. + * + * @tparam T Value type. + * @tparam N Sample capacity. + */ +template +class moving_average +{ +public: + /// Type of value to average. + typedef T value_type; + + /// Constructs a moving average + moving_average(): + m_sample_index{0}, + m_sum{0}, + m_average{0} + {} + + /** + * Adds a sample to the moving average. If the moving average has reached its sample capacity, the oldest sample will be discarded. + * + * @param value Sample value. + * + * @return Current average value. + */ + value_type operator()(value_type value) noexcept + { + m_sum += value; + if (m_sample_index < N) + { + m_samples[m_sample_index] = value; + ++m_sample_index; + m_average = m_sum / static_cast(m_sample_index); + } + else + { + value_type& sample = m_samples[m_sample_index % N]; + m_sum -= sample; + sample = value; + ++m_sample_index; + m_average = m_sum / static_cast(N); + } + + return m_average; + } + + /** + * Resets the moving average. + */ + void reset() noexcept + { + m_sample_index = 0; + m_sum = value_type{0}; + m_average = value_type{0}; + } + + /// Returns a pointer to the sample data. + [[nodiscard]] inline constexpr value_type* data() const noexcept + { + return m_samples.data(); + } + + /// Returns the current moving average value. + [[nodiscard]] inline value_type average() const noexcept + { + return m_average; + } + + ///Returns the sum of all current samples. + [[nodiscard]] inline value_type sum() const noexcept + { + return m_sum; + } + + /// Returns the current number of samples. + [[nodiscard]] inline std::size_t size() const noexcept + { + return std::min(m_sample_index, N); + } + + /// Returns the maximum number of samples. + [[nodiscard]] inline constexpr std::size_t capacity() const noexcept + { + return N; + } + + /// Return `true` if there are currently no samples in the average, `false` otherwise. + [[nodiscard]] inline constexpr bool empty() const noexcept + { + return !m_sample_index; + } + + /// Return `true` if the number of samples in the average has reached its capacity, `false` otherwise. + [[nodiscard]] inline constexpr bool full() const noexcept + { + return m_sample_index >= N; + } + +private: + std::size_t m_sample_index; + value_type m_samples[N]; + value_type m_sum; + value_type m_average; +}; + +} // namespace math + +#endif // ANTKEEPER_MATH_MOVING_AVERAGE_HPP