File indexing completed on 2025-01-30 10:22:37
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016 #ifndef ROOT7_RNTupleMetrics
0017 #define ROOT7_RNTupleMetrics
0018
0019 #include <ROOT/RConfig.hxx>
0020 #include <string_view>
0021
0022 #include <TError.h>
0023
0024 #include <atomic>
0025 #include <chrono>
0026 #include <cstdint>
0027 #include <ctime> // for CPU time measurement with clock()
0028 #include <functional>
0029 #include <limits>
0030 #include <memory>
0031 #include <ostream>
0032 #include <string>
0033 #include <vector>
0034 #include <utility>
0035
0036 namespace ROOT {
0037 namespace Experimental {
0038 namespace Detail {
0039
0040 class RNTupleMetrics;
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051 class RNTuplePerfCounter {
0052 private:
0053
0054 static constexpr char kFieldSeperator = '|';
0055
0056 std::string fName;
0057 std::string fUnit;
0058 std::string fDescription;
0059 bool fIsEnabled = false;
0060
0061 public:
0062 RNTuplePerfCounter(const std::string &name, const std::string &unit, const std::string &desc)
0063 : fName(name), fUnit(unit), fDescription(desc) {}
0064 virtual ~RNTuplePerfCounter();
0065 void Enable() { fIsEnabled = true; }
0066 bool IsEnabled() const { return fIsEnabled; }
0067 std::string GetName() const { return fName; }
0068 std::string GetDescription() const { return fDescription; }
0069 std::string GetUnit() const { return fUnit; }
0070
0071 virtual std::int64_t GetValueAsInt() const = 0;
0072 virtual std::string GetValueAsString() const = 0;
0073 std::string ToString() const;
0074 };
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084 class RNTuplePlainCounter : public RNTuplePerfCounter {
0085 private:
0086 std::int64_t fCounter = 0;
0087
0088 public:
0089 RNTuplePlainCounter(const std::string &name, const std::string &unit, const std::string &desc)
0090 : RNTuplePerfCounter(name, unit, desc)
0091 {
0092 }
0093
0094 R__ALWAYS_INLINE void Inc() { ++fCounter; }
0095 R__ALWAYS_INLINE void Dec() { --fCounter; }
0096 R__ALWAYS_INLINE void Add(int64_t delta) { fCounter += delta; }
0097 R__ALWAYS_INLINE int64_t GetValue() const { return fCounter; }
0098 R__ALWAYS_INLINE void SetValue(int64_t val) { fCounter = val; }
0099 std::int64_t GetValueAsInt() const override { return fCounter; }
0100 std::string GetValueAsString() const override { return std::to_string(fCounter); }
0101 };
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111 class RNTupleAtomicCounter : public RNTuplePerfCounter {
0112 private:
0113 std::atomic<std::int64_t> fCounter{0};
0114
0115 public:
0116 RNTupleAtomicCounter(const std::string &name, const std::string &unit, const std::string &desc)
0117 : RNTuplePerfCounter(name, unit, desc) { }
0118
0119 R__ALWAYS_INLINE
0120 void Inc() {
0121 if (R__unlikely(IsEnabled()))
0122 ++fCounter;
0123 }
0124
0125 R__ALWAYS_INLINE
0126 void Dec() {
0127 if (R__unlikely(IsEnabled()))
0128 --fCounter;
0129 }
0130
0131 R__ALWAYS_INLINE
0132 void Add(int64_t delta) {
0133 if (R__unlikely(IsEnabled()))
0134 fCounter += delta;
0135 }
0136
0137 R__ALWAYS_INLINE
0138 int64_t XAdd(int64_t delta) {
0139 if (R__unlikely(IsEnabled()))
0140 return fCounter.fetch_add(delta);
0141 return 0;
0142 }
0143
0144 R__ALWAYS_INLINE
0145 int64_t GetValue() const {
0146 if (R__unlikely(IsEnabled()))
0147 return fCounter.load();
0148 return 0;
0149 }
0150
0151 R__ALWAYS_INLINE
0152 void SetValue(int64_t val) {
0153 if (R__unlikely(IsEnabled()))
0154 fCounter.store(val);
0155 }
0156
0157 std::int64_t GetValueAsInt() const override { return GetValue(); }
0158 std::string GetValueAsString() const override { return std::to_string(GetValue()); }
0159 };
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169 class RNTupleCalcPerf : public RNTuplePerfCounter {
0170 public:
0171 using MetricFunc_t = std::function<std::pair<bool, double>(const RNTupleMetrics &)>;
0172
0173 private:
0174 RNTupleMetrics &fMetrics;
0175 const MetricFunc_t fFunc;
0176
0177 public:
0178 RNTupleCalcPerf(const std::string &name, const std::string &unit, const std::string &desc,
0179 RNTupleMetrics &metrics, MetricFunc_t &&func)
0180 : RNTuplePerfCounter(name, unit, desc), fMetrics(metrics), fFunc(std::move(func))
0181 {
0182 }
0183
0184 double GetValue() const {
0185 auto ret = fFunc(fMetrics);
0186 if (ret.first)
0187 return ret.second;
0188 return std::numeric_limits<double>::quiet_NaN();
0189 }
0190
0191 std::int64_t GetValueAsInt() const override {
0192 return static_cast<std::int64_t>(GetValue());
0193 }
0194
0195 std::string GetValueAsString() const override {
0196 return std::to_string(GetValue());
0197 }
0198 };
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209 template <typename BaseCounterT>
0210 class RNTupleTickCounter : public BaseCounterT {
0211 public:
0212 RNTupleTickCounter(const std::string &name, const std::string &unit, const std::string &desc)
0213 : BaseCounterT(name, unit, desc)
0214 {
0215 R__ASSERT(unit == "ns");
0216 }
0217
0218 std::int64_t GetValueAsInt() const final {
0219 auto ticks = BaseCounterT::GetValue();
0220 return std::uint64_t((double(ticks) / double(CLOCKS_PER_SEC)) * (1000. * 1000. * 1000.));
0221 }
0222
0223 std::string GetValueAsString() const final {
0224 return std::to_string(GetValueAsInt());
0225 }
0226 };
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236
0237
0238 template <typename WallTimeT, typename CpuTimeT>
0239 class RNTupleTimer {
0240 private:
0241 using Clock_t = std::chrono::steady_clock;
0242
0243 WallTimeT &fCtrWallTime;
0244 CpuTimeT &fCtrCpuTicks;
0245
0246 Clock_t::time_point fStartTime;
0247
0248 clock_t fStartTicks = 0;
0249
0250 public:
0251 RNTupleTimer(WallTimeT &ctrWallTime, CpuTimeT &ctrCpuTicks)
0252 : fCtrWallTime(ctrWallTime), fCtrCpuTicks(ctrCpuTicks)
0253 {
0254 if (!fCtrWallTime.IsEnabled())
0255 return;
0256 fStartTime = Clock_t::now();
0257 fStartTicks = clock();
0258 }
0259
0260 ~RNTupleTimer() {
0261 if (!fCtrWallTime.IsEnabled())
0262 return;
0263 auto wallTimeNs = std::chrono::duration_cast<std::chrono::nanoseconds>(Clock_t::now() - fStartTime);
0264 fCtrWallTime.Add(wallTimeNs.count());
0265 fCtrCpuTicks.Add(clock() - fStartTicks);
0266 }
0267
0268 RNTupleTimer(const RNTupleTimer &other) = delete;
0269 RNTupleTimer &operator =(const RNTupleTimer &other) = delete;
0270 };
0271
0272 using RNTuplePlainTimer = RNTupleTimer<RNTuplePlainCounter, RNTupleTickCounter<RNTuplePlainCounter>>;
0273 using RNTupleAtomicTimer = RNTupleTimer<RNTupleAtomicCounter, RNTupleTickCounter<RNTupleAtomicCounter>>;
0274
0275
0276
0277
0278
0279
0280
0281
0282
0283
0284
0285 class RNTupleMetrics {
0286 private:
0287
0288 static constexpr char kNamespaceSeperator = '.';
0289
0290 std::vector<std::unique_ptr<RNTuplePerfCounter>> fCounters;
0291 std::vector<RNTupleMetrics *> fObservedMetrics;
0292 std::string fName;
0293 bool fIsEnabled = false;
0294
0295 bool Contains(const std::string &name) const;
0296
0297 public:
0298 explicit RNTupleMetrics(const std::string &name) : fName(name) {}
0299 RNTupleMetrics(const RNTupleMetrics &other) = delete;
0300 RNTupleMetrics & operator=(const RNTupleMetrics &other) = delete;
0301 RNTupleMetrics(RNTupleMetrics &&other) = default;
0302 RNTupleMetrics & operator=(RNTupleMetrics &&other) = default;
0303 ~RNTupleMetrics() = default;
0304
0305
0306 template <typename CounterPtrT, class... Args>
0307 CounterPtrT MakeCounter(const std::string &name, Args&&... args)
0308 {
0309 R__ASSERT(!Contains(name));
0310 auto counter = std::make_unique<std::remove_pointer_t<CounterPtrT>>(name, std::forward<Args>(args)...);
0311 auto ptrCounter = counter.get();
0312 fCounters.emplace_back(std::move(counter));
0313 return ptrCounter;
0314 }
0315
0316
0317 const RNTuplePerfCounter *GetLocalCounter(std::string_view name) const;
0318
0319
0320 const RNTuplePerfCounter *GetCounter(std::string_view name) const;
0321
0322 void ObserveMetrics(RNTupleMetrics &observee);
0323
0324 void Print(std::ostream &output, const std::string &prefix = "") const;
0325 void Enable();
0326 bool IsEnabled() const { return fIsEnabled; }
0327 };
0328
0329 }
0330 }
0331 }
0332
0333 #endif