Refactor profiler and related classes

This commit is contained in:
sfan5 2024-04-10 23:56:34 +02:00
parent 5a07f5a652
commit 72eeb9fecb
7 changed files with 133 additions and 132 deletions

View File

@ -1132,9 +1132,11 @@ void Game::run()
FpsControl draw_times; FpsControl draw_times;
f32 dtime; // in seconds f32 dtime; // in seconds
/* Clear the profiler */ // Clear the profiler
Profiler::GraphValues dummyvalues; {
g_profiler->graphGet(dummyvalues); Profiler::GraphValues dummyvalues;
g_profiler->graphPop(dummyvalues);
}
draw_times.reset(); draw_times.reset();
@ -4229,7 +4231,7 @@ void Game::updateClouds(float dtime)
inline void Game::updateProfilerGraphs(ProfilerGraph *graph) inline void Game::updateProfilerGraphs(ProfilerGraph *graph)
{ {
Profiler::GraphValues values; Profiler::GraphValues values;
g_profiler->graphGet(values); g_profiler->graphPop(values);
graph->put(values); graph->put(values);
} }

View File

@ -23,14 +23,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <string> #include <string>
#include <mutex> #include <mutex>
enum TimePrecision
{
PRECISION_SECONDS,
PRECISION_MILLI,
PRECISION_MICRO,
PRECISION_NANO
};
inline struct tm mt_localtime() inline struct tm mt_localtime()
{ {
// initialize the time zone on first invocation // initialize the time zone on first invocation

View File

@ -33,7 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrlichttypes.h" // u64 #include "irrlichttypes.h" // u64
#include "debug.h" #include "debug.h"
#include "constants.h" #include "constants.h"
#include "gettime.h" #include "util/timetaker.h" // TimePrecision
#ifdef _MSC_VER #ifdef _MSC_VER
#define SWPRINTF_CHARSTRING L"%S" #define SWPRINTF_CHARSTRING L"%S"

View File

@ -22,40 +22,37 @@ with this program; if not, write to the Free Software Foundation, Inc.,
static Profiler main_profiler; static Profiler main_profiler;
Profiler *g_profiler = &main_profiler; Profiler *g_profiler = &main_profiler;
ScopeProfiler::ScopeProfiler(
Profiler *profiler, const std::string &name, ScopeProfilerType type) : ScopeProfiler::ScopeProfiler(Profiler *profiler, const std::string &name,
m_profiler(profiler), ScopeProfilerType type, TimePrecision prec) :
m_name(name), m_type(type) m_profiler(profiler),
m_name(name), m_type(type), m_precision(prec)
{ {
m_name.append(" [ms]"); m_name.append(" [").append(TimePrecision_units[prec]).append("]");
if (m_profiler) m_time1 = porting::getTime(prec);
m_timer = new TimeTaker(m_name, nullptr, PRECISION_MILLI);
} }
ScopeProfiler::~ScopeProfiler() ScopeProfiler::~ScopeProfiler()
{ {
if (!m_timer) if (!m_profiler)
return; return;
float duration_ms = m_timer->stop(true); float duration = porting::getTime(m_precision) - m_time1;
float duration = duration_ms;
if (m_profiler) { switch (m_type) {
switch (m_type) { case SPT_ADD:
case SPT_ADD: m_profiler->add(m_name, duration);
m_profiler->add(m_name, duration); break;
break; case SPT_AVG:
case SPT_AVG: m_profiler->avg(m_name, duration);
m_profiler->avg(m_name, duration); break;
break; case SPT_GRAPH_ADD:
case SPT_GRAPH_ADD: m_profiler->graphAdd(m_name, duration);
m_profiler->graphAdd(m_name, duration); break;
break; case SPT_MAX:
case SPT_MAX: m_profiler->max(m_name, duration);
m_profiler->max(m_name, duration); break;
break;
}
} }
delete m_timer;
} }
Profiler::Profiler() Profiler::Profiler()
@ -66,92 +63,68 @@ Profiler::Profiler()
void Profiler::add(const std::string &name, float value) void Profiler::add(const std::string &name, float value)
{ {
MutexAutoLock lock(m_mutex); MutexAutoLock lock(m_mutex);
{
/* No average shall have been used; mark add/max used as -2 */ auto it = m_data.find(name);
std::map<std::string, int>::iterator n = m_avgcounts.find(name); if (it == m_data.end()) {
if (n == m_avgcounts.end()) { // mark with special value for checking
m_avgcounts[name] = -2; m_data.emplace(name, DataPair{value, -SPT_ADD});
} else { } else {
if (n->second == -1) assert(it->second.avgcount == -SPT_ADD);
n->second = -2; it->second.value += value;
assert(n->second == -2);
}
}
{
std::map<std::string, float>::iterator n = m_data.find(name);
if (n == m_data.end())
m_data[name] = value;
else
n->second += value;
} }
} }
void Profiler::max(const std::string &name, float value) void Profiler::max(const std::string &name, float value)
{ {
MutexAutoLock lock(m_mutex); MutexAutoLock lock(m_mutex);
{
/* No average shall have been used; mark add/max used as -2 */ auto it = m_data.find(name);
auto n = m_avgcounts.find(name); if (it == m_data.end()) {
if (n == m_avgcounts.end()) { // mark with special value for checking
m_avgcounts[name] = -2; m_data.emplace(name, DataPair{value, -SPT_MAX});
} else { } else {
if (n->second == -1) assert(it->second.avgcount == -SPT_MAX);
n->second = -2; it->second.value = std::max(value, it->second.value);
assert(n->second == -2);
}
}
{
auto n = m_data.find(name);
if (n == m_data.end())
m_data[name] = value;
else if (value > n->second)
n->second = value;
} }
} }
void Profiler::avg(const std::string &name, float value) void Profiler::avg(const std::string &name, float value)
{ {
MutexAutoLock lock(m_mutex); MutexAutoLock lock(m_mutex);
int &count = m_avgcounts[name];
assert(count != -2); auto it = m_data.find(name);
count = MYMAX(count, 0) + 1; if (it == m_data.end()) {
m_data[name] += value; m_data.emplace(name, DataPair{value, 1});
} else {
assert(it->second.avgcount >= 1);
it->second.value += value;
it->second.avgcount++;
}
} }
void Profiler::clear() void Profiler::clear()
{ {
MutexAutoLock lock(m_mutex); MutexAutoLock lock(m_mutex);
for (auto &it : m_data) { for (auto &it : m_data)
it.second = 0; it.second = DataPair();
}
m_avgcounts.clear();
m_start_time = porting::getTimeMs(); m_start_time = porting::getTimeMs();
} }
float Profiler::getValue(const std::string &name) const float Profiler::getValue(const std::string &name) const
{ {
auto numerator = m_data.find(name); auto it = m_data.find(name);
if (numerator == m_data.end()) if (it == m_data.end())
return 0.f; return 0;
return it->second.getValue();
auto denominator = m_avgcounts.find(name);
if (denominator != m_avgcounts.end()) {
if (denominator->second >= 1)
return numerator->second / denominator->second;
}
return numerator->second;
} }
int Profiler::getAvgCount(const std::string &name) const int Profiler::getAvgCount(const std::string &name) const
{ {
auto n = m_avgcounts.find(name); auto it = m_data.find(name);
if (it == m_data.end())
if (n != m_avgcounts.end() && n->second >= 1) return 1;
return n->second; int denominator = it->second.avgcount;
return denominator >= 1 ? denominator : 1;
return 1;
} }
u64 Profiler::getElapsedMs() const u64 Profiler::getElapsedMs() const
@ -204,6 +177,6 @@ void Profiler::getPage(GraphValues &o, u32 page, u32 pagecount)
continue; continue;
} }
o[i.first] = i.second / getAvgCount(i.first); o[i.first] = i.second.getValue();
} }
} }

