Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #pragma once
- #include <util/string.hpp>
- #include <util/time.hpp>
- #include <util/thread.hpp>
- #include <util/json.hpp>
- #include <mutex>
- #include <array>
- #include <map>
- #include <atomic>
- #include "logger.hpp"
- namespace Labs {
- #define EVENT_DECL(identificator_user, event_var, event_name) static ::Labs::Identificator<identificator_user> event_var = ::Labs::Identificator<identificator_user>::init_event(event_name);
- #define TIMER_SECTION_DECL(event_name) EVENT_DECL(ThreadTimer, event_name, #event_name)
- #define THREAD_TIMER_SECTION(event_name) TIMER_SECTION_DECL(event_name) ThreadTimer::set_section(event_name)
- #define THREAD_TIMER_SECTION_END ThreadTimer::end_section()
- #define THREAD_TIMER_SECTION_AUTO(event_name) TIMER_SECTION_DECL(event_name) auto holder = ThreadTimer::set_auto_section(event_name)
- struct ProfItem {
- double total_time;
- unsigned int count;
- double get_avg() const {
- return total_time/count;
- }
- ProfItem& operator+=(const ProfItem& other) {
- total_time += other.total_time;
- count+=other.count;
- return *this;
- }
- };
- constexpr size_t MAX_ID_CNT = 100;
- template<class User>
- class Identificator {
- public:
- static Identificator init_event(const String& name) {
- std::unique_lock<std::mutex> g(init_mutex);
- auto& idx = event_indexes[name];
- if(idx == 0) {
- idx = ++counter;
- if(idx >= MAX_ID_CNT) {
- throw std::runtime_error("Exceeded maximum id count");
- }
- names[idx] = name;
- if(names[0].empty()) {
- names[0] = "Undefined";
- }
- }
- g.unlock();
- return Identificator(idx);
- }
- Identificator(int _index) :
- index(_index)
- {
- }
- Identificator() :
- index()
- {}
- Identificator(const Identificator& other) = default;
- Identificator& operator=(const Identificator& other) = default;
- int get_int() const {
- return index;
- }
- const String& get_label() const {
- return names[index];
- }
- bool is_registered() const {
- return !names[index].empty();
- }
- bool operator<(const Identificator& other) const{
- return index < other.index;
- }
- private:
- static std::mutex init_mutex;
- static std::map<String,int> event_indexes;
- static std::atomic_int counter;
- static std::array<String, MAX_ID_CNT> names;
- int index;
- };
- template<class User>
- std::mutex Identificator<User>::init_mutex;
- template<class User>
- std::map<String,int> Identificator<User>::event_indexes;
- template<class User>
- std::atomic_int Identificator<User>::counter;
- template<class User>
- std::array<String, MAX_ID_CNT> Identificator<User>::names;
- class ThreadTimer;
- typedef Identificator<ThreadTimer> TTI;
- class ThreadTimer {
- public:
- class SectionEnder {
- public:
- SectionEnder() :
- owner(true)
- {}
- ~SectionEnder() {
- if(owner) {
- ThreadTimer::end_section();
- }
- }
- SectionEnder(const SectionEnder& other) = delete;
- SectionEnder& operator=(const SectionEnder& other) = delete;
- SectionEnder(SectionEnder&& other) :
- owner(true)
- {
- other.owner = false;
- }
- SectionEnder& operator=(SectionEnder&& other) {
- owner = true;
- other.owner = false;
- return *this;
- }
- private:
- bool owner;
- };
- typedef std::function<void(const TTI& id, const ProfItem& val)> ConsumerFun;
- static void set_section(const TTI& id) {
- std::cerr << "SECTION " << id.get_label() << std::endl;
- double time = microtime();
- double& s_time = start_time.get();
- if(s_time == 0.0) {
- s_time = time;
- }
- ProfItem diff {time - s_time, 1};
- TTI& cs = current_section.get();
- timings.get()[cs.get_int()] += diff;
- s_time = time;
- for(size_t i = 0; i < consumers.size(); i++) {
- consumers[i](cs, diff);
- }
- cs = id;
- }
- static SectionEnder set_auto_section(const TTI& id) {
- set_section(id);
- return SectionEnder();
- }
- static void end_section() {
- EVENT_DECL(ThreadTimer, event, "Undefined");
- set_section(event);
- }
- static void reset() {
- auto& vec = timings.get();
- ProfItem empty {0.0,0};
- std::fill(vec.begin(), vec.end(), empty);
- }
- private:
- template<size_t p>
- friend class PeriodicAvgTimer;
- friend class AvgTimer;
- static void register_consumer_fun(const ConsumerFun& fun) {
- consumers.push_back(fun);
- }
- static ThreadLocal<TTI> current_section;
- static ThreadLocal<double> start_time;
- static ThreadLocal<std::array<ProfItem, MAX_ID_CNT>> timings;
- static std::vector<ConsumerFun> consumers;
- };
- inline Json::Value timings_to_json(const std::array<ProfItem, MAX_ID_CNT>& data) {
- Json::Value ret;
- for(int i = 0; i < data.size(); i++) {
- if(data[i].count != 0) {
- TTI id(i);
- ret[id.get_label()]["all"] = data[i].total_time;
- ret[id.get_label()]["cnt"] = data[i].count;
- ret[id.get_label()]["avg"] = data[i].get_avg();
- }
- }
- return ret;
- }
- template <size_t period>
- class PeriodicAvgTimer {
- public:
- static Json::Value report_json() {
- log_info("AVG:", period, timings_to_json(timings), last_flush, registrator);
- return timings_to_json(old_timings);
- }
- private:
- static void add_val(const TTI& id, ProfItem val) {
- std::cerr << "ADD: " << id.get_label() << " : " << period << std::endl;
- double c_time = microtime();
- if(c_time - last_flush > period) {
- static std::mutex m;
- std::lock_guard<std::mutex> g(m);
- if(c_time - last_flush > period) {
- timings.swap(old_timings);
- ProfItem it{0.0, 0};
- std::fill(timings.begin(), timings.end(), it);
- last_flush = c_time;
- }
- }
- timings[id.get_int()] += val;
- }
- static int register_for_updates() {
- std::cerr << "REG:" << period << std::endl;
- ThreadTimer::register_consumer_fun(PeriodicAvgTimer::add_val);
- //it's a place holder
- return 42;
- }
- static std::array<ProfItem, MAX_ID_CNT> timings;
- static std::array<ProfItem, MAX_ID_CNT> old_timings;
- static int registrator;
- static double last_flush;
- };
- template<size_t period>
- std::array<ProfItem, MAX_ID_CNT> PeriodicAvgTimer<period>::timings;
- template<size_t period>
- std::array<ProfItem, MAX_ID_CNT> PeriodicAvgTimer<period>::old_timings;
- template<size_t period>
- int PeriodicAvgTimer<period>::registrator = PeriodicAvgTimer<period>::register_for_updates();
- template<size_t period>
- double PeriodicAvgTimer<period>::last_flush = 0.0;
- class AvgTimer {
- public:
- static Json::Value report_json() {
- return timings_to_json(timings);
- }
- private:
- static void add_val(const Identificator<ThreadTimer>& id, ProfItem val) {
- timings[id.get_int()] += val;
- }
- static int registrator;
- static int register_for_updates() {
- std::cerr << "REG AVG:" << std::endl;
- ThreadTimer::register_consumer_fun(AvgTimer::add_val);
- //it's a place holder
- return 42;
- }
- static std::array<ProfItem, MAX_ID_CNT> timings;
- };
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement