From cbc1483537c56994c3434db8f4ebed073cc7502d Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Tue, 23 Jan 2024 23:58:06 +0100 Subject: [PATCH 01/10] add profiling code --- include/Profiling.h | 52 +++++++++++++++++++++++++++++++++++++++++++++ src/Profiling.cpp | 41 +++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 include/Profiling.h create mode 100644 src/Profiling.cpp diff --git a/include/Profiling.h b/include/Profiling.h new file mode 100644 index 0000000..21b0784 --- /dev/null +++ b/include/Profiling.h @@ -0,0 +1,52 @@ +#pragma once + +#include +#include +#include +#include + +namespace prof { + +using Duration = std::chrono::duration; +using TimePoint = std::chrono::high_resolution_clock::time_point; + +/// Returns the current time. +TimePoint now(); + +/// Returns a sub-millisecond resolution duration between start and end. +Duration duration(const TimePoint& start, const TimePoint& end); + +/// Calculates and stores the moving average over K samples of execution time data +/// for some single unit of code. Threadsafe. +struct UnitExecutionTime { + UnitExecutionTime(); + + /// Adds a sample to the collection, overriding the oldest sample if needed. + void add_sample(const Duration& dur); + + /// Calculates the average duration over the `measurement_count()` measurements. + Duration average_duration() const; + + /// Returns the number of elements the moving average is calculated over. + size_t measurement_count(); + +private: + boost::synchronized_value> m_measurements; +}; + +/// Holds profiles for multiple units by name. Threadsafe. +struct UnitProfileCollection { + /// Adds a sample to the collection, overriding the oldest sample if needed. + void add_sample(const std::string& unit, const Duration& duration); + + /// Calculates the average duration over the `measurement_count()` measurements. + Duration average_duration(const std::string& unit); + + /// Returns the number of elements the moving average is calculated over. + size_t measurement_count(const std::string& unit); + +private: + boost::synchronized_value> m_map; +}; + +} diff --git a/src/Profiling.cpp b/src/Profiling.cpp new file mode 100644 index 0000000..8013df2 --- /dev/null +++ b/src/Profiling.cpp @@ -0,0 +1,41 @@ +#include "Profiling.h" + +prof::Duration prof::duration(const TimePoint& start, const TimePoint& end) { + return end - start; +} +prof::TimePoint prof::now() { + return std::chrono::high_resolution_clock::now(); +} +prof::Duration prof::UnitProfileCollection::average_duration(const std::string& unit) { + return m_map->operator[](unit).average_duration(); +} + +size_t prof::UnitProfileCollection::measurement_count(const std::string& unit) { + return m_map->operator[](unit).measurement_count(); +} + +void prof::UnitProfileCollection::add_sample(const std::string& unit, const Duration& duration) { + m_map->operator[](unit).add_sample(duration); +} + +size_t prof::UnitExecutionTime::measurement_count() { + return m_measurements->size(); +} + +prof::Duration prof::UnitExecutionTime::average_duration() const { + auto measurements = m_measurements.synchronize(); + Duration sum {}; + for (const auto& measurement : *measurements) { + sum += measurement; + } + return sum / measurements->size(); +} + +void prof::UnitExecutionTime::add_sample(const Duration& dur) { + m_measurements->push_back(dur); +} + +prof::UnitExecutionTime::UnitExecutionTime() + : m_measurements(boost::circular_buffer(16)) { +} + From 7deea900fbef7d30a71f503b0fa78d4929aafafe Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Wed, 24 Jan 2024 00:17:42 +0100 Subject: [PATCH 02/10] add Util.DebugExecutionTime --- CMakeLists.txt | 2 ++ include/Profiling.h | 3 +++ include/TLuaEngine.h | 4 ++++ src/Profiling.cpp | 11 ++++++++++- src/TLuaEngine.cpp | 17 ++++++++++++++++- 5 files changed, 35 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e53fab1..68d1036 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,6 +49,7 @@ set(PRJ_HEADERS include/TServer.h include/VehicleData.h include/Env.h + include/Profiling.h ) # add all source files (.cpp) to this, except the one with main() set(PRJ_SOURCES @@ -72,6 +73,7 @@ set(PRJ_SOURCES src/TServer.cpp src/VehicleData.cpp src/Env.cpp + src/Profiling.cpp ) find_package(Lua REQUIRED) diff --git a/include/Profiling.h b/include/Profiling.h index 21b0784..12afd51 100644 --- a/include/Profiling.h +++ b/include/Profiling.h @@ -45,6 +45,9 @@ struct UnitProfileCollection { /// Returns the number of elements the moving average is calculated over. size_t measurement_count(const std::string& unit); + /// Returns the averages for all stored units. + std::unordered_map all_average_durations(); + private: boost::synchronized_value> m_map; }; diff --git a/include/TLuaEngine.h b/include/TLuaEngine.h index b4c14b0..a125b0f 100644 --- a/include/TLuaEngine.h +++ b/include/TLuaEngine.h @@ -18,9 +18,11 @@ #pragma once +#include "Profiling.h" #include "TNetwork.h" #include "TServer.h" #include +#include #include #include #include @@ -253,6 +255,8 @@ private: sol::table Lua_FS_ListFiles(const std::string& Path); sol::table Lua_FS_ListDirectories(const std::string& Path); + prof::UnitProfileCollection mProfile {}; + std::string mName; TLuaStateId mStateId; lua_State* mState; diff --git a/src/Profiling.cpp b/src/Profiling.cpp index 8013df2..dd267fc 100644 --- a/src/Profiling.cpp +++ b/src/Profiling.cpp @@ -36,6 +36,15 @@ void prof::UnitExecutionTime::add_sample(const Duration& dur) { } prof::UnitExecutionTime::UnitExecutionTime() - : m_measurements(boost::circular_buffer(16)) { + : m_measurements(boost::circular_buffer(100)) { +} + +std::unordered_map prof::UnitProfileCollection::all_average_durations() { + auto map = m_map.synchronize(); + std::unordered_map result {}; + for (const auto& [name, time] : *map) { + result[name] = time.average_duration().count(); + } + return result; } diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 5dff14e..8330fc3 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -21,11 +21,13 @@ #include "CustomAssert.h" #include "Http.h" #include "LuaAPI.h" +#include "Profiling.h" #include "TLuaPlugin.h" #include "sol/object.hpp" #include #include +#include #include #include #include @@ -847,6 +849,15 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, TLuaStateI UtilTable.set_function("RandomIntRange", [this](int64_t min, int64_t max) -> int64_t { return std::uniform_int_distribution(min, max)(mMersenneTwister); }); + UtilTable.set_function("DebugExecutionTime", [this]() -> sol::table { + sol::state_view StateView(mState); + sol::table Result = StateView.create_table(); + auto durs = mProfile.all_average_durations(); + for (const auto& [name, dur] : durs) { + Result[name] = dur; + } + return Result; + }); auto HttpTable = StateView.create_named_table("Http"); HttpTable.set_function("CreateConnection", [this](const std::string& host, uint16_t port) { @@ -984,6 +995,7 @@ void TLuaEngine::StateThreadData::operator()() { std::chrono::milliseconds(500), [&]() -> bool { return !mStateFunctionQueue.empty(); }); if (NotExpired) { + auto ProfStart = prof::now(); auto TheQueuedFunction = std::move(mStateFunctionQueue.front()); mStateFunctionQueue.erase(mStateFunctionQueue.begin()); Lock.unlock(); @@ -1042,6 +1054,9 @@ void TLuaEngine::StateThreadData::operator()() { Result->ErrorMessage = BeamMPFnNotFoundError; // special error kind that we can ignore later Result->MarkAsReady(); } + auto ProfEnd = prof::now(); + auto ProfDuration = prof::duration(ProfStart, ProfEnd); + mProfile.add_sample(FnName, ProfDuration); } } } @@ -1101,7 +1116,7 @@ void TLuaResult::MarkAsReady() { void TLuaResult::WaitUntilReady() { std::unique_lock readyLock(*this->ReadyMutex); // wait if not ready yet - if(!this->Ready) + if (!this->Ready) this->ReadyCondition->wait(readyLock); } From 88721d4f7f5cb5eeafc17263ab19670a5cff8edd Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Wed, 24 Jan 2024 00:21:55 +0100 Subject: [PATCH 03/10] add boost circular buffer to dependencies --- vcpkg.json | 1 + 1 file changed, 1 insertion(+) diff --git a/vcpkg.json b/vcpkg.json index 85b9cb2..3bd6b9e 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -6,6 +6,7 @@ "boost-spirit", "boost-uuid", "boost-variant", + "boost-circular-buffer", "cpp-httplib", "doctest", "fmt", From 4347cb4af2693726ca867267a8ffb7bae38cd920 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Wed, 24 Jan 2024 01:26:16 +0100 Subject: [PATCH 04/10] add min, max, stddev to stats --- include/Profiling.h | 21 +++++++++++++++------ src/Profiling.cpp | 38 ++++++++++++++++++++++++++++++-------- src/TLuaEngine.cpp | 10 +++++++--- 3 files changed, 52 insertions(+), 17 deletions(-) diff --git a/include/Profiling.h b/include/Profiling.h index 12afd51..424834b 100644 --- a/include/Profiling.h +++ b/include/Profiling.h @@ -16,6 +16,13 @@ TimePoint now(); /// Returns a sub-millisecond resolution duration between start and end. Duration duration(const TimePoint& start, const TimePoint& end); +struct Stats { + double mean; + double stddev; + double min; + double max; +}; + /// Calculates and stores the moving average over K samples of execution time data /// for some single unit of code. Threadsafe. struct UnitExecutionTime { @@ -24,8 +31,9 @@ struct UnitExecutionTime { /// Adds a sample to the collection, overriding the oldest sample if needed. void add_sample(const Duration& dur); - /// Calculates the average duration over the `measurement_count()` measurements. - Duration average_duration() const; + /// Calculates the mean duration over the `measurement_count()` measurements, + /// as well as the standard deviation. + Stats stats() const; /// Returns the number of elements the moving average is calculated over. size_t measurement_count(); @@ -39,14 +47,15 @@ struct UnitProfileCollection { /// Adds a sample to the collection, overriding the oldest sample if needed. void add_sample(const std::string& unit, const Duration& duration); - /// Calculates the average duration over the `measurement_count()` measurements. - Duration average_duration(const std::string& unit); + /// Calculates the mean duration over the `measurement_count()` measurements, + /// as well as the standard deviation. + Stats stats(const std::string& unit); /// Returns the number of elements the moving average is calculated over. size_t measurement_count(const std::string& unit); - /// Returns the averages for all stored units. - std::unordered_map all_average_durations(); + /// Returns the stats for all stored units. + std::unordered_map all_stats(); private: boost::synchronized_value> m_map; diff --git a/src/Profiling.cpp b/src/Profiling.cpp index dd267fc..8440db0 100644 --- a/src/Profiling.cpp +++ b/src/Profiling.cpp @@ -1,4 +1,5 @@ #include "Profiling.h" +#include prof::Duration prof::duration(const TimePoint& start, const TimePoint& end) { return end - start; @@ -6,8 +7,8 @@ prof::Duration prof::duration(const TimePoint& start, const TimePoint& end) { prof::TimePoint prof::now() { return std::chrono::high_resolution_clock::now(); } -prof::Duration prof::UnitProfileCollection::average_duration(const std::string& unit) { - return m_map->operator[](unit).average_duration(); +prof::Stats prof::UnitProfileCollection::stats(const std::string& unit) { + return m_map->operator[](unit).stats(); } size_t prof::UnitProfileCollection::measurement_count(const std::string& unit) { @@ -22,13 +23,35 @@ size_t prof::UnitExecutionTime::measurement_count() { return m_measurements->size(); } -prof::Duration prof::UnitExecutionTime::average_duration() const { +prof::Stats prof::UnitExecutionTime::stats() const { + Stats result {}; + // calculate sum auto measurements = m_measurements.synchronize(); + if (measurements->size() == 0) { + return result; + } + result.max = std::numeric_limits::min(); + result.min = std::numeric_limits::max(); Duration sum {}; for (const auto& measurement : *measurements) { + if (measurement.count() > result.max) { + result.max = measurement.count(); + } + if (measurement.count() < result.min) { + result.min = measurement.count(); + } sum += measurement; } - return sum / measurements->size(); + // calculate mean + result.mean = (sum / measurements->size()).count(); + // calculate stddev + result.stddev = 0; + for (const auto& measurement : *measurements) { + // (measurements[i] - mean)^2 + result.stddev += std::pow(measurement.count() - result.mean, 2); + } + result.stddev = std::sqrt(result.stddev / double(measurements->size())); + return result; } void prof::UnitExecutionTime::add_sample(const Duration& dur) { @@ -39,12 +62,11 @@ prof::UnitExecutionTime::UnitExecutionTime() : m_measurements(boost::circular_buffer(100)) { } -std::unordered_map prof::UnitProfileCollection::all_average_durations() { +std::unordered_map prof::UnitProfileCollection::all_stats() { auto map = m_map.synchronize(); - std::unordered_map result {}; + std::unordered_map result {}; for (const auto& [name, time] : *map) { - result[name] = time.average_duration().count(); + result[name] = time.stats(); } return result; } - diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 8330fc3..e5c37aa 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -852,9 +852,13 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, TLuaStateI UtilTable.set_function("DebugExecutionTime", [this]() -> sol::table { sol::state_view StateView(mState); sol::table Result = StateView.create_table(); - auto durs = mProfile.all_average_durations(); - for (const auto& [name, dur] : durs) { - Result[name] = dur; + auto stats = mProfile.all_stats(); + for (const auto& [name, stat] : stats) { + Result[name] = StateView.create_table(); + Result[name]["mean"] = stat.mean; + Result[name]["stddev"] = stat.stddev; + Result[name]["min"] = stat.min; + Result[name]["max"] = stat.max; } return Result; }); From 946c1362e1fd022fef65e97a718ad8350c13b0c9 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Wed, 24 Jan 2024 13:50:11 +0100 Subject: [PATCH 05/10] add custom profiling via Debug(Start|Stop)Profile --- include/Profiling.h | 1 + include/TLuaEngine.h | 1 + src/Profiling.cpp | 1 + src/TLuaEngine.cpp | 11 +++++++++++ 4 files changed, 14 insertions(+) diff --git a/include/Profiling.h b/include/Profiling.h index 424834b..0ed5406 100644 --- a/include/Profiling.h +++ b/include/Profiling.h @@ -21,6 +21,7 @@ struct Stats { double stddev; double min; double max; + size_t n; }; /// Calculates and stores the moving average over K samples of execution time data diff --git a/include/TLuaEngine.h b/include/TLuaEngine.h index a125b0f..a6c8c8f 100644 --- a/include/TLuaEngine.h +++ b/include/TLuaEngine.h @@ -256,6 +256,7 @@ private: sol::table Lua_FS_ListDirectories(const std::string& Path); prof::UnitProfileCollection mProfile {}; + std::unordered_map mProfileStarts; std::string mName; TLuaStateId mStateId; diff --git a/src/Profiling.cpp b/src/Profiling.cpp index 8440db0..ab21bf4 100644 --- a/src/Profiling.cpp +++ b/src/Profiling.cpp @@ -30,6 +30,7 @@ prof::Stats prof::UnitExecutionTime::stats() const { if (measurements->size() == 0) { return result; } + result.n = measurements->size(); result.max = std::numeric_limits::min(); result.min = std::numeric_limits::max(); Duration sum {}; diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index e5c37aa..059eca0 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -859,9 +859,20 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, TLuaStateI Result[name]["stddev"] = stat.stddev; Result[name]["min"] = stat.min; Result[name]["max"] = stat.max; + Result[name]["n"] = stat.n; } return Result; }); + UtilTable.set_function("DebugStartProfile", [this](const std::string& name) { + mProfileStarts[name] = prof::now(); + }); + UtilTable.set_function("DebugStopProfile", [this](const std::string& name) { + if (!mProfileStarts.contains(name)) { + beammp_lua_errorf("DebugStopProfile('{}') failed, because a profile for '{}' wasn't started", name, name); + return; + } + mProfile.add_sample(name, prof::duration(mProfileStarts.at(name), prof::now())); + }); auto HttpTable = StateView.create_named_table("Http"); HttpTable.set_function("CreateConnection", [this](const std::string& host, uint16_t port) { From 40533c04bcafcca41f7d592089602d6d623b7a7f Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Wed, 6 Mar 2024 10:24:25 +0100 Subject: [PATCH 06/10] add total calls to stats --- include/Profiling.h | 2 ++ src/Profiling.cpp | 2 ++ src/TLuaEngine.cpp | 1 + 3 files changed, 5 insertions(+) diff --git a/include/Profiling.h b/include/Profiling.h index 0ed5406..ad3e76b 100644 --- a/include/Profiling.h +++ b/include/Profiling.h @@ -22,6 +22,7 @@ struct Stats { double min; double max; size_t n; + size_t total_calls; }; /// Calculates and stores the moving average over K samples of execution time data @@ -41,6 +42,7 @@ struct UnitExecutionTime { private: boost::synchronized_value> m_measurements; + size_t m_total_calls {}; }; /// Holds profiles for multiple units by name. Threadsafe. diff --git a/src/Profiling.cpp b/src/Profiling.cpp index ab21bf4..1e17992 100644 --- a/src/Profiling.cpp +++ b/src/Profiling.cpp @@ -52,11 +52,13 @@ prof::Stats prof::UnitExecutionTime::stats() const { result.stddev += std::pow(measurement.count() - result.mean, 2); } result.stddev = std::sqrt(result.stddev / double(measurements->size())); + result.total_calls = m_total_calls; return result; } void prof::UnitExecutionTime::add_sample(const Duration& dur) { m_measurements->push_back(dur); + ++m_total_calls; } prof::UnitExecutionTime::UnitExecutionTime() diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 059eca0..298c352 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -860,6 +860,7 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, TLuaStateI Result[name]["min"] = stat.min; Result[name]["max"] = stat.max; Result[name]["n"] = stat.n; + Result[name]["total_calls"] = stat.total_calls; } return Result; }); From 590b159f14fd2057c4222cfc997e10cb296a56bf Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 7 Mar 2024 00:25:47 +0100 Subject: [PATCH 07/10] switch to a runnning calculation for stdev and mean --- include/Profiling.h | 11 ++++++++--- src/Profiling.cpp | 46 ++++++++++++--------------------------------- src/TLuaEngine.cpp | 2 +- src/main.cpp | 15 ++++++++++++++- 4 files changed, 35 insertions(+), 39 deletions(-) diff --git a/include/Profiling.h b/include/Profiling.h index ad3e76b..68ece0b 100644 --- a/include/Profiling.h +++ b/include/Profiling.h @@ -4,6 +4,7 @@ #include #include #include +#include namespace prof { @@ -18,7 +19,7 @@ Duration duration(const TimePoint& start, const TimePoint& end); struct Stats { double mean; - double stddev; + double stdev; double min; double max; size_t n; @@ -38,11 +39,15 @@ struct UnitExecutionTime { Stats stats() const; /// Returns the number of elements the moving average is calculated over. - size_t measurement_count(); + size_t measurement_count() const { return m_total_calls; } private: - boost::synchronized_value> m_measurements; size_t m_total_calls {}; + double m_sum {}; + // sum of measurements squared (for running stdev) + double m_measurement_sqr_sum {}; + double m_min { std::numeric_limits::max() }; + double m_max { std::numeric_limits::min() }; }; /// Holds profiles for multiple units by name. Threadsafe. diff --git a/src/Profiling.cpp b/src/Profiling.cpp index 1e17992..2e840c4 100644 --- a/src/Profiling.cpp +++ b/src/Profiling.cpp @@ -19,50 +19,28 @@ void prof::UnitProfileCollection::add_sample(const std::string& unit, const Dura m_map->operator[](unit).add_sample(duration); } -size_t prof::UnitExecutionTime::measurement_count() { - return m_measurements->size(); -} - prof::Stats prof::UnitExecutionTime::stats() const { Stats result {}; // calculate sum - auto measurements = m_measurements.synchronize(); - if (measurements->size() == 0) { - return result; - } - result.n = measurements->size(); - result.max = std::numeric_limits::min(); - result.min = std::numeric_limits::max(); - Duration sum {}; - for (const auto& measurement : *measurements) { - if (measurement.count() > result.max) { - result.max = measurement.count(); - } - if (measurement.count() < result.min) { - result.min = measurement.count(); - } - sum += measurement; - } - // calculate mean - result.mean = (sum / measurements->size()).count(); - // calculate stddev - result.stddev = 0; - for (const auto& measurement : *measurements) { - // (measurements[i] - mean)^2 - result.stddev += std::pow(measurement.count() - result.mean, 2); - } - result.stddev = std::sqrt(result.stddev / double(measurements->size())); - result.total_calls = m_total_calls; + result.n = m_total_calls; + result.max = m_min; + result.min = m_max; + // calculate mean: mean = sum_x / n + result.mean = m_sum / double(m_total_calls); + // calculate stdev: stdev = sqrt((sum_x2 / n) - (mean * mean)) + result.stdev = std::sqrt((m_measurement_sqr_sum / double(result.n)) - (result.mean * result.mean)); return result; } void prof::UnitExecutionTime::add_sample(const Duration& dur) { - m_measurements->push_back(dur); + m_sum += dur.count(); + m_measurement_sqr_sum += dur.count() * dur.count(); + m_min = std::min(dur.count(), m_min); + m_max = std::max(dur.count(), m_max); ++m_total_calls; } -prof::UnitExecutionTime::UnitExecutionTime() - : m_measurements(boost::circular_buffer(100)) { +prof::UnitExecutionTime::UnitExecutionTime() { } std::unordered_map prof::UnitProfileCollection::all_stats() { diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 298c352..4baaa37 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -856,7 +856,7 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, TLuaStateI for (const auto& [name, stat] : stats) { Result[name] = StateView.create_table(); Result[name]["mean"] = stat.mean; - Result[name]["stddev"] = stat.stddev; + Result[name]["stdev"] = stat.stdev; Result[name]["min"] = stat.min; Result[name]["max"] = stat.max; Result[name]["n"] = stat.n; diff --git a/src/main.cpp b/src/main.cpp index 311fa26..bd08b75 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -20,6 +20,7 @@ #include "Common.h" #include "Http.h" #include "LuaAPI.h" +#include "Profiling.h" #include "SignalHandling.h" #include "TConfig.h" #include "THeartbeatThread.h" @@ -30,6 +31,7 @@ #include "TResourceManager.h" #include "TServer.h" +#include #include #include @@ -124,7 +126,7 @@ int BeamMPServerMain(MainArguments Arguments) { } } } - + TConfig Config(ConfigPath); if (Config.Failed()) { @@ -176,6 +178,17 @@ int BeamMPServerMain(MainArguments Arguments) { Http::Server::THttpServerInstance HttpServerInstance {}; } + prof::UnitExecutionTime t {}; + for (size_t i = 0; i < 10'000'000; ++i) { + t.add_sample(std::chrono::seconds(1)); + t.add_sample(std::chrono::seconds(2)); + t.add_sample(std::chrono::seconds(3)); + } + auto stats = t.stats(); + beammp_errorf("mean: {}, stdev: {}, min: {}, max: {}, n: {}", stats.mean, stats.stdev, stats.min, stats.max, stats.n); + + exit(69); + Application::SetSubsystemStatus("Main", Application::Status::Good); RegisterThread("Main(Waiting)"); From e4826e8bf1a0955dc18183987fb5956065b1bdd4 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 7 Mar 2024 00:42:36 +0100 Subject: [PATCH 08/10] remove test code --- include/Profiling.h | 1 - src/TLuaEngine.cpp | 1 - src/main.cpp | 11 ----------- 3 files changed, 13 deletions(-) diff --git a/include/Profiling.h b/include/Profiling.h index 68ece0b..7b57fe6 100644 --- a/include/Profiling.h +++ b/include/Profiling.h @@ -23,7 +23,6 @@ struct Stats { double min; double max; size_t n; - size_t total_calls; }; /// Calculates and stores the moving average over K samples of execution time data diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 4baaa37..18e5d3a 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -860,7 +860,6 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, TLuaStateI Result[name]["min"] = stat.min; Result[name]["max"] = stat.max; Result[name]["n"] = stat.n; - Result[name]["total_calls"] = stat.total_calls; } return Result; }); diff --git a/src/main.cpp b/src/main.cpp index bd08b75..1b8bf8b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -178,17 +178,6 @@ int BeamMPServerMain(MainArguments Arguments) { Http::Server::THttpServerInstance HttpServerInstance {}; } - prof::UnitExecutionTime t {}; - for (size_t i = 0; i < 10'000'000; ++i) { - t.add_sample(std::chrono::seconds(1)); - t.add_sample(std::chrono::seconds(2)); - t.add_sample(std::chrono::seconds(3)); - } - auto stats = t.stats(); - beammp_errorf("mean: {}, stdev: {}, min: {}, max: {}, n: {}", stats.mean, stats.stdev, stats.min, stats.max, stats.n); - - exit(69); - Application::SetSubsystemStatus("Main", Application::Status::Good); RegisterThread("Main(Waiting)"); From c85e026c2dcac092e373fc2a2942b41a5972fbc2 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 7 Mar 2024 00:45:00 +0100 Subject: [PATCH 09/10] cleanup --- include/Profiling.h | 5 +++-- src/Profiling.cpp | 7 +++++++ src/main.cpp | 2 -- vcpkg.json | 1 - 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/include/Profiling.h b/include/Profiling.h index 7b57fe6..72b0a99 100644 --- a/include/Profiling.h +++ b/include/Profiling.h @@ -1,10 +1,10 @@ #pragma once -#include #include #include #include #include +#include namespace prof { @@ -38,9 +38,10 @@ struct UnitExecutionTime { Stats stats() const; /// Returns the number of elements the moving average is calculated over. - size_t measurement_count() const { return m_total_calls; } + size_t measurement_count() const; private: + std::mutex m_mtx {}; size_t m_total_calls {}; double m_sum {}; // sum of measurements squared (for running stdev) diff --git a/src/Profiling.cpp b/src/Profiling.cpp index 2e840c4..f6a41d8 100644 --- a/src/Profiling.cpp +++ b/src/Profiling.cpp @@ -20,6 +20,7 @@ void prof::UnitProfileCollection::add_sample(const std::string& unit, const Dura } prof::Stats prof::UnitExecutionTime::stats() const { + std::unique_lock lock(m_mtx); Stats result {}; // calculate sum result.n = m_total_calls; @@ -33,6 +34,7 @@ prof::Stats prof::UnitExecutionTime::stats() const { } void prof::UnitExecutionTime::add_sample(const Duration& dur) { + std::unique_lock lock(m_mtx); m_sum += dur.count(); m_measurement_sqr_sum += dur.count() * dur.count(); m_min = std::min(dur.count(), m_min); @@ -51,3 +53,8 @@ std::unordered_map prof::UnitProfileCollection::all_st } return result; } +size_t prof::UnitExecutionTime::measurement_count() const { + std::unique_lock lock(m_mtx); + return m_total_calls; +} + diff --git a/src/main.cpp b/src/main.cpp index 1b8bf8b..028ea3b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -20,7 +20,6 @@ #include "Common.h" #include "Http.h" #include "LuaAPI.h" -#include "Profiling.h" #include "SignalHandling.h" #include "TConfig.h" #include "THeartbeatThread.h" @@ -31,7 +30,6 @@ #include "TResourceManager.h" #include "TServer.h" -#include #include #include diff --git a/vcpkg.json b/vcpkg.json index 3bd6b9e..85b9cb2 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -6,7 +6,6 @@ "boost-spirit", "boost-uuid", "boost-variant", - "boost-circular-buffer", "cpp-httplib", "doctest", "fmt", From 7e1f86478d0670fb56d357cfa916ec8ccd6ece7f Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 7 Mar 2024 01:03:16 +0100 Subject: [PATCH 10/10] make mutex mutable --- include/Profiling.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/Profiling.h b/include/Profiling.h index 72b0a99..c0b23c8 100644 --- a/include/Profiling.h +++ b/include/Profiling.h @@ -41,7 +41,7 @@ struct UnitExecutionTime { size_t measurement_count() const; private: - std::mutex m_mtx {}; + mutable std::mutex m_mtx {}; size_t m_total_calls {}; double m_sum {}; // sum of measurements squared (for running stdev)