Caffe2 - C++ API
A deep learning, cross platform ML framework
stats.h
1 
17 #pragma once
18 
19 #include <atomic>
20 #include <memory>
21 #include <mutex>
22 #include <string>
23 #include <unordered_map>
24 #include <vector>
25 #include "caffe2/core/logging.h"
26 #include "caffe2/core/static_tracepoint.h"
27 
28 namespace caffe2 {
29 
30 class StatValue {
31  std::atomic<int64_t> v_{0};
32 
33  public:
34  int64_t increment(int64_t inc) {
35  return v_ += inc;
36  }
37 
38  int64_t reset(int64_t value = 0) {
39  return v_.exchange(value);
40  }
41 
42  int64_t get() const {
43  return v_.load();
44  }
45 };
46 
48  std::string key;
49  int64_t value;
50  std::chrono::time_point<std::chrono::high_resolution_clock> ts;
51 };
52 
56 using ExportedStatList = std::vector<ExportedStatValue>;
57 using ExportedStatMap = std::unordered_map<std::string, int64_t>;
58 
59 ExportedStatMap toMap(const ExportedStatList& stats);
60 
134  std::mutex mutex_;
135  std::unordered_map<std::string, std::unique_ptr<StatValue>> stats_;
136 
137  public:
142  static StatRegistry& get();
143 
148  StatValue* add(const std::string& name);
149 
155  void publish(ExportedStatList& exported, bool reset = false);
156 
157  ExportedStatList publish(bool reset = false) {
158  ExportedStatList stats;
159  publish(stats, reset);
160  return stats;
161  }
162 
167  void update(const ExportedStatList& data);
168 
169  ~StatRegistry();
170 };
171 
172 struct Stat {
173  std::string groupName;
174  std::string name;
175  Stat(const std::string& gn, const std::string& n) : groupName(gn), name(n) {}
176 
177  template <typename... Unused>
178  int64_t increment(Unused...) {
179  return -1;
180  }
181 };
182 
183 class ExportedStat : public Stat {
184  StatValue* value_;
185 
186  public:
187  ExportedStat(const std::string& gn, const std::string& n)
188  : Stat(gn, n), value_(StatRegistry::get().add(gn + "/" + n)) {}
189 
190  int64_t increment(int64_t value = 1) {
191  return value_->increment(value);
192  }
193 
194  template <typename T, typename Unused1, typename... Unused>
195  int64_t increment(T value, Unused1, Unused...) {
196  return increment(value);
197  }
198 };
199 
201  private:
202  ExportedStat count_;
203 
204  public:
205  AvgExportedStat(const std::string& gn, const std::string& n)
206  : ExportedStat(gn, n + "/sum"), count_(gn, n + "/count") {}
207 
208  int64_t increment(int64_t value = 1) {
209  count_.increment();
210  return ExportedStat::increment(value);
211  }
212 
213  template <typename T, typename Unused1, typename... Unused>
214  int64_t increment(T value, Unused1, Unused...) {
215  return increment(value);
216  }
217 };
218 
220  // Uses an offset (first_) to remove issue of cancellation
221  // Variance is then (sumsqoffset_ - (sumoffset_^2) / count_) / (count_ - 1)
222  private:
223  ExportedStat count_;
224  ExportedStat sumsqoffset_;
225  ExportedStat sumoffset_;
226  std::atomic<int64_t> first_{std::numeric_limits<int64_t>::min()};
227  int64_t const_min_{std::numeric_limits<int64_t>::min()};
228 
229  public:
230  StdDevExportedStat(const std::string& gn, const std::string& n)
231  : ExportedStat(gn, n + "/sum"),
232  count_(gn, n + "/count"),
233  sumsqoffset_(gn, n + "/sumsqoffset"),
234  sumoffset_(gn, n + "/sumoffset") {}
235 
236  int64_t increment(int64_t value = 1) {
237  first_.compare_exchange_strong(const_min_, value);
238  int64_t offset_value = first_.load();
239  int64_t orig_value = value;
240  value -= offset_value;
241  count_.increment();
242  sumsqoffset_.increment(value * value);
243  sumoffset_.increment(value);
244  return ExportedStat::increment(orig_value);
245  }
246 
247  template <typename T, typename Unused1, typename... Unused>
248  int64_t increment(T value, Unused1, Unused...) {
249  return increment(value);
250  }
251 };
252 
254  private:
255  std::vector<ExportedStat> details_;
256 
257  public:
258  DetailedExportedStat(const std::string& gn, const std::string& n)
259  : ExportedStat(gn, n) {}
260 
261  void setDetails(const std::vector<std::string>& detailNames) {
262  details_.clear();
263  for (const auto& detailName : detailNames) {
264  details_.emplace_back(groupName, name + "/" + detailName);
265  }
266  }
267 
268  template <typename T, typename... Unused>
269  int64_t increment(T value, size_t detailIndex, Unused...) {
270  if (detailIndex < details_.size()) {
271  details_[detailIndex].increment(value);
272  }
273  return ExportedStat::increment(value);
274  }
275 };
276 
277 namespace detail {
278 
279 template <class T>
280 struct _ScopeGuard {
281  T f_;
282  std::chrono::high_resolution_clock::time_point start_;
283 
284  explicit _ScopeGuard(T f)
285  : f_(f), start_(std::chrono::high_resolution_clock::now()) {}
286  ~_ScopeGuard() {
287  using namespace std::chrono;
288  auto duration = high_resolution_clock::now() - start_;
289  int64_t nanos = duration_cast<nanoseconds>(duration).count();
290  f_(nanos);
291  }
292 
293  // Using implicit cast to bool so that it can be used in an 'if' condition
294  // within CAFFE_DURATION macro below.
295  /* implicit */ operator bool() {
296  return true;
297  }
298 };
299 
300 template <class T>
301 _ScopeGuard<T> ScopeGuard(T f) {
302  return _ScopeGuard<T>(f);
303 }
304 }
305 
306 #define CAFFE_STAT_CTOR(ClassName) \
307  ClassName(std::string name) : groupName(name) {} \
308  std::string groupName
309 
310 #define CAFFE_EXPORTED_STAT(name) \
311  ExportedStat name { \
312  groupName, #name \
313  }
314 
315 #define CAFFE_AVG_EXPORTED_STAT(name) \
316  AvgExportedStat name { \
317  groupName, #name \
318  }
319 
320 #define CAFFE_STDDEV_EXPORTED_STAT(name) \
321  StdDevExportedStat name { \
322  groupName, #name \
323  }
324 
325 #define CAFFE_DETAILED_EXPORTED_STAT(name) \
326  DetailedExportedStat name { \
327  groupName, #name \
328  }
329 
330 #define CAFFE_STAT(name) \
331  Stat name { \
332  groupName, #name \
333  }
334 
335 #define CAFFE_EVENT(stats, field, ...) \
336  { \
337  auto __caffe_event_value_ = stats.field.increment(__VA_ARGS__); \
338  CAFFE_SDT( \
339  field, \
340  stats.field.groupName.c_str(), \
341  __caffe_event_value_, \
342  ##__VA_ARGS__); \
343  }
344 
345 #define CAFFE_DURATION(stats, field, ...) \
346  if (auto g = detail::ScopeGuard([&](int64_t nanos) { \
347  CAFFE_EVENT(stats, field, nanos, ##__VA_ARGS__); \
348  }))
349 }
Copyright (c) 2016-present, Facebook, Inc.
std::vector< ExportedStatValue > ExportedStatList
Holds names and values of counters exported from a StatRegistry.
Definition: stats.h:56
static StatRegistry & get()
Retrieve the singleton StatRegistry, which gets populated through the CAFFE_EVENT macro...
Definition: stats.cc:65
Holds a map of atomic counters keyed by name.
Definition: stats.h:133