cpp-common
stats.hh
Go to the documentation of this file.
1 // -*- mode: c++; c-basic-offset: 2; -*-
2 
3 #pragma once
4 
11 #include "cpp-common.hh"
12 #include "string.hh"
13 
14 #include <concepts>
15 #include <cstddef>
16 #include <map>
17 #include <numeric>
18 #include <sstream>
19 #include <string>
20 #include <vector>
21 
22 namespace nvsl {
23  template <class T>
24  concept Integral = std::is_integral<T>::value;
25 
26  template <typename T, typename I>
27  concept Averageable = Integral<I> && requires(T a, T b, I c) {
28  (a + b) / c;
29  };
30 
32  class StatsBase;
33  class StatsCollection {
34  public:
35  static std::vector<StatsBase *> stats;
36 
37  ~StatsCollection();
38  };
39 
41  class StatsBase {
42  protected:
43  std::string stat_name;
44  std::string stat_desc;
45 
46  public:
47  StatsBase(bool reg) {
48  if (reg) {
49  StatsCollection::stats.push_back(this);
50  }
51  };
52 
53  void init(const std::string &name, const std::string &desc) {
54  this->stat_name = name;
55  this->stat_desc = desc;
56  }
57 
58  virtual double avg() const { return 0; }
59  virtual std::string str() const { return ""; }
60  virtual std::string latex(const std::string &prefix = "") const {
61  (void)prefix;
62  return "";
63  }
64  };
65 
67  class StatsScalar : public StatsBase {
68  private:
69  double total;
70  size_t count;
71 
72  bool is_time;
73  time_unit unit;
74 
75  public:
76  StatsScalar(bool reg = true) : StatsBase(reg), total(0), count(0){};
77 
78  void init(const std::string &name, const std::string &desc,
79  bool is_time = false, time_unit unit = time_unit::any_unit) {
80  StatsBase::init(name, desc);
81  this->is_time = is_time;
82  this->unit = unit;
83  }
84 
85  friend StatsScalar operator+(StatsScalar lhs, const auto rhs) {
86  lhs.total += rhs;
87  lhs.count++;
88  return lhs;
89  }
90 
91  StatsScalar &operator+=(const auto rhs) {
92  this->total += rhs;
93  this->count++;
94  return *this;
95  }
96 
98  double avg() const override { return total / (double)count; }
99 
101  std::string str() const override {
102  std::stringstream ss;
103  ss << stat_name << " = " << avg();
104 
105  if (this->is_time) {
106  ss << " (" << ns_to_hr(this->avg()) << ")";
107  }
108 
109  if (stat_desc != "") {
110  ss << " # " << stat_desc;
111  }
112 
113  return ss.str();
114  }
115 
116  std::string latex(const std::string &prefix = "") const override {
117  std::string name = "stat" + prefix + this->stat_name;
118  std::string result = "";
119  size_t ns, us, ms, s;
120 
121  name = nvsl::zip(nvsl::split(name, "_"), "");
122 
123  ns = this->avg();
124  us = this->avg() / 1000;
125  ms = this->avg() / 1000000;
126  s = this->avg() / 1000000000;
127 
128  switch (unit) {
129  case nvsl::time_unit::s_unit:
130  result = to_latex(name, ns, "~s", 1000000000);
131  break;
132  case nvsl::time_unit::ms_unit:
133  result = to_latex(name, ns, "~ms", 1000000);
134  break;
135  case nvsl::time_unit::us_unit:
136  result = to_latex(name, ns, "~\\us{}", 1000);
137  break;
138  case nvsl::time_unit::ns_unit:
139  result = to_latex(name, ns, "~ns", 1);
140  break;
141  case nvsl::time_unit::any_unit:
142  if (s != 0)
143  result = to_latex(name, ns, "~s", 1000000000);
144  else if (ms != 0)
145  result = to_latex(name, ns, "~ms", 1000000);
146  else if (us != 0)
147  result = to_latex(name, ns, "~\\us{}", 1000);
148  else
149  result = to_latex(name, ns, "~ns", 1);
150  break;
151  }
152 
153  result = result + " % total ops = " + std::to_string(this->count);
154 
155  return result;
156  };
157  };
158 
160  class StatsNamedVector : public StatsBase {
161  private:
162  std::map<std::string, StatsScalar> vec;
163  time_unit unit;
164 
165  public:
166  StatsNamedVector(bool reg = true) : StatsBase(reg){};
167 
168  void init(const std::string &name, const std::string &desc,
169  time_unit unit = time_unit::any_unit) {
170  StatsBase::init(name, desc);
171  this->unit = unit;
172  }
173 
174  StatsScalar &operator[](const std::string &memb_name) {
175  const auto memb = this->vec.find(memb_name);
176  const auto exists = memb != this->vec.end();
177 
178  if (not exists) {
179  vec.emplace(std::make_pair(memb_name, false));
180  vec[memb_name].init(memb_name, "", false, this->unit);
181  }
182 
183  return vec[memb_name];
184  }
185 
187  std::string str() const override {
188  std::stringstream ss;
189 
190  for (const auto &[k, v] : this->vec) {
191  ss << this->stat_name << "." << k << " = " << v.avg() << std::endl;
192  }
193 
194  return ss.str();
195  }
196 
197  std::string latex(const std::string &prefix = "") const override {
198  std::stringstream ss;
199 
200  for (const auto &[k, v] : this->vec) {
201  ss << v.latex(prefix + this->stat_name) << std::endl;
202  }
203 
204  return ss.str();
205  }
206  };
207 
208  inline StatsCollection::~StatsCollection() {
209  if (get_env_val(NVSL_GEN_STATS_ENV)) {
210  std::cout << std::endl << "==== Stats ====" << std::endl;
211  for (const auto stat : StatsCollection::stats) {
212  std::cout << stat->str() << std::endl;
213  std::cerr << stat->latex() << std::endl;
214  }
215  }
216  }
217 } // namespace nvsl
nvsl::zip
auto zip(const std::vector< std::string > arr, const std::string join_str)
Concat all the elements of a string vector into a stingle string.
Definition: string.hh:42
nvsl::StatsNamedVector::str
std::string str() const override
Get the string representation of the stat.
Definition: stats.hh:187
nvsl::StatsScalar::avg
double avg() const override
Get the average value per operation.
Definition: stats.hh:98
string.hh
Usefult string functions. Mostly resemble python's.
nvsl::StatsScalar::str
std::string str() const override
Get the string representation of the stat.
Definition: stats.hh:101