add min, max, stddev to stats

This commit is contained in:
Lion Kortlepel 2024-01-24 01:26:16 +01:00 committed by Lion
parent 88721d4f7f
commit 4347cb4af2
3 changed files with 52 additions and 17 deletions

View File

@ -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<std::string, double> all_average_durations();
/// Returns the stats for all stored units.
std::unordered_map<std::string, Stats> all_stats();
private:
boost::synchronized_value<std::unordered_map<std::string, UnitExecutionTime>> m_map;

View File

@ -1,4 +1,5 @@
#include "Profiling.h"
#include <limits>
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<double>::min();
result.min = std::numeric_limits<double>::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<Duration>(100)) {
}
std::unordered_map<std::string, double> prof::UnitProfileCollection::all_average_durations() {
std::unordered_map<std::string, prof::Stats> prof::UnitProfileCollection::all_stats() {
auto map = m_map.synchronize();
std::unordered_map<std::string, double> result {};
std::unordered_map<std::string, Stats> result {};
for (const auto& [name, time] : *map) {
result[name] = time.average_duration().count();
result[name] = time.stats();
}
return result;
}

View File

@ -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;
});