Logo ROOT  
Reference Guide
Loading...
Searching...
No Matches
RNTupleMetrics.hxx
Go to the documentation of this file.
1/// \file ROOT/RNTupleMetrics.hxx
2/// \author Jakob Blomer <jblomer@cern.ch>
3/// \date 2019-08-27
4/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
5/// is welcome!
6
7/*************************************************************************
8 * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. *
9 * All rights reserved. *
10 * *
11 * For the licensing terms see $ROOTSYS/LICENSE. *
12 * For the list of contributors see $ROOTSYS/README/CREDITS. *
13 *************************************************************************/
14
15#ifndef ROOT_RNTupleMetrics
16#define ROOT_RNTupleMetrics
17
18#include <ROOT/RConfig.hxx>
19#include <string_view>
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 <functional>
28#include <limits>
29#include <memory>
30#include <ostream>
31#include <string>
32#include <type_traits>
33#include <vector>
34#include <utility>
35
36namespace ROOT {
37namespace Experimental {
38namespace Detail {
39
40class RNTupleMetrics;
41
42// clang-format off
43/**
44\class ROOT::Experimental::Detail::RNTuplePerfCounter
45\ingroup NTuple
46\brief A performance counter with a name and a unit, which can be activated on demand
47
48Derived classes decide on the counter type and implement printing of the value.
49*/
50// clang-format on
52private:
53 /// Symbol to split name, unit, description, and value when printing
54 static constexpr char kFieldSeperator = '|';
55
56 std::string fName;
57 std::string fUnit;
58 std::string fDescription;
59 bool fIsEnabled = false;
60
61public:
62 RNTuplePerfCounter(const std::string &name, const std::string &unit, const std::string &desc)
63 : fName(name), fUnit(unit), fDescription(desc) {}
64 virtual ~RNTuplePerfCounter();
65 void Enable() { fIsEnabled = true; }
66 bool IsEnabled() const { return fIsEnabled; }
67 const std::string &GetName() const { return fName; }
68 const std::string &GetDescription() const { return fDescription; }
69 const std::string &GetUnit() const { return fUnit; }
70
71 virtual std::int64_t GetValueAsInt() const = 0;
72 virtual std::string GetValueAsString() const = 0;
73 std::string ToString() const;
74};
75
76
77// clang-format off
78/**
79\class ROOT::Experimental::Detail::RNTuplePlainCounter
80\ingroup NTuple
81\brief A non thread-safe integral performance counter
82*/
83// clang-format on
85private:
86 std::int64_t fCounter = 0;
87
88public:
89 RNTuplePlainCounter(const std::string &name, const std::string &unit, const std::string &desc)
90 : RNTuplePerfCounter(name, unit, desc)
91 {
92 }
93
96 R__ALWAYS_INLINE void Add(int64_t delta) { fCounter += delta; }
97 R__ALWAYS_INLINE int64_t GetValue() const { return fCounter; }
98 R__ALWAYS_INLINE void SetValue(int64_t val) { fCounter = val; }
99 std::int64_t GetValueAsInt() const override { return fCounter; }
100 std::string GetValueAsString() const override { return std::to_string(fCounter); }
101};
102
103
104// clang-format off
105/**
106\class ROOT::Experimental::Detail::RNTupleAtomicCounter
107\ingroup NTuple
108\brief A thread-safe integral performance counter
109*/
110// clang-format on
112private:
113 std::atomic<std::int64_t> fCounter{0};
114
115public:
116 RNTupleAtomicCounter(const std::string &name, const std::string &unit, const std::string &desc)
117 : RNTuplePerfCounter(name, unit, desc) { }
118
120 void Inc() {
121 if (R__unlikely(IsEnabled()))
122 ++fCounter;
123 }
124
126 void Dec() {
127 if (R__unlikely(IsEnabled()))
128 --fCounter;
129 }
130
132 void Add(int64_t delta) {
133 if (R__unlikely(IsEnabled()))
134 fCounter += delta;
135 }
136
138 int64_t XAdd(int64_t delta) {
139 if (R__unlikely(IsEnabled()))
140 return fCounter.fetch_add(delta);
141 return 0;
142 }
143
145 int64_t GetValue() const {
146 if (R__unlikely(IsEnabled()))
147 return fCounter.load();
148 return 0;
149 }
150
152 void SetValue(int64_t val) {
153 if (R__unlikely(IsEnabled()))
154 fCounter.store(val);
155 }
156
157 std::int64_t GetValueAsInt() const override { return GetValue(); }
158 std::string GetValueAsString() const override { return std::to_string(GetValue()); }
159};
160
161
162// clang-format off
163/**
164\class ROOT::Experimental::Detail::RNTupleCalcPerf
165\ingroup NTuple
166\brief A metric element that computes its floating point value from other counters.
167*/
168// clang-format on
170public:
171 using MetricFunc_t = std::function<std::pair<bool, double>(const RNTupleMetrics &)>;
172
173private:
176
177public:
178 RNTupleCalcPerf(const std::string &name, const std::string &unit, const std::string &desc,
179 RNTupleMetrics &metrics, MetricFunc_t &&func)
180 : RNTuplePerfCounter(name, unit, desc), fMetrics(metrics), fFunc(std::move(func))
181 {
182 }
183
184 double GetValue() const {
185 auto ret = fFunc(fMetrics);
186 if (ret.first)
187 return ret.second;
188 return std::numeric_limits<double>::quiet_NaN();
189 }
190
191 std::int64_t GetValueAsInt() const override {
192 return static_cast<std::int64_t>(GetValue());
193 }
194
195 std::string GetValueAsString() const override {
196 return std::to_string(GetValue());
197 }
198};
199
200// clang-format off
201/**
202\class ROOT::Experimental::Detail::RNTupleTickCounter
203\ingroup NTuple
204\brief A counter for CPU ticks.
205
206Whether this counter is thread-safe depends on BaseCounterT, see RNTuplePlainCounter and RNTupleAtomicCounter.
207
208When printing, the value is converted from ticks to nanoseconds.
209*/
210// clang-format on
211template <typename BaseCounterT>
213public:
214 RNTupleTickCounter(const std::string &name, const std::string &unit, const std::string &desc)
215 : BaseCounterT(name, unit, desc)
216 {
217 R__ASSERT(unit == "ns");
218 }
219
220 std::int64_t GetValueAsInt() const final {
221 auto ticks = BaseCounterT::GetValue();
222 return std::uint64_t((double(ticks) / double(CLOCKS_PER_SEC)) * (1000. * 1000. * 1000.));
223 }
224
225 std::string GetValueAsString() const final {
226 return std::to_string(GetValueAsInt());
227 }
228};
229
230
231// clang-format off
232/**
233\class ROOT::Experimental::Detail::RNTupleTimer
234\ingroup NTuple
235\brief Record wall time and CPU time between construction and destruction
236
237Uses RAII as a stop watch. Only the wall time counter is used to determine whether the timer is active.
238*/
239// clang-format on
240template <typename WallTimeT, typename CpuTimeT>
242private:
243 using Clock_t = std::chrono::steady_clock;
244
245 WallTimeT &fCtrWallTime;
246 CpuTimeT &fCtrCpuTicks;
247 /// Wall clock time
248 Clock_t::time_point fStartTime;
249 /// CPU time
250 clock_t fStartTicks = 0;
251
252public:
253 RNTupleTimer(WallTimeT &ctrWallTime, CpuTimeT &ctrCpuTicks)
254 : fCtrWallTime(ctrWallTime), fCtrCpuTicks(ctrCpuTicks)
255 {
256 if (!fCtrWallTime.IsEnabled())
257 return;
258 fStartTime = Clock_t::now();
259 fStartTicks = clock();
260 }
261
263 if (!fCtrWallTime.IsEnabled())
264 return;
265 auto wallTimeNs = std::chrono::duration_cast<std::chrono::nanoseconds>(Clock_t::now() - fStartTime);
266 fCtrWallTime.Add(wallTimeNs.count());
267 fCtrCpuTicks.Add(clock() - fStartTicks);
268 }
269
270 RNTupleTimer(const RNTupleTimer &other) = delete;
271 RNTupleTimer &operator =(const RNTupleTimer &other) = delete;
272};
273
276
277
278// clang-format off
279/**
280\class ROOT::Experimental::Detail::RNTupleMetrics
281\ingroup NTuple
282\brief A collection of Counter objects with a name, a unit, and a description.
283
284The class owns the counters.
285*/
286// clang-format on
288private:
289 /// Symbol to split metrics name from counter / sub metrics name
290 static constexpr char kNamespaceSeperator = '.';
291
292 std::vector<std::unique_ptr<RNTuplePerfCounter>> fCounters;
293 std::vector<RNTupleMetrics *> fObservedMetrics;
294 std::string fName;
295 bool fIsEnabled = false;
296
297 bool Contains(const std::string &name) const;
298
299public:
300 explicit RNTupleMetrics(const std::string &name) : fName(name) {}
301 RNTupleMetrics(const RNTupleMetrics &other) = delete;
302 RNTupleMetrics & operator=(const RNTupleMetrics &other) = delete;
303 RNTupleMetrics(RNTupleMetrics &&other) = default;
305 ~RNTupleMetrics() = default;
306
307 // TODO(jblomer): return a reference
308 template <typename CounterPtrT, class... Args>
309 CounterPtrT MakeCounter(const std::string &name, Args&&... args)
310 {
312 auto counter = std::make_unique<std::remove_pointer_t<CounterPtrT>>(name, std::forward<Args>(args)...);
313 auto ptrCounter = counter.get();
314 fCounters.emplace_back(std::move(counter));
315 return ptrCounter;
316 }
317
318 /// Searches counters registered in this object only. Returns nullptr if `name` is not found.
319 const RNTuplePerfCounter *GetLocalCounter(std::string_view name) const;
320 /// Searches this object and all the observed sub metrics. `name` must start with the prefix used
321 /// by this RNTupleMetrics instance. Returns nullptr if `name` is not found.
322 const RNTuplePerfCounter *GetCounter(std::string_view name) const;
323
324 void ObserveMetrics(RNTupleMetrics &observee);
325
326 void Print(std::ostream &output, const std::string &prefix = "") const;
327 void Enable();
328 bool IsEnabled() const { return fIsEnabled; }
329};
330
331} // namespace Detail
332} // namespace Experimental
333} // namespace ROOT
334
335#endif
#define R__ALWAYS_INLINE
Definition RConfig.hxx:552
#define R__unlikely(expr)
Definition RConfig.hxx:586
char * ret
Definition Rotated.cxx:221
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:125
char name[80]
Definition TGX11.cxx:148
RNTupleAtomicCounter(const std::string &name, const std::string &unit, const std::string &desc)
RNTupleCalcPerf(const std::string &name, const std::string &unit, const std::string &desc, RNTupleMetrics &metrics, MetricFunc_t &&func)
RNTupleMetrics(const std::string &name)
RNTuplePlainCounter(const std::string &name, const std::string &unit, const std::string &desc)
RNTupleTickCounter(const std::string &name, const std::string &unit, const std::string &desc)
R__ALWAYS_INLINE void SetValue(int64_t val)
R__ALWAYS_INLINE int64_t XAdd(int64_t delta)
RNTupleAtomicCounter(const std::string &name, const std::string &unit, const std::string &desc)
R__ALWAYS_INLINE void Add(int64_t delta)
std::int64_t GetValueAsInt() const override
std::function< std::pair< bool, double >(const RNTupleMetrics &)> MetricFunc_t
std::string GetValueAsString() const override
RNTupleCalcPerf(const std::string &name, const std::string &unit, const std::string &desc, RNTupleMetrics &metrics, MetricFunc_t &&func)
A collection of Counter objects with a name, a unit, and a description.
const RNTuplePerfCounter * GetCounter(std::string_view name) const
Searches this object and all the observed sub metrics.
RNTupleMetrics & operator=(const RNTupleMetrics &other)=delete
void ObserveMetrics(RNTupleMetrics &observee)
RNTupleMetrics & operator=(RNTupleMetrics &&other)=default
const RNTuplePerfCounter * GetLocalCounter(std::string_view name) const
Searches counters registered in this object only. Returns nullptr if name is not found.
std::vector< std::unique_ptr< RNTuplePerfCounter > > fCounters
RNTupleMetrics(RNTupleMetrics &&other)=default
CounterPtrT MakeCounter(const std::string &name, Args &&... args)
bool Contains(const std::string &name) const
std::vector< RNTupleMetrics * > fObservedMetrics
void Print(std::ostream &output, const std::string &prefix="") const
RNTupleMetrics(const RNTupleMetrics &other)=delete
static constexpr char kNamespaceSeperator
Symbol to split metrics name from counter / sub metrics name.
A performance counter with a name and a unit, which can be activated on demand.
virtual std::string GetValueAsString() const =0
static constexpr char kFieldSeperator
Symbol to split name, unit, description, and value when printing.
virtual std::int64_t GetValueAsInt() const =0
RNTuplePerfCounter(const std::string &name, const std::string &unit, const std::string &desc)
RNTuplePlainCounter(const std::string &name, const std::string &unit, const std::string &desc)
R__ALWAYS_INLINE int64_t GetValue() const
R__ALWAYS_INLINE void SetValue(int64_t val)
R__ALWAYS_INLINE void Add(int64_t delta)
RNTupleTickCounter(const std::string &name, const std::string &unit, const std::string &desc)
Record wall time and CPU time between construction and destruction.
RNTupleTimer(WallTimeT &ctrWallTime, CpuTimeT &ctrCpuTicks)
RNTupleTimer(const RNTupleTimer &other)=delete
RNTupleTimer & operator=(const RNTupleTimer &other)=delete
RNTupleTimer< RNTupleAtomicCounter, RNTupleTickCounter< RNTupleAtomicCounter > > RNTupleAtomicTimer
RNTupleTimer< RNTuplePlainCounter, RNTupleTickCounter< RNTuplePlainCounter > > RNTuplePlainTimer
Namespace for ROOT features in testing.
Definition TROOT.h:100