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