View File

@ -58,54 +58,71 @@ public:
void getPage(GraphValues &o, u32 page, u32 pagecount); void getPage(GraphValues &o, u32 page, u32 pagecount);
void graphSet(const std::string &id, float value)
{
MutexAutoLock lock(m_mutex);
m_graphvalues[id] = value;
}
void graphAdd(const std::string &id, float value) void graphAdd(const std::string &id, float value)
{ {
MutexAutoLock lock(m_mutex); MutexAutoLock lock(m_mutex);
std::map<std::string, float>::iterator i = auto it = m_graphvalues.find(id);
m_graphvalues.find(id); if (it == m_graphvalues.end())
if(i == m_graphvalues.end()) m_graphvalues.emplace(id, value);
m_graphvalues[id] = value;
else else
i->second += value; it->second += value;
} }
void graphGet(GraphValues &result) void graphPop(GraphValues &result)
{ {
MutexAutoLock lock(m_mutex); MutexAutoLock lock(m_mutex);
result = m_graphvalues; assert(result.empty());
m_graphvalues.clear(); std::swap(result, m_graphvalues);
} }
void remove(const std::string& name) void remove(const std::string& name)
{ {
MutexAutoLock lock(m_mutex); MutexAutoLock lock(m_mutex);
m_avgcounts.erase(name);
m_data.erase(name); m_data.erase(name);
} }
private: private:
struct DataPair {
float value = 0;
int avgcount = 0;
inline float getValue() const {
return avgcount >= 1 ? (value / avgcount) : value;
}
};
std::mutex m_mutex; std::mutex m_mutex;
std::map<std::string, float> m_data; std::map<std::string, DataPair> m_data;
std::map<std::string, int> m_avgcounts;
std::map<std::string, float> m_graphvalues; std::map<std::string, float> m_graphvalues;
u64 m_start_time; u64 m_start_time;
}; };
enum ScopeProfilerType{ enum ScopeProfilerType : u8
SPT_ADD, {
SPT_ADD = 1,
SPT_AVG, SPT_AVG,
SPT_GRAPH_ADD, SPT_GRAPH_ADD,
SPT_MAX SPT_MAX
}; };
// Note: this class should be kept lightweight.
class ScopeProfiler class ScopeProfiler
{ {
public: public:
ScopeProfiler(Profiler *profiler, const std::string &name, ScopeProfiler(Profiler *profiler, const std::string &name,
ScopeProfilerType type = SPT_ADD); ScopeProfilerType type = SPT_ADD,
TimePrecision precision = PRECISION_MILLI);
~ScopeProfiler(); ~ScopeProfiler();
private: private:
Profiler *m_profiler = nullptr; Profiler *m_profiler = nullptr;
std::string m_name; std::string m_name;
TimeTaker *m_timer = nullptr; u64 m_time1;
enum ScopeProfilerType m_type; ScopeProfilerType m_type;
TimePrecision m_precision;
}; };

