flatten 20260225
This commit is contained in:
150
tjp/core/profile/PROFILE_SCOPE.cpp
Normal file
150
tjp/core/profile/PROFILE_SCOPE.cpp
Normal file
@@ -0,0 +1,150 @@
|
||||
// TJP COPYRIGHT HEADER
|
||||
|
||||
#include "PROFILE_SCOPE.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <list>
|
||||
#include <iomanip>
|
||||
|
||||
#include <tjp/core/threads/Lock.hpp>
|
||||
#include <tjp/core/timer/Timer.hpp>
|
||||
|
||||
#include <tjp/core/log/Log.h>
|
||||
#include <tjp/core/log/LogOf.h>
|
||||
#include <tjp/core/algorithm/starts_with.hpp>
|
||||
#include <tjp/core/assert/debug_assert.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace tjp {
|
||||
namespace core {
|
||||
namespace profile_scope {
|
||||
|
||||
void ProfileScopeManager::append (ProfileToken *token)
|
||||
{
|
||||
auto lock = lock_of(mutex);
|
||||
tokens.push_back(token);
|
||||
}
|
||||
|
||||
|
||||
std::ostream &ProfileScopeManager::print (std::ostream &s)
|
||||
{
|
||||
auto l = lock_of(mutex);
|
||||
return print_no_lock(s);
|
||||
}
|
||||
|
||||
std::ostream &ProfileScopeManager::print_no_lock (std::ostream &s)
|
||||
{
|
||||
Timepoint now = Clock::now();
|
||||
Timepoint then = now - std::chrono::milliseconds(1000);
|
||||
|
||||
s << std::setprecision(10) << std::fixed << std::showpoint;
|
||||
|
||||
struct TokenStats {
|
||||
ProfileToken *token;
|
||||
Stats stats;
|
||||
} ;
|
||||
std::vector<TokenStats> sortedStats;
|
||||
|
||||
for (auto &token : tokens)
|
||||
{
|
||||
Stats stats = token->getStats(then);
|
||||
if (stats.count > 0)
|
||||
{
|
||||
sortedStats.push_back({ token, stats });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::sort(sortedStats.begin(), sortedStats.end(), [](auto &l, auto &r) { return l.stats.totalDuration < r.stats.totalDuration; });
|
||||
|
||||
s << "\nPROFILE ---------------------";
|
||||
|
||||
for (auto &[token, stats] : sortedStats)
|
||||
{
|
||||
s << "\n";
|
||||
s
|
||||
<< "PROFILE\t" << token->name
|
||||
<< ":\t" << stats.count
|
||||
<< "\t" << std::chrono::duration_cast<std::chrono::nanoseconds>(stats.averageDuration).count() / (float)1e+9
|
||||
<< "s\t" << std::chrono::duration_cast<std::chrono::nanoseconds>(stats.totalDuration).count() / (float)1e+9
|
||||
<< "s";
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
std::ostream &ProfileScopeManager::print_clear (std::ostream &s)
|
||||
{
|
||||
auto l = lock_of(mutex);
|
||||
auto &r = print_no_lock(s);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void profile_log ()
|
||||
{
|
||||
std::ostringstream s;
|
||||
ProfileScopeManagerSingleton::getInstance()->print(s);
|
||||
|
||||
sLogRelease("profile", s.str());
|
||||
}
|
||||
|
||||
// ------------------------------------------------------
|
||||
|
||||
ProfileToken::ProfileToken(const char *prettyFunction)
|
||||
{
|
||||
name = prettyFunction;
|
||||
ProfileScopeManagerSingleton::getInstance()->append(this);
|
||||
}
|
||||
|
||||
void ProfileToken::onRecord(ProfileRecord &&record)
|
||||
{
|
||||
auto l = lock_of(mutex);
|
||||
records.emplace_back(std::move(record));
|
||||
}
|
||||
|
||||
Stats ProfileToken::getStats (const Timepoint &then)
|
||||
{
|
||||
auto l = lock_of(mutex);
|
||||
Duration duration = Duration::zero();
|
||||
size_t count = 0;
|
||||
|
||||
for (auto &record : records)
|
||||
{
|
||||
if (record.end > then)
|
||||
{
|
||||
duration += record.duration;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (count)
|
||||
{
|
||||
return Stats {
|
||||
.count = count,
|
||||
.totalDuration = duration,
|
||||
.averageDuration = duration / count
|
||||
};
|
||||
}
|
||||
|
||||
return Stats { .count = 0 };
|
||||
}
|
||||
|
||||
static bool profile_enabled_ = false;
|
||||
|
||||
void profile_enable()
|
||||
{
|
||||
xLogActivateStory("profile");
|
||||
profile_enabled_ = true;
|
||||
}
|
||||
|
||||
bool profile_enabled()
|
||||
{
|
||||
return profile_enabled_;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
147
tjp/core/profile/PROFILE_SCOPE.h
Normal file
147
tjp/core/profile/PROFILE_SCOPE.h
Normal file
@@ -0,0 +1,147 @@
|
||||
// TJP COPYRIGHT HEADER
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
|
||||
#include <sstream>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <tjp/core/threads/Lock.hpp>
|
||||
|
||||
namespace tjp {
|
||||
namespace core {
|
||||
namespace profile_scope {
|
||||
|
||||
typedef std::chrono::high_resolution_clock Clock;
|
||||
typedef std::chrono::time_point<Clock> Timepoint;
|
||||
typedef Clock::duration Duration;
|
||||
|
||||
struct ProfileToken;
|
||||
|
||||
struct ProfileScopeManager
|
||||
{
|
||||
Mutex mutex;
|
||||
|
||||
std::vector<ProfileToken *> tokens;
|
||||
|
||||
public:
|
||||
void append (ProfileToken *token);
|
||||
|
||||
std::ostream &print (std::ostream &s);
|
||||
std::ostream &print_no_lock (std::ostream &s);
|
||||
std::ostream &print_clear (std::ostream &s);
|
||||
} ;
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct ProfileScopeManagerSingleton_
|
||||
{
|
||||
static ProfileScopeManager *singleton;
|
||||
|
||||
static ProfileScopeManager *getInstance ()
|
||||
{
|
||||
if (!singleton)
|
||||
singleton = new ProfileScopeManager();
|
||||
|
||||
return singleton;
|
||||
}
|
||||
} ;
|
||||
|
||||
template<typename T>
|
||||
ProfileScopeManager *ProfileScopeManagerSingleton_<T>::singleton = nullptr;
|
||||
|
||||
using ProfileScopeManagerSingleton = ProfileScopeManagerSingleton_<void>;
|
||||
|
||||
struct ProfileRecord
|
||||
{
|
||||
Timepoint begin, end;
|
||||
Duration duration;
|
||||
const void *other;
|
||||
} ;
|
||||
|
||||
struct Stats
|
||||
{
|
||||
size_t count;
|
||||
Duration totalDuration, averageDuration;
|
||||
} ;
|
||||
|
||||
struct ProfileToken
|
||||
{
|
||||
std::string name;
|
||||
|
||||
Mutex mutex;
|
||||
std::vector<ProfileRecord> records;
|
||||
|
||||
ProfileToken(const char *prettyFunction);
|
||||
|
||||
void onRecord(ProfileRecord &&record);
|
||||
Stats getStats (const Timepoint &then);
|
||||
} ;
|
||||
|
||||
void profile_enable();
|
||||
bool profile_enabled();
|
||||
|
||||
struct ProfileScope
|
||||
{
|
||||
bool enabled;
|
||||
ProfileToken *token;
|
||||
ProfileRecord record;
|
||||
|
||||
ProfileScope(ProfileToken *token_, const void *other = nullptr) :
|
||||
token(token_),
|
||||
enabled(profile_enabled())
|
||||
{
|
||||
if (enabled)
|
||||
{
|
||||
record.other = other;
|
||||
record.begin = Clock::now();
|
||||
}
|
||||
}
|
||||
|
||||
~ProfileScope()
|
||||
{
|
||||
if (enabled)
|
||||
{
|
||||
record.end = Clock::now();
|
||||
record.duration = record.end - record.begin;
|
||||
token->onRecord(std::move(record));
|
||||
}
|
||||
}
|
||||
} ;
|
||||
|
||||
void profile_log();
|
||||
|
||||
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
#ifdef _DEBUG
|
||||
//#define USE_PROFILE
|
||||
#endif
|
||||
|
||||
#ifdef USE_PROFILE
|
||||
|
||||
#define PROFILE_SCOPE(...) \
|
||||
static tjp::core::profile_scope::ProfileToken __profile_token__(__PRETTY_FUNCTION__); \
|
||||
tjp::core::profile_scope::ProfileScope __profile_scope__(&__profile_token__, __VA_ARGS__)
|
||||
|
||||
#define PROFILE_FUNCTION(...) PROFILE_SCOPE(__VA_ARGS__)
|
||||
|
||||
#define PROFILE_LOG() tjp::core::profile_scope::profile_log()
|
||||
|
||||
#define PROFILE_ENABLE() tjp::core::profile_scope::profile_enable()
|
||||
|
||||
#else
|
||||
|
||||
#define PROFILE_SCOPE(...)
|
||||
#define PROFILE_FUNCTION(...)
|
||||
#define PROFILE_LOG()
|
||||
#define PROFILE_ENABLE()
|
||||
|
||||
#endif
|
||||
106
tjp/core/profile/PROFILE_SIGNAL.cpp
Normal file
106
tjp/core/profile/PROFILE_SIGNAL.cpp
Normal file
@@ -0,0 +1,106 @@
|
||||
// TJP COPYRIGHT HEADER
|
||||
|
||||
#define TESTING
|
||||
#include "PROFILE_SIGNAL.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <list>
|
||||
|
||||
#include <tjp/core/threads/Lock.hpp>
|
||||
#include <tjp/core/timer/Timer.hpp>
|
||||
|
||||
#include <tjp/core/log/Log.h>
|
||||
#include <tjp/core/log/LogOf.h>
|
||||
#include <tjp/core/assert/debug_assert.h>
|
||||
#include <tjp/core/time/Time+IO.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
|
||||
namespace tjp {
|
||||
namespace core {
|
||||
|
||||
void ProfileSignal::clear ()
|
||||
{
|
||||
auto l = lock_of(mutex);
|
||||
clear_no_lock();
|
||||
}
|
||||
|
||||
void ProfileSignal::clear_no_lock ()
|
||||
{
|
||||
timers.clear();
|
||||
times.clear();
|
||||
cleared = true;
|
||||
}
|
||||
|
||||
std::ostream &ProfileSignal::print (std::ostream &s)
|
||||
{
|
||||
auto l = lock_of(mutex);
|
||||
return print_no_lock(s);
|
||||
}
|
||||
|
||||
std::ostream &ProfileSignal::print_no_lock (std::ostream &s)
|
||||
{
|
||||
for (auto &[e, ts] : times)
|
||||
{
|
||||
s << "\t" << e;
|
||||
for (auto &t : ts)
|
||||
{
|
||||
s << "\t" << t;
|
||||
}
|
||||
|
||||
s << std::endl;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
std::ostream &ProfileSignal::print_clear (std::ostream &s)
|
||||
{
|
||||
auto l = lock_of(mutex);
|
||||
auto &r = print_no_lock(s);
|
||||
clear_no_lock();
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
void ProfileSignal::begin (Event &&e)
|
||||
{
|
||||
auto l = lock_of(mutex);
|
||||
|
||||
auto time = timeSource.get();
|
||||
auto i = timers.find(e);
|
||||
if (i != timers.end())
|
||||
return;
|
||||
|
||||
timers[e] = time;
|
||||
|
||||
signal.notify_all();
|
||||
}
|
||||
|
||||
void ProfileSignal::end (Event &&e)
|
||||
{
|
||||
auto l = lock_of(mutex);
|
||||
auto i = timers.find(e);
|
||||
if (i != timers.end())
|
||||
{
|
||||
auto then = i->second;
|
||||
auto now = timeSource.get();
|
||||
auto dt = now-then;
|
||||
times[e].push_back(dt);
|
||||
|
||||
std::ostringstream s;
|
||||
sLogDebug("profile_signal", e << "\t" << dt << ((dt > time::Deciseconds(1)) ? " dt-large" : ""));
|
||||
std::cout << s.str();
|
||||
|
||||
timers.erase(i);
|
||||
}
|
||||
|
||||
signal.notify_all();
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
144
tjp/core/profile/PROFILE_SIGNAL.h
Normal file
144
tjp/core/profile/PROFILE_SIGNAL.h
Normal file
@@ -0,0 +1,144 @@
|
||||
// TJP COPYRIGHT HEADER
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef TESTING
|
||||
|
||||
#include <tjp/core/threads/Lock.hpp>
|
||||
#include <tjp/core/timer/Timer.hpp>
|
||||
#include <tjp/core/time/Time.h>
|
||||
#include <tjp/core/time/Source.hpp>
|
||||
#include <functional>
|
||||
|
||||
#include <sstream>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace tjp {
|
||||
namespace core {
|
||||
|
||||
struct ProfileSignal
|
||||
{
|
||||
typedef std::string Event;
|
||||
|
||||
core::Event::Mutex mutex;
|
||||
core::Event signal;
|
||||
bool cleared = false;
|
||||
|
||||
typedef time::Time Time;
|
||||
typedef time::Duration Duration;
|
||||
time::SourceStandard timeSource;
|
||||
|
||||
std::map<Event, Time> timers;
|
||||
std::map<Event, std::vector<Duration>> times;
|
||||
|
||||
typedef std::list<Event> Events;
|
||||
Events events;
|
||||
|
||||
public:
|
||||
void append (Event &&e);
|
||||
|
||||
const std::string STAR = "*";
|
||||
|
||||
void begin(Event &&e);
|
||||
void end(Event &&e);
|
||||
|
||||
void clear();
|
||||
void clear_no_lock();
|
||||
|
||||
std::ostream &print (std::ostream &s);
|
||||
std::ostream &print_no_lock (std::ostream &s);
|
||||
std::ostream &print_clear (std::ostream &s);
|
||||
} ;
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct ProfileSignalSingleton
|
||||
{
|
||||
static ProfileSignal *singleton;
|
||||
|
||||
static ProfileSignal *getInstance ()
|
||||
{
|
||||
if (!singleton)
|
||||
singleton = new ProfileSignal();
|
||||
|
||||
return singleton;
|
||||
}
|
||||
} ;
|
||||
|
||||
template<typename T>
|
||||
ProfileSignal *ProfileSignalSingleton<T>::singleton = nullptr;
|
||||
|
||||
|
||||
// -------
|
||||
|
||||
|
||||
template<typename S, typename T, typename ...X>
|
||||
void profile_test_event_string_args(S &s, T &t)
|
||||
{
|
||||
s << t;
|
||||
}
|
||||
|
||||
template<typename S, typename T, typename ...X>
|
||||
void profile_test_event_string_args(S &s, T &&t, X&&...x)
|
||||
{
|
||||
s << t << ",";
|
||||
profile_test_event_string_args(s, x...);
|
||||
}
|
||||
|
||||
template<typename ... T>
|
||||
std::string profile_test_event_string(T&& ...t)
|
||||
{
|
||||
std::ostringstream s;
|
||||
profile_test_event_string_args(s, t...);
|
||||
return s.str();
|
||||
}
|
||||
|
||||
|
||||
template<typename...T>
|
||||
void profile_time_clear()
|
||||
{
|
||||
ProfileSignalSingleton<void>::getInstance()->clear ();
|
||||
}
|
||||
|
||||
template<typename S>
|
||||
S &profile_time_print(S &stream)
|
||||
{
|
||||
return ProfileSignalSingleton<void>::getInstance()->print (stream);
|
||||
}
|
||||
|
||||
template<typename S>
|
||||
S &process_time_print_clear(S &stream)
|
||||
{
|
||||
return ProfileSignalSingleton<void>::getInstance()->print_clear (stream);
|
||||
}
|
||||
|
||||
|
||||
template<typename...T>
|
||||
void profile_time_begin(T&&...t)
|
||||
{
|
||||
ProfileSignalSingleton<void>::getInstance()->begin (ProfileSignal::Event{ process_test_event_string(t...) });
|
||||
}
|
||||
|
||||
template<typename...T>
|
||||
void profile_time_end(T&&...t)
|
||||
{
|
||||
return ProfileSignalSingleton<void>::getInstance()->end(ProfileSignal::Event{ process_test_event_string(t...) });
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
#define TEST_TIME_CLEAR() tjp::core::profile_time_clear()
|
||||
#define TEST_TIME_PRINT(stream) tjp::core::profile_time_print(stream)
|
||||
#define TEST_TIME_PRINT_CLEAR(stream) tjp::core::profile_time_print_clear(stream)
|
||||
#define TEST_TIME_BEGIN(v,...) tjp::core::profile_time_begin(v,__VA_ARGS__)
|
||||
#define TEST_TIME_END(v,...) tjp::core::profile_time_end(v,__VA_ARGS__)
|
||||
|
||||
#else
|
||||
|
||||
#define TEST_TIME_BEGIN(...)
|
||||
#define TEST_TIME_END(...)
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user