Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
RNTupleMetrics.hxx
Go to the documentation of this file.
1 /// \file ROOT/RNTupleMetrics.hxx
2 /// \ingroup NTuple ROOT7
3 /// \author Jakob Blomer <jblomer@cern.ch>
4 /// \date 2019-08-27
5 /// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
6 /// is welcome!
7 
8 /*************************************************************************
9  * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. *
10  * All rights reserved. *
11  * *
12  * For the licensing terms see $ROOTSYS/LICENSE. *
13  * For the list of contributors see $ROOTSYS/README/CREDITS. *
14  *************************************************************************/
15 
16 #ifndef ROOT7_RNTupleMetrics
17 #define ROOT7_RNTupleMetrics
18 
19 #include <ROOT/RConfig.hxx>
20 
21 #include <TError.h>
22 
23 #include <atomic>
24 #include <chrono>
25 #include <cstdint>
26 #include <ctime> // for CPU time measurement with clock()
27 #include <memory>
28 #include <ostream>
29 #include <string>
30 #include <vector>
31 #include <utility>
32 
33 namespace ROOT {
34 namespace Experimental {
35 namespace Detail {
36 
37 // clang-format off
38 /**
39 \class ROOT::Experimental::Detail::RNTuplePerfCounter
40 \ingroup NTuple
41 \brief A performance counter with a name and a unit, which can be activated on demand
42 
43 Derived classes decide on the counter type and implement printing of the value.
44 */
45 // clang-format on
46 class RNTuplePerfCounter {
47 private:
48  /// Symbol to split name, unit, description, and value when printing
49  static constexpr char kFieldSeperator = '|';
50 
51  std::string fName;
52  std::string fUnit;
53  std::string fDescription;
54  bool fIsEnabled = false;
55 
56 public:
57  RNTuplePerfCounter(const std::string &name, const std::string &unit, const std::string &desc)
58  : fName(name), fUnit(unit), fDescription(desc) {}
59  virtual ~RNTuplePerfCounter();
60  void Enable() { fIsEnabled = true; }
61  bool IsEnabled() const { return fIsEnabled; }
62  std::string GetName() const { return fName; }
63  std::string GetDescription() const { return fDescription; }
64  std::string GetUnit() const { return fUnit; }
65 
66  virtual std::string ValueToString() const = 0;
67  std::string ToString() const;
68 };
69 
70 
71 // clang-format off
72 /**
73 \class ROOT::Experimental::Detail::RNTuplePlainCounter
74 \ingroup NTuple
75 \brief A non thread-safe integral performance counter
76 */
77 // clang-format on
78 class RNTuplePlainCounter : public RNTuplePerfCounter {
79 private:
80  std::int64_t fCounter = 0;
81 
82 public:
83  RNTuplePlainCounter(const std::string &name, const std::string &unit, const std::string &desc)
84  : RNTuplePerfCounter(name, unit, desc)
85  {
86  }
87 
88  R__ALWAYS_INLINE void Inc() { ++fCounter; }
89  R__ALWAYS_INLINE void Dec() { --fCounter; }
90  R__ALWAYS_INLINE void Add(int64_t delta) { fCounter += delta; }
91  R__ALWAYS_INLINE int64_t GetValue() const { return fCounter; }
92  R__ALWAYS_INLINE void SetValue(int64_t val) { fCounter = val; }
93  std::string ValueToString() const override { return std::to_string(fCounter); }
94 };
95 
96 
97 // clang-format off
98 /**
99 \class ROOT::Experimental::Detail::RNTupleAtomicCounter
100 \ingroup NTuple
101 \brief A thread-safe integral performance counter
102 */
103 // clang-format on
104 class RNTupleAtomicCounter : public RNTuplePerfCounter {
105 private:
106  std::atomic<std::int64_t> fCounter{0};
107 
108 public:
109  RNTupleAtomicCounter(const std::string &name, const std::string &unit, const std::string &desc)
110  : RNTuplePerfCounter(name, unit, desc) { }
111 
112  R__ALWAYS_INLINE
113  void Inc() {
114  if (R__unlikely(IsEnabled()))
115  ++fCounter;
116  }
117 
118  R__ALWAYS_INLINE
119  void Dec() {
120  if (R__unlikely(IsEnabled()))
121  --fCounter;
122  }
123 
124  R__ALWAYS_INLINE
125  void Add(int64_t delta) {
126  if (R__unlikely(IsEnabled()))
127  fCounter += delta;
128  }
129 
130  R__ALWAYS_INLINE
131  int64_t XAdd(int64_t delta) {
132  if (R__unlikely(IsEnabled()))
133  return fCounter.fetch_add(delta);
134  return 0;
135  }
136 
137  R__ALWAYS_INLINE
138  int64_t GetValue() const {
139  if (R__unlikely(IsEnabled()))
140  return fCounter.load();
141  return 0;
142  }
143 
144  R__ALWAYS_INLINE
145  void SetValue(int64_t val) {
146  if (R__unlikely(IsEnabled()))
147  fCounter.store(val);
148  }
149 
150  std::string ValueToString() const override { return std::to_string(GetValue()); }
151 };
152 
153 
154 // clang-format off
155 /**
156 \class ROOT::Experimental::Detail::RNTupleTickCounter
157 \ingroup NTuple
158 \brief An either thread-safe or non thread safe counter for CPU ticks
159 
160 On print, the value is converted from ticks to ns.
161 */
162 // clang-format on
163 template <typename BaseCounterT>
164 class RNTupleTickCounter : public BaseCounterT {
165 public:
166  RNTupleTickCounter(const std::string &name, const std::string &unit, const std::string &desc)
167  : BaseCounterT(name, unit, desc)
168  {
169  R__ASSERT(unit == "ns");
170  }
171 
172  std::string ValueToString() const final {
173  auto ticks = BaseCounterT::GetValue();
174  return std::to_string(std::uint64_t(
175  (double(ticks) / double(CLOCKS_PER_SEC)) * (1000. * 1000. * 1000.)));
176  }
177 };
178 
179 
180 // clang-format off
181 /**
182 \class ROOT::Experimental::Detail::RNTupleTimer
183 \ingroup NTuple
184 \brief Record wall time and CPU time between construction and destruction
185 
186 Uses RAII as a stop watch. Only the wall time counter is used to determine whether the timer is active.
187 */
188 // clang-format on
189 template <typename WallTimeT, typename CpuTimeT>
190 class RNTupleTimer {
191 private:
192  using Clock_t = std::chrono::steady_clock;
193 
194  WallTimeT &fCtrWallTime;
195  CpuTimeT &fCtrCpuTicks;
196  /// Wall clock time
197  Clock_t::time_point fStartTime;
198  /// CPU time
199  clock_t fStartTicks;
200 
201 public:
202  RNTupleTimer(WallTimeT &ctrWallTime, CpuTimeT &ctrCpuTicks)
203  : fCtrWallTime(ctrWallTime), fCtrCpuTicks(ctrCpuTicks)
204  {
205  if (!fCtrWallTime.IsEnabled())
206  return;
207  fStartTime = Clock_t::now();
208  fStartTicks = clock();
209  }
210 
211  ~RNTupleTimer() {
212  if (!fCtrWallTime.IsEnabled())
213  return;
214  auto wallTimeNs = std::chrono::duration_cast<std::chrono::nanoseconds>(Clock_t::now() - fStartTime);
215  fCtrWallTime.Add(wallTimeNs.count());
216  fCtrCpuTicks.Add(clock() - fStartTicks);
217  }
218 
219  RNTupleTimer(const RNTupleTimer &other) = delete;
220  RNTupleTimer &operator =(const RNTupleTimer &other) = delete;
221 };
222 
223 using RNTuplePlainTimer = RNTupleTimer<RNTuplePlainCounter, RNTupleTickCounter<RNTuplePlainCounter>>;
224 using RNTupleAtomicTimer = RNTupleTimer<RNTupleAtomicCounter, RNTupleTickCounter<RNTupleAtomicCounter>>;
225 
226 
227 // clang-format off
228 /**
229 \class ROOT::Experimental::Detail::RNTupleMetrics
230 \ingroup NTuple
231 \brief A collection of Counter objects with a name, a unit, and a description.
232 
233 The class owns the counters; on registration of a new
234 */
235 // clang-format on
236 class RNTupleMetrics {
237 private:
238  /// Symbol to split metrics name from counter / sub metrics name
239  static constexpr char kNamespaceSeperator = '.';
240 
241  std::vector<std::unique_ptr<RNTuplePerfCounter>> fCounters;
242  std::vector<RNTupleMetrics *> fObservedMetrics;
243  std::string fName;
244  bool fIsEnabled = false;
245 
246  bool Contains(const std::string &name) const;
247 
248 public:
249  explicit RNTupleMetrics(const std::string &name) : fName(name) {}
250  RNTupleMetrics(const RNTupleMetrics &other) = delete;
251  RNTupleMetrics & operator=(const RNTupleMetrics &other) = delete;
252  ~RNTupleMetrics() = default;
253 
254  template <typename CounterPtrT>
255  CounterPtrT MakeCounter(const std::string &name, const std::string &unit, const std::string &desc)
256  {
257  R__ASSERT(!Contains(name));
258  auto counter = std::make_unique<std::remove_pointer_t<CounterPtrT>>(name, unit, desc);
259  auto ptrCounter = counter.get();
260  fCounters.emplace_back(std::move(counter));
261  return ptrCounter;
262  }
263 
264  void ObserveMetrics(RNTupleMetrics &observee);
265 
266  void Print(std::ostream &output, const std::string &prefix = "") const;
267  void Enable();
268  bool IsEnabled() const { return fIsEnabled; }
269 };
270 
271 } // namespace Detail
272 } // namespace Experimental
273 } // namespace ROOT
274 
275 #endif