View File

@ -23,12 +23,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "log.h" #include "log.h"
#include <ostream> #include <ostream>
TimeTaker::TimeTaker(const std::string &name, u64 *result, TimePrecision prec) void TimeTaker::start()
{ {
m_name = name; m_time1 = porting::getTime(m_precision);
m_result = result;
m_precision = prec;
m_time1 = porting::getTime(prec);
} }
u64 TimeTaker::stop(bool quiet) u64 TimeTaker::stop(bool quiet)
@ -39,15 +36,8 @@ u64 TimeTaker::stop(bool quiet)
(*m_result) += dtime; (*m_result) += dtime;
} else { } else {
if (!quiet) { if (!quiet) {
static const char* const units[] = {
"s" /* PRECISION_SECONDS */,
"ms" /* PRECISION_MILLI */,
"us" /* PRECISION_MICRO */,
"ns" /* PRECISION_NANO */,
};
infostream << m_name << " took " infostream << m_name << " took "
<< dtime << units[m_precision] << dtime << TimePrecision_units[m_precision] << std::endl;
<< std::endl;
} }
} }
m_running = false; m_running = false;

View File

@ -19,18 +19,43 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#pragma once #pragma once
#include <string>
#include "irrlichttypes.h" #include "irrlichttypes.h"
#include "gettime.h"
enum TimePrecision : s8
{
PRECISION_SECONDS,
PRECISION_MILLI,
PRECISION_MICRO,
PRECISION_NANO,
};
constexpr const char *TimePrecision_units[] = {
"s" /* PRECISION_SECONDS */,
"ms" /* PRECISION_MILLI */,
"us" /* PRECISION_MICRO */,
"ns" /* PRECISION_NANO */,
};
/* /*
TimeTaker TimeTaker
*/ */
// Note: this class should be kept lightweight
class TimeTaker class TimeTaker
{ {
public: public:
TimeTaker(const std::string &name, u64 *result=nullptr, TimeTaker(const std::string &name, u64 *result = nullptr,
TimePrecision prec=PRECISION_MILLI); TimePrecision prec = PRECISION_MILLI)
{
if (result)
m_result = result;
else
m_name = name;
m_precision = prec;
start();
}
~TimeTaker() ~TimeTaker()
{ {
@ -42,9 +67,11 @@ public:
u64 getTimerTime(); u64 getTimerTime();
private: private:
void start();
std::string m_name; std::string m_name;
u64 *m_result = nullptr;
u64 m_time1; u64 m_time1;
bool m_running = true; bool m_running = true;
TimePrecision m_precision; TimePrecision m_precision;
u64 *m_result = nullptr;
}; };