File indexing completed on 2025-12-15 10:14:14
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #pragma once
0013
0014 #include <Gaudi/MonitoringHub.h>
0015
0016 #include <chrono>
0017
0018 namespace Gaudi::Accumulators {
0019 template <class Rep, class Period>
0020 auto sqrt( std::chrono::duration<Rep, Period> d );
0021 template <class Rep1, class Rep2, class Period>
0022 auto operator*( const std::chrono::duration<Rep1, Period>& lhs, const std::chrono::duration<Rep2, Period>& rhs );
0023 }
0024
0025
0026 #if defined( __GNUC__ ) && ( __GNUC__ == 11 ) && !defined( __clang__ )
0027 namespace std::chrono {
0028 template <typename Ratio>
0029 static constexpr const char* suffix( const Ratio& ) {
0030 if constexpr ( std::ratio_equal_v<Ratio, std::ratio<1>> ) {
0031 return "s";
0032 } else if constexpr ( std::ratio_equal_v<Ratio, std::milli> ) {
0033 return "ms";
0034 } else if constexpr ( std::ratio_equal_v<Ratio, std::micro> ) {
0035 return "us";
0036 } else if constexpr ( std::ratio_equal_v<Ratio, std::nano> ) {
0037 return "ns";
0038 } else if constexpr ( std::ratio_equal_v<Ratio, std::ratio<60>> ) {
0039 return "m";
0040 } else if constexpr ( std::ratio_equal_v<Ratio, std::ratio<3600>> ) {
0041 return "h";
0042 }
0043 return "";
0044 }
0045 template <class Rep, class Period>
0046 std::ostream& operator<<( std::ostream& os, const std::chrono::duration<Rep, Period>& d ) {
0047 return os << d.count() << suffix( Period{} );
0048 }
0049 }
0050 #endif
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233
0234 #include <atomic>
0235 #include <boost/format.hpp>
0236 #include <cmath>
0237 #include <iostream>
0238 #include <limits>
0239 #include <nlohmann/json.hpp>
0240 #include <sstream>
0241 #include <tuple>
0242 #include <type_traits>
0243 #include <utility>
0244
0245 #include <GaudiKernel/CommonMessaging.h>
0246 #include <GaudiKernel/MsgStream.h>
0247 #include <GaudiKernel/detected.h>
0248
0249
0250 namespace nlohmann {
0251 template <class Rep, class Period>
0252 struct adl_serializer<std::chrono::duration<Rep, Period>> {
0253 static void to_json( json& j, const std::chrono::duration<Rep, Period>& d ) { j = d.count(); }
0254 static void from_json( const json& j, std::chrono::duration<Rep, Period>& d ) {
0255 d = std::chrono::duration<Rep, Period>{ j.get<Rep>() };
0256 }
0257 };
0258 }
0259
0260 namespace Gaudi::Accumulators {
0261
0262
0263 enum class atomicity { none, full };
0264
0265
0266 template <class T>
0267 auto sqrt( T d );
0268
0269
0270
0271
0272 template <typename T, T N>
0273 struct Constant {
0274 template <typename U>
0275 constexpr T operator()( U&& ) const noexcept {
0276 return N;
0277 }
0278 };
0279
0280
0281
0282
0283 struct Identity {
0284 template <typename U>
0285 constexpr decltype( auto ) operator()( U&& v ) const noexcept {
0286 return std::forward<U>( v );
0287 }
0288 };
0289
0290
0291
0292
0293 struct Square {
0294 template <typename U>
0295 constexpr decltype( auto ) operator()( U&& v ) const noexcept {
0296 return v * v;
0297 }
0298 };
0299
0300
0301
0302
0303 template <typename T, typename = int>
0304 using has_fetch_add_ = decltype( std::declval<T&>().fetch_add( 0 ) );
0305 template <typename T>
0306 inline constexpr bool has_fetch_add_v = Gaudi::cpp17::is_detected_v<has_fetch_add_, T>;
0307
0308
0309
0310
0311 template <typename Arithmetic, typename Result = double>
0312 using fp_result_type = std::conditional_t<std::is_integral_v<Arithmetic>, Result, Arithmetic>;
0313
0314
0315
0316
0317 template <typename Arithmetic, atomicity Atomicity>
0318 struct BaseValueHandler;
0319
0320
0321
0322
0323 template <typename Arithmetic>
0324 struct BaseValueHandler<Arithmetic, atomicity::none> {
0325 using OutputType = Arithmetic;
0326 using InternalType = Arithmetic;
0327 static constexpr OutputType getValue( const InternalType& v ) noexcept { return v; }
0328 static Arithmetic exchange( InternalType& v, Arithmetic newv ) noexcept { return std::exchange( v, newv ); }
0329 };
0330
0331
0332
0333
0334 template <typename Arithmetic>
0335 struct BaseValueHandler<Arithmetic, atomicity::full> {
0336 using OutputType = Arithmetic;
0337 using InternalType = std::atomic<Arithmetic>;
0338 static constexpr OutputType getValue( const InternalType& v ) noexcept {
0339 return v.load( std::memory_order_relaxed );
0340 }
0341 static Arithmetic exchange( InternalType& v, Arithmetic newv ) noexcept { return v.exchange( newv ); }
0342 };
0343
0344
0345
0346
0347
0348 template <typename Arithmetic, atomicity Atomicity>
0349 struct Adder;
0350
0351
0352
0353
0354 template <typename Arithmetic>
0355 struct Adder<Arithmetic, atomicity::none> : BaseValueHandler<Arithmetic, atomicity::none> {
0356 using typename BaseValueHandler<Arithmetic, atomicity::none>::OutputType;
0357 using typename BaseValueHandler<Arithmetic, atomicity::none>::InternalType;
0358 static constexpr OutputType DefaultValue() { return Arithmetic{}; }
0359 static void merge( InternalType& a, Arithmetic b ) noexcept { a += b; }
0360 };
0361
0362
0363
0364
0365 template <typename AtomicType, typename Arithmetic>
0366 void fetch_add( AtomicType& atVar, Arithmetic value ) {
0367 if constexpr ( has_fetch_add_v<AtomicType> ) {
0368 atVar.fetch_add( value, std::memory_order_relaxed );
0369 } else {
0370 auto current = BaseValueHandler<Arithmetic, atomicity::full>::getValue( atVar );
0371 while ( !atVar.compare_exchange_weak( current, current + value ) )
0372 ;
0373 }
0374 }
0375
0376
0377
0378
0379 template <typename Arithmetic>
0380 struct Adder<Arithmetic, atomicity::full> : BaseValueHandler<Arithmetic, atomicity::full> {
0381 using typename BaseValueHandler<Arithmetic, atomicity::full>::OutputType;
0382 using typename BaseValueHandler<Arithmetic, atomicity::full>::InternalType;
0383 static constexpr OutputType DefaultValue() { return Arithmetic{}; }
0384 static void merge( InternalType& a, Arithmetic b ) noexcept {
0385 if constexpr ( !std::is_floating_point_v<Arithmetic> ) {
0386 if ( DefaultValue() == b ) return;
0387 }
0388 fetch_add( a, b );
0389 }
0390 };
0391
0392
0393
0394
0395
0396 template <typename Arithmetic, atomicity Atomicity, typename Compare, Arithmetic ( *Initial )()>
0397 struct Extremum;
0398
0399
0400
0401
0402 template <typename Arithmetic, typename Compare, Arithmetic ( *Initial )()>
0403 struct Extremum<Arithmetic, atomicity::none, Compare, Initial> : BaseValueHandler<Arithmetic, atomicity::none> {
0404 using typename BaseValueHandler<Arithmetic, atomicity::none>::OutputType;
0405 using typename BaseValueHandler<Arithmetic, atomicity::none>::InternalType;
0406 static constexpr OutputType DefaultValue() { return Initial(); }
0407 static void merge( InternalType& a, Arithmetic b ) noexcept {
0408 if ( Compare{}( b, a ) ) a = b;
0409 }
0410 };
0411
0412
0413
0414
0415 template <typename Arithmetic, typename Compare, Arithmetic ( *Initial )()>
0416 struct Extremum<Arithmetic, atomicity::full, Compare, Initial> : BaseValueHandler<Arithmetic, atomicity::full> {
0417 using typename BaseValueHandler<Arithmetic, atomicity::full>::OutputType;
0418 using typename BaseValueHandler<Arithmetic, atomicity::full>::InternalType;
0419 static constexpr OutputType DefaultValue() { return Initial(); }
0420 static void merge( InternalType& a, Arithmetic b ) noexcept {
0421 Arithmetic prev_value = BaseValueHandler<Arithmetic, atomicity::full>::getValue( a );
0422 while ( Compare{}( b, prev_value ) && !a.compare_exchange_weak( prev_value, b ) )
0423 ;
0424 }
0425 };
0426
0427
0428
0429
0430
0431 template <typename Arithmetic, atomicity Atomicity = atomicity::full>
0432 using Minimum = Extremum<Arithmetic, Atomicity, std::less<Arithmetic>, std::numeric_limits<Arithmetic>::max>;
0433
0434
0435
0436
0437
0438 template <typename Arithmetic, atomicity Atomicity = atomicity::full>
0439 using Maximum = Extremum<Arithmetic, Atomicity, std::greater<Arithmetic>, std::numeric_limits<Arithmetic>::lowest>;
0440
0441
0442
0443
0444
0445
0446 struct construct_empty_t {
0447 explicit construct_empty_t() = default;
0448 };
0449 constexpr construct_empty_t construct_empty{};
0450
0451
0452
0453
0454
0455
0456
0457
0458
0459
0460
0461
0462
0463
0464
0465
0466
0467
0468 template <typename InputTypeT, typename InnerType, atomicity Atomicity = atomicity::full,
0469 typename InputTransform = Identity, typename OutputTransform = Identity,
0470 typename ValueHandler = Adder<InnerType, Atomicity>>
0471 class GenericAccumulator {
0472 template <typename, typename, atomicity, typename, typename, typename>
0473 friend class GenericAccumulator;
0474
0475 public:
0476 using InputType = InputTypeT;
0477 using OutputType = std::decay_t<std::invoke_result_t<OutputTransform, InnerType>>;
0478 using InternalType = InnerType;
0479 using JSONStringEntriesType = std::string;
0480 GenericAccumulator operator+=( const InputType by ) {
0481 ValueHandler::merge( m_value, InputTransform{}( by ) );
0482 return *this;
0483 }
0484 GenericAccumulator() = default;
0485
0486 template <atomicity ato, typename VH>
0487 GenericAccumulator( construct_empty_t,
0488 const GenericAccumulator<InputType, InnerType, ato, InputTransform, OutputTransform, VH>& )
0489 : GenericAccumulator() {}
0490 template <typename... Args>
0491 GenericAccumulator( std::in_place_t, Args&&... args ) : m_value( std::forward<Args>( args )... ) {}
0492 GenericAccumulator( const GenericAccumulator& other ) : m_value( ValueHandler::getValue( other.m_value ) ) {}
0493 GenericAccumulator& operator=( const GenericAccumulator& other ) {
0494 m_value = ValueHandler::getValue( other.m_value );
0495 return *this;
0496 }
0497 OutputType value() const { return OutputTransform{}( ValueHandler::getValue( m_value ) ); }
0498 void reset() { reset( ValueHandler::DefaultValue() ); }
0499 template <atomicity ato, typename VH>
0500 void mergeAndReset( GenericAccumulator<InputType, InnerType, ato, InputTransform, OutputTransform, VH>& other ) {
0501 ValueHandler::merge( m_value, VH::exchange( other.m_value, VH::DefaultValue() ) );
0502 }
0503 template <atomicity ato, typename VH>
0504 void operator+( GenericAccumulator<InputType, InnerType, ato, InputTransform, OutputTransform, VH>&& other ) {
0505 ValueHandler::merge( m_value, other.m_value );
0506 }
0507
0508 protected:
0509 GenericAccumulator( InnerType in ) : m_value( std::move( in ) ) {}
0510 auto rawValue() const { return ValueHandler::getValue( m_value ); }
0511 void reset( InnerType in ) { m_value = std::move( in ); }
0512 static InnerType extractJSONData( const nlohmann::json& j, const JSONStringEntriesType& entries ) {
0513 return j.at( entries ).get<InnerType>();
0514 }
0515
0516 private:
0517 typename ValueHandler::InternalType m_value{ ValueHandler::DefaultValue() };
0518 };
0519
0520
0521
0522
0523
0524
0525 template <typename Arithmetic, atomicity Atomicity, typename InputTypeT = Arithmetic,
0526 template <atomicity, typename> class... Bases>
0527 class AccumulatorSet : public Bases<Atomicity, Arithmetic>... {
0528 public:
0529 using InputType = InputTypeT;
0530 using OutputType = std::tuple<typename Bases<Atomicity, Arithmetic>::OutputType...>;
0531 using InternalType = std::tuple<typename Bases<Atomicity, Arithmetic>::InternalType...>;
0532 using JSONStringEntriesType = std::tuple<typename Bases<Atomicity, Arithmetic>::JSONStringEntriesType...>;
0533 constexpr AccumulatorSet() = default;
0534
0535 template <atomicity ato>
0536 AccumulatorSet( construct_empty_t, const AccumulatorSet<Arithmetic, ato, InputType, Bases...>& )
0537 : AccumulatorSet() {}
0538 AccumulatorSet& operator+=( const InputType by ) {
0539 ( Bases<Atomicity, Arithmetic>::operator+=( by ), ... );
0540 return *this;
0541 }
0542 OutputType value() const { return std::make_tuple( Bases<Atomicity, Arithmetic>::value()... ); }
0543 void reset() { ( Bases<Atomicity, Arithmetic>::reset(), ... ); }
0544 template <atomicity Ato>
0545 void mergeAndReset( AccumulatorSet<Arithmetic, Ato, InputType, Bases...>& other ) {
0546 ( Bases<Atomicity, Arithmetic>::mergeAndReset( static_cast<Bases<Ato, Arithmetic>&>( other ) ), ... );
0547 }
0548 template <atomicity Ato>
0549 void operator+( AccumulatorSet<Arithmetic, Ato, InputType, Bases...>&& other ) {
0550 ( Bases<Atomicity, Arithmetic>::operator+( static_cast<Bases<Ato, Arithmetic>&&>( other ) ), ... );
0551 }
0552
0553 protected:
0554 AccumulatorSet( const InternalType& t ) : AccumulatorSet() { reset( t ); }
0555 void reset( const InternalType& t ) {
0556 std::apply( [this]( const auto&... i ) { ( this->Bases<Atomicity, Arithmetic>::reset( i ), ... ); }, t );
0557 }
0558 static InternalType extractJSONData( const nlohmann::json& j, const JSONStringEntriesType& entries ) {
0559 return extractJSONDataHelper( j, entries, std::index_sequence_for<Bases<Atomicity, Arithmetic>...>{} );
0560 }
0561
0562 private:
0563 template <size_t... Is>
0564 static InternalType extractJSONDataHelper( const nlohmann::json& j, const JSONStringEntriesType& entries,
0565 std::index_sequence<Is...> ) {
0566 return extractJSONDataHelper( j, std::get<Is>( entries )... );
0567 }
0568 static InternalType
0569 extractJSONDataHelper( const nlohmann::json& j,
0570 typename Bases<Atomicity, Arithmetic>::JSONStringEntriesType... entries ) {
0571 return { Bases<Atomicity, Arithmetic>::extractJSONData( j, entries )... };
0572 }
0573 };
0574
0575
0576
0577
0578
0579 template <atomicity Atomicity, typename Arithmetic = double>
0580 struct MaxAccumulator
0581 : GenericAccumulator<Arithmetic, Arithmetic, Atomicity, Identity, Identity, Maximum<Arithmetic, Atomicity>> {
0582 using GenericAccumulator<Arithmetic, Arithmetic, Atomicity, Identity, Identity,
0583 Maximum<Arithmetic, Atomicity>>::GenericAccumulator;
0584 Arithmetic max() const { return this->value(); }
0585 };
0586
0587
0588
0589
0590
0591 template <atomicity Atomicity, typename Arithmetic = double>
0592 struct MinAccumulator
0593 : GenericAccumulator<Arithmetic, Arithmetic, Atomicity, Identity, Identity, Minimum<Arithmetic, Atomicity>> {
0594 using GenericAccumulator<Arithmetic, Arithmetic, Atomicity, Identity, Identity,
0595 Minimum<Arithmetic, Atomicity>>::GenericAccumulator;
0596 Arithmetic min() const { return this->value(); }
0597 };
0598
0599
0600
0601
0602
0603
0604
0605 template <atomicity Atomicity, typename Arithmetic = double>
0606 struct CountAccumulator : GenericAccumulator<Arithmetic, unsigned long, Atomicity, Constant<unsigned long, 1UL>> {
0607 using GenericAccumulator<Arithmetic, unsigned long, Atomicity, Constant<unsigned long, 1UL>>::GenericAccumulator;
0608 CountAccumulator& operator++() {
0609 ( *this ) += Arithmetic{};
0610 return *this;
0611 }
0612 CountAccumulator operator++( int ) {
0613 auto copy = *this;
0614 ++( *this );
0615 return copy;
0616 }
0617 unsigned long nEntries() const { return this->value(); }
0618 };
0619
0620
0621
0622
0623
0624 template <atomicity Atomicity, typename Arithmetic = double>
0625 struct SumAccumulator : GenericAccumulator<Arithmetic, Arithmetic, Atomicity, Identity> {
0626 using GenericAccumulator<Arithmetic, Arithmetic, Atomicity, Identity>::GenericAccumulator;
0627 Arithmetic sum() const { return this->value(); }
0628 };
0629
0630
0631
0632
0633
0634
0635 template <atomicity Atomicity, typename Arithmetic = unsigned long>
0636 struct IntegralAccumulator : GenericAccumulator<Arithmetic, Arithmetic, Atomicity, Identity> {
0637 static_assert( std::is_integral_v<Arithmetic>,
0638 "Invalid Arithmetic type for IntegralAccumulator. It must be an integral type" );
0639
0640 using GenericAccumulator<Arithmetic, Arithmetic, Atomicity, Identity>::GenericAccumulator;
0641 IntegralAccumulator& operator++() {
0642 ( *this ) += 1;
0643 return *this;
0644 }
0645 IntegralAccumulator operator++( int ) {
0646 auto copy = *this;
0647 ++( *this );
0648 return copy;
0649 }
0650 Arithmetic nEntries() const { return this->value(); }
0651 Arithmetic sum() const { return this->value(); }
0652 };
0653
0654
0655
0656
0657
0658 template <atomicity Atomicity, typename Arithmetic = double>
0659 struct SquareAccumulator : GenericAccumulator<Arithmetic, Arithmetic, Atomicity, Square> {
0660 using GenericAccumulator<Arithmetic, Arithmetic, Atomicity, Square>::GenericAccumulator;
0661 Arithmetic sum2() const { return this->value(); }
0662 };
0663
0664
0665 struct TrueTo1 {
0666 unsigned int operator()( bool v ) const { return v; }
0667 };
0668
0669
0670
0671
0672
0673
0674 template <atomicity Atomicity, typename Arithmetic>
0675 struct TrueAccumulator : GenericAccumulator<Arithmetic, unsigned long, Atomicity, TrueTo1> {
0676 using GenericAccumulator<Arithmetic, unsigned long, Atomicity, TrueTo1>::GenericAccumulator;
0677 unsigned long nTrueEntries() const { return this->value(); }
0678 };
0679
0680
0681 struct FalseTo1 {
0682 unsigned int operator()( bool v ) const { return !v; }
0683 };
0684
0685
0686
0687
0688
0689
0690 template <atomicity Atomicity, typename Arithmetic>
0691 struct FalseAccumulator : GenericAccumulator<Arithmetic, unsigned long, Atomicity, FalseTo1> {
0692 using GenericAccumulator<Arithmetic, unsigned long, Atomicity, FalseTo1>::GenericAccumulator;
0693 unsigned long nFalseEntries() const { return this->value(); }
0694 };
0695
0696
0697
0698
0699
0700
0701 template <atomicity Atomicity, typename Arithmetic>
0702 struct BinomialAccumulator : AccumulatorSet<bool, Atomicity, bool, TrueAccumulator, FalseAccumulator> {
0703 using AccumulatorSet<bool, Atomicity, bool, TrueAccumulator, FalseAccumulator>::AccumulatorSet;
0704 unsigned long nEntries() const { return this->nTrueEntries() + this->nFalseEntries(); }
0705
0706 template <typename Result = fp_result_type<Arithmetic>>
0707 auto efficiency() const {
0708 auto nbEntries = nEntries();
0709 if ( 1 > nbEntries ) return Result{ -1 };
0710 return static_cast<Result>( this->nTrueEntries() ) / nbEntries;
0711 }
0712 auto eff() const { return efficiency(); }
0713
0714 template <typename Result = fp_result_type<Arithmetic>>
0715 auto efficiencyErr() const {
0716
0717
0718 using Gaudi::Accumulators::sqrt;
0719 using std::sqrt;
0720 auto nbEntries = nEntries();
0721 if ( 1 > nbEntries ) return Result{ -1 };
0722 return sqrt( static_cast<Result>( this->nTrueEntries() * this->nFalseEntries() ) / nbEntries ) / nbEntries;
0723 }
0724 auto effErr() const { return efficiencyErr(); }
0725 using AccumulatorSet<bool, Atomicity, bool, TrueAccumulator, FalseAccumulator>::operator+=;
0726 struct binomial_t {
0727 unsigned long nPass;
0728 unsigned long nTotal;
0729 };
0730 BinomialAccumulator& operator+=( binomial_t b ) {
0731 assert( b.nPass <= b.nTotal );
0732 TrueAccumulator<atomicity::none, bool> t{ std::in_place, b.nPass };
0733 TrueAccumulator<Atomicity, bool>::mergeAndReset( t );
0734 FalseAccumulator<atomicity::none, bool> f{ std::in_place, b.nTotal - b.nPass };
0735 FalseAccumulator<Atomicity, bool>::mergeAndReset( f );
0736 return *this;
0737 }
0738 };
0739
0740
0741
0742
0743
0744
0745 template <atomicity Atomicity, typename Arithmetic, template <atomicity, typename> typename CountAcc,
0746 template <atomicity, typename> typename SumAcc>
0747 struct AveragingAccumulatorBase
0748 : AccumulatorSet<Arithmetic, Atomicity, typename CountAcc<Atomicity, Arithmetic>::InputType, CountAcc, SumAcc> {
0749 static_assert( std::is_same_v<typename CountAcc<Atomicity, Arithmetic>::InputType,
0750 typename SumAcc<Atomicity, Arithmetic>::InputType>,
0751 "Incompatible Counters in definition of AveragingAccumulator. Both should have identical Input" );
0752 using AccumulatorSet<Arithmetic, Atomicity, typename CountAcc<Atomicity, Arithmetic>::InputType, CountAcc,
0753 SumAcc>::AccumulatorSet;
0754 template <typename Result = fp_result_type<Arithmetic>>
0755 auto mean() const {
0756 auto n = this->nEntries();
0757 Result sum = this->sum();
0758 return ( n > 0 ) ? static_cast<Result>( sum / n ) : Result{};
0759 }
0760 };
0761
0762
0763
0764
0765
0766 template <atomicity Atomicity, typename Arithmetic>
0767 using AveragingAccumulator = AveragingAccumulatorBase<Atomicity, Arithmetic, CountAccumulator, SumAccumulator>;
0768
0769
0770
0771
0772
0773
0774 template <atomicity Atomicity, typename Arithmetic, template <atomicity, typename> typename AvgAcc,
0775 template <atomicity, typename> typename SquareAcc>
0776 struct SigmaAccumulatorBase
0777 : AccumulatorSet<Arithmetic, Atomicity, typename AvgAcc<Atomicity, Arithmetic>::InputType, AvgAcc, SquareAcc> {
0778 static_assert( std::is_same_v<typename AvgAcc<Atomicity, Arithmetic>::InputType,
0779 typename SquareAcc<Atomicity, Arithmetic>::InputType>,
0780 "Incompatible Counters in definition of SigmaAccumulator. Both should have identical Input" );
0781 using AccumulatorSet<Arithmetic, Atomicity, typename SquareAcc<Atomicity, Arithmetic>::InputType, AvgAcc,
0782 SquareAcc>::AccumulatorSet;
0783 template <typename Result = fp_result_type<Arithmetic>>
0784 auto biased_sample_variance() const {
0785 auto n = this->nEntries();
0786 Result sum = this->sum();
0787 return ( n > 0 ) ? static_cast<Result>( ( this->sum2() - sum * ( sum / n ) ) / n ) : Result{};
0788 }
0789
0790 template <typename Result = fp_result_type<Arithmetic>>
0791 auto unbiased_sample_variance() const {
0792 auto n = this->nEntries();
0793 Result sum = this->sum();
0794 return ( n > 1 ) ? static_cast<Result>( ( this->sum2() - sum * ( sum / n ) ) / ( n - 1 ) ) : Result{};
0795 }
0796
0797 template <typename Result = fp_result_type<Arithmetic>>
0798 auto standard_deviation() const {
0799
0800
0801 using Gaudi::Accumulators::sqrt;
0802 using std::sqrt;
0803 Result v = biased_sample_variance();
0804 return ( Result{ 0 } > v ) ? Result{} : static_cast<Result>( sqrt( v ) );
0805 }
0806 [[deprecated( "The name 'rms' has changed to standard_deviation" )]] Arithmetic rms() const {
0807 return standard_deviation();
0808 }
0809
0810 template <typename Result = fp_result_type<Arithmetic>>
0811 auto meanErr() const {
0812 auto n = this->nEntries();
0813 if ( 0 == n ) return Result{};
0814
0815
0816 using Gaudi::Accumulators::sqrt;
0817 using std::sqrt;
0818 Result v = biased_sample_variance();
0819 return ( Result{ 0 } > v ) ? Result{} : static_cast<Result>( sqrt( v / n ) );
0820 }
0821 };
0822
0823
0824
0825
0826
0827 template <atomicity Atomicity, typename Arithmetic>
0828 using SigmaAccumulator = SigmaAccumulatorBase<Atomicity, Arithmetic, AveragingAccumulator, SquareAccumulator>;
0829
0830
0831
0832
0833
0834 template <atomicity Atomicity, typename Arithmetic>
0835 using StatAccumulator =
0836 AccumulatorSet<Arithmetic, Atomicity, Arithmetic, SigmaAccumulator, MinAccumulator, MaxAccumulator>;
0837
0838
0839
0840
0841
0842
0843
0844 template <template <atomicity Ato, typename... Int> class ContainedAccumulator, atomicity Atomicity, typename... Args>
0845 class Buffer : public ContainedAccumulator<atomicity::none, Args...> {
0846 using prime_type = ContainedAccumulator<Atomicity, Args...>;
0847 using base_type = ContainedAccumulator<atomicity::none, Args...>;
0848
0849 public:
0850 Buffer() = delete;
0851 Buffer( prime_type& p ) : base_type( construct_empty, p ), m_prime( &p ) {}
0852 Buffer( const Buffer& ) = delete;
0853 void operator=( const Buffer& ) = delete;
0854 Buffer( Buffer&& other ) : base_type( std::move( other ) ), m_prime( other.m_prime ) { other.m_prime = nullptr; }
0855 void push() {
0856 if ( m_prime ) { m_prime->mergeAndReset( static_cast<base_type&>( *this ) ); }
0857 }
0858 ~Buffer() { push(); }
0859
0860 private:
0861 prime_type* m_prime = nullptr;
0862 };
0863
0864
0865
0866
0867
0868 struct PrintableCounter {
0869 PrintableCounter() = default;
0870
0871 virtual ~PrintableCounter() = default;
0872
0873 template <typename stream>
0874 stream& printImpl( stream& s, std::string_view tag ) const {
0875 s << boost::format{ " | %|-48.48s|%|50t|" } % ( std::string{ '\"' }.append( tag ).append( "\"" ) );
0876 return print( s, true );
0877 }
0878
0879 virtual std::ostream& print( std::ostream&, bool tableFormat = false ) const = 0;
0880 virtual MsgStream& print( MsgStream&, bool tableFormat = true ) const = 0;
0881
0882 virtual std::ostream& print( std::ostream& o, std::string_view tag ) const { return printImpl( o, tag ); }
0883 virtual MsgStream& print( MsgStream& o, std::string_view tag ) const { return printImpl( o, tag ); }
0884
0885
0886 virtual bool toBePrinted() const { return true; }
0887
0888 std::string toString() const {
0889 std::ostringstream ost;
0890 print( ost );
0891 return ost.str();
0892 }
0893 };
0894
0895
0896
0897
0898 inline std::ostream& operator<<( std::ostream& s, const PrintableCounter& counter ) { return counter.print( s ); }
0899 inline MsgStream& operator<<( MsgStream& s, const PrintableCounter& counter ) { return counter.print( s ); }
0900
0901
0902
0903
0904
0905
0906 template <atomicity Atomicity, template <atomicity Ato, typename... Int> class Accumulator, typename... Args>
0907 class BufferableCounter : public PrintableCounter, public Accumulator<Atomicity, Args...> {
0908 public:
0909 using Accumulator<Atomicity, Args...>::Accumulator;
0910 using BufferType = Buffer<Accumulator, Atomicity, Args...>;
0911 BufferableCounter() = default;
0912 template <typename OWNER>
0913 BufferableCounter( OWNER* o, std::string const& name ) : BufferableCounter( o, name, *this ) {}
0914 BufferType buffer() { return { *this }; }
0915 BufferableCounter( BufferableCounter const& ) = delete;
0916 BufferableCounter& operator=( BufferableCounter const& ) = delete;
0917 ~BufferableCounter() {
0918 if ( m_monitoringHub ) { m_monitoringHub->removeEntity( *this ); }
0919 }
0920
0921 inline static const std::string typeString{ "counter" };
0922
0923 protected:
0924 template <typename OWNER, typename SELF, typename... CARGS>
0925 BufferableCounter( OWNER* o, std::string const& name, SELF& self, CARGS... args )
0926 : Accumulator<Atomicity, Args...>( args... ), m_monitoringHub( &o->serviceLocator()->monitoringHub() ) {
0927 m_monitoringHub->registerEntity( o->name(), name, self.typeString, self );
0928 }
0929
0930 private:
0931 Monitoring::Hub* m_monitoringHub{ nullptr };
0932 };
0933
0934
0935
0936
0937
0938 template <atomicity Atomicity = atomicity::full, typename Arithmetic = unsigned long>
0939 struct Counter : BufferableCounter<Atomicity, IntegralAccumulator, Arithmetic> {
0940 inline static const std::string typeString{ std::string{ "counter:Counter:" } + typeid( Arithmetic ).name() };
0941 using BufferableCounter<Atomicity, IntegralAccumulator, Arithmetic>::BufferableCounter;
0942 template <typename OWNER>
0943 Counter( OWNER* o, std::string const& name )
0944 : BufferableCounter<Atomicity, IntegralAccumulator, Arithmetic>( o, name, *this ) {}
0945 Counter& operator++() { return ( *this ) += 1; }
0946 Counter& operator+=( const Arithmetic v ) {
0947 BufferableCounter<Atomicity, IntegralAccumulator, Arithmetic>::operator+=( v );
0948 return *this;
0949 }
0950 using BufferableCounter<Atomicity, IntegralAccumulator, Arithmetic>::print;
0951
0952 template <typename stream>
0953 stream& printImpl( stream& o, bool tableFormat ) const {
0954
0955 auto fmt = ( tableFormat ? "|%|10d| |" : "#=%|-7lu|" );
0956 return o << boost::format{ fmt } % this->nEntries();
0957 }
0958
0959 std::ostream& print( std::ostream& o, bool tableFormat = false ) const override {
0960 return printImpl( o, tableFormat );
0961 }
0962 MsgStream& print( MsgStream& o, bool tableFormat = false ) const override { return printImpl( o, tableFormat ); }
0963 bool toBePrinted() const override { return this->nEntries() > 0; }
0964 friend void reset( Counter& c ) { c.reset(); }
0965 friend void mergeAndReset( Counter& c, Counter& o ) { c.mergeAndReset( o ); }
0966 friend void to_json( nlohmann::json& j, Counter const& c ) {
0967 j = { { "type", c.typeString }, { "empty", c.nEntries() == 0 }, { "nEntries", c.nEntries() } };
0968 }
0969 static Counter fromJSON( const nlohmann::json& j ) {
0970 return IntegralAccumulator<Atomicity, Arithmetic>::extractJSONData( j, { "nEntries" } );
0971 }
0972 };
0973
0974
0975
0976
0977
0978 template <typename Arithmetic = double, atomicity Atomicity = atomicity::full>
0979 struct AveragingCounter : BufferableCounter<Atomicity, AveragingAccumulator, Arithmetic> {
0980 inline static const std::string typeString{ std::string{ "counter:AveragingCounter:" } +
0981 typeid( Arithmetic ).name() };
0982 using BufferableCounter<Atomicity, AveragingAccumulator, Arithmetic>::BufferableCounter;
0983 template <typename OWNER>
0984 AveragingCounter( OWNER* o, std::string const& name )
0985 : BufferableCounter<Atomicity, AveragingAccumulator, Arithmetic>( o, name, *this ) {}
0986 using BufferableCounter<Atomicity, AveragingAccumulator, Arithmetic>::print;
0987
0988 template <typename stream>
0989 stream& printImpl( stream& o, bool tableFormat ) const {
0990 auto fmt = ( tableFormat ? "|%|10d| |%|11.7g| |%|#11.5g| |" : "#=%|-7lu| Sum=%|-11.5g| Mean=%|#10.4g|" );
0991 return o << boost::format{ fmt } % this->nEntries() % this->sum() % this->mean();
0992 }
0993
0994 std::ostream& print( std::ostream& o, bool tableFormat = false ) const override {
0995 return printImpl( o, tableFormat );
0996 }
0997 MsgStream& print( MsgStream& o, bool tableFormat = false ) const override { return printImpl( o, tableFormat ); }
0998
0999 bool toBePrinted() const override { return this->nEntries() > 0; }
1000 friend void reset( AveragingCounter& c ) { return c.reset(); }
1001 friend void mergeAndReset( AveragingCounter& c, AveragingCounter& o ) { c.mergeAndReset( o ); }
1002 friend void to_json( nlohmann::json& j, AveragingCounter const& c ) {
1003 j = { { "type", c.typeString },
1004 { "empty", c.nEntries() == 0 },
1005 { "nEntries", c.nEntries() },
1006 { "sum", c.sum() },
1007 { "mean", c.mean() } };
1008 }
1009 static AveragingCounter fromJSON( const nlohmann::json& j ) {
1010 return AveragingAccumulator<Atomicity, Arithmetic>::extractJSONData( j, { "nEntries", "sum" } );
1011 }
1012 };
1013 template <typename Arithmetic = double, atomicity Atomicity = atomicity::full>
1014 using SummingCounter = AveragingCounter<Arithmetic, Atomicity>;
1015
1016
1017
1018
1019
1020 template <typename Arithmetic = double, atomicity Atomicity = atomicity::full>
1021 struct SigmaCounter : BufferableCounter<Atomicity, SigmaAccumulator, Arithmetic> {
1022 inline static const std::string typeString{ std::string{ "counter:SigmaCounter:" } + typeid( Arithmetic ).name() };
1023 using BufferableCounter<Atomicity, SigmaAccumulator, Arithmetic>::BufferableCounter;
1024 template <typename OWNER>
1025 SigmaCounter( OWNER* o, std::string const& name )
1026 : BufferableCounter<Atomicity, SigmaAccumulator, Arithmetic>( o, name, *this ) {}
1027 using BufferableCounter<Atomicity, SigmaAccumulator, Arithmetic>::print;
1028
1029 template <typename stream>
1030 stream& printImpl( stream& o, bool tableFormat ) const {
1031 auto fmt = ( tableFormat ? "|%|10d| |%|11.7g| |%|#11.5g| |%|#11.5g| |"
1032 : "#=%|-7lu| Sum=%|-11.5g| Mean=%|#10.4g| +- %|-#10.5g|" );
1033 return o << boost::format{ fmt } % this->nEntries() % this->sum() % this->mean() % this->standard_deviation();
1034 }
1035
1036 std::ostream& print( std::ostream& o, bool tableFormat = false ) const override {
1037 return printImpl( o, tableFormat );
1038 }
1039 MsgStream& print( MsgStream& o, bool tableFormat = false ) const override { return printImpl( o, tableFormat ); }
1040 bool toBePrinted() const override { return this->nEntries() > 0; }
1041 friend void reset( SigmaCounter& c ) { c.reset(); }
1042 friend void mergeAndReset( SigmaCounter& c, SigmaCounter& o ) { c.mergeAndReset( o ); }
1043 friend void to_json( nlohmann::json& j, SigmaCounter const& c ) {
1044 j = { { "type", c.typeString },
1045 { "empty", c.nEntries() == 0 },
1046 { "nEntries", c.nEntries() },
1047 { "sum", c.sum() },
1048 { "mean", c.mean() },
1049 { "sum2", c.sum2() },
1050 { "standard_deviation", c.standard_deviation() } };
1051 }
1052 static SigmaCounter fromJSON( const nlohmann::json& j ) {
1053 return SigmaAccumulator<Atomicity, Arithmetic>::extractJSONData( j, { { "nEntries", "sum" }, "sum2" } );
1054 }
1055 };
1056
1057
1058
1059
1060
1061 template <typename Arithmetic = double, atomicity Atomicity = atomicity::full>
1062 struct StatCounter : BufferableCounter<Atomicity, StatAccumulator, Arithmetic> {
1063 inline static const std::string typeString{ std::string{ "counter:StatCounter:" } + typeid( Arithmetic ).name() };
1064 using BufferableCounter<Atomicity, StatAccumulator, Arithmetic>::BufferableCounter;
1065 template <typename OWNER>
1066 StatCounter( OWNER* o, std::string const& name )
1067 : BufferableCounter<Atomicity, StatAccumulator, Arithmetic>( o, name, *this ) {}
1068 using BufferableCounter<Atomicity, StatAccumulator, Arithmetic>::print;
1069
1070 template <typename stream>
1071 stream& printImpl( stream& o, bool tableFormat ) const {
1072 auto fmt = ( tableFormat ? "|%|10d| |%|11.7g| |%|#11.5g| |%|#11.5g| |%|#12.5g| |%|#12.5g| |"
1073 : "#=%|-7lu| Sum=%|-11.5g| Mean=%|#10.4g| +- %|-#10.5g| Min/Max=%|#10.4g|/%|-#10.4g|" );
1074 return o << boost::format{ fmt } % this->nEntries() % this->sum() % this->mean() % this->standard_deviation() %
1075 this->min() % this->max();
1076 }
1077
1078 std::ostream& print( std::ostream& o, bool tableFormat = false ) const override {
1079 return printImpl( o, tableFormat );
1080 }
1081 MsgStream& print( MsgStream& o, bool tableFormat = false ) const override { return printImpl( o, tableFormat ); }
1082 bool toBePrinted() const override { return this->nEntries() > 0; }
1083 friend void reset( StatCounter& c ) { c.reset(); }
1084 friend void mergeAndReset( StatCounter& c, StatCounter& o ) { c.mergeAndReset( o ); }
1085 friend void to_json( nlohmann::json& j, StatCounter const& c ) {
1086 j = { { "type", c.typeString },
1087 { "empty", c.nEntries() == 0 },
1088 { "nEntries", c.nEntries() },
1089 { "sum", c.sum() },
1090 { "mean", c.mean() },
1091 { "sum2", c.sum2() },
1092 { "standard_deviation", c.standard_deviation() },
1093 { "min", c.min() },
1094 { "max", c.max() } };
1095 }
1096 static StatCounter fromJSON( const nlohmann::json& j ) {
1097 return StatAccumulator<Atomicity, Arithmetic>::extractJSONData(
1098 j, { { { "nEntries", "sum" }, "sum2" }, "min", "max" } );
1099 }
1100 };
1101
1102
1103
1104
1105
1106 template <typename Arithmetic = double, atomicity Atomicity = atomicity::full>
1107 struct BinomialCounter : BufferableCounter<Atomicity, BinomialAccumulator, Arithmetic> {
1108 inline static const std::string typeString{ std::string{ "counter:BinomialCounter:" } +
1109 typeid( Arithmetic ).name() };
1110 using BufferableCounter<Atomicity, BinomialAccumulator, Arithmetic>::BufferableCounter;
1111 template <typename OWNER>
1112 BinomialCounter( OWNER* o, std::string const& name )
1113 : BufferableCounter<Atomicity, BinomialAccumulator, Arithmetic>( o, name, *this ) {}
1114
1115 template <typename stream>
1116 stream& printImpl( stream& o, bool tableFormat ) const {
1117 auto fmt = ( tableFormat ? "|%|10d| |%|11.5g| |(%|#9.7g| +- %|-#8.7g|)%% |"
1118 : "#=%|-7lu| Sum=%|-11.5g| Eff=|(%|#9.7g| +- %|-#8.6g|)%%|" );
1119 return o << boost::format{ fmt } % this->nEntries() % this->nTrueEntries() % ( this->efficiency() * 100 ) %
1120 ( this->efficiencyErr() * 100 );
1121 }
1122
1123 std::ostream& print( std::ostream& o, bool tableFormat = false ) const override {
1124 return printImpl( o, tableFormat );
1125 }
1126 MsgStream& print( MsgStream& o, bool tableFormat = false ) const override { return printImpl( o, tableFormat ); }
1127
1128 template <typename stream>
1129 stream& printImpl( stream& o, std::string_view tag ) const {
1130
1131 o << boost::format{ " |*%|-48.48s|%|50t|" } % ( std::string{ "\"" }.append( tag ).append( "\"" ) );
1132 return print( o, true );
1133 }
1134
1135 std::ostream& print( std::ostream& o, std::string_view tag ) const override { return printImpl( o, tag ); }
1136 MsgStream& print( MsgStream& o, std::string_view tag ) const override { return printImpl( o, tag ); }
1137 bool toBePrinted() const override { return this->nEntries() > 0; }
1138 friend void reset( BinomialCounter& c ) { c.reset(); }
1139 friend void mergeAndReset( BinomialCounter& c, BinomialCounter& o ) { c.mergeAndReset( o ); }
1140 friend void to_json( nlohmann::json& j, BinomialCounter const& c ) {
1141 j = { { "type", c.typeString },
1142 { "empty", c.nEntries() == 0 },
1143 { "nEntries", c.nTrueEntries() + c.nFalseEntries() },
1144 { "nTrueEntries", c.nTrueEntries() },
1145 { "nFalseEntries", c.nFalseEntries() },
1146 { "efficiency", c.efficiency() },
1147 { "efficiencyErr", c.efficiencyErr() } };
1148 }
1149 static BinomialCounter fromJSON( const nlohmann::json& j ) {
1150 return BinomialAccumulator<Atomicity, Arithmetic>::extractJSONData( j, { "nTrueEntries", "nFalseEntries" } );
1151 }
1152 };
1153
1154 namespace details::MsgCounter {
1155 template <atomicity Atomicity>
1156 struct Handler : Adder<unsigned long, Atomicity> {
1157 using Base = Adder<unsigned long, Atomicity>;
1158 static void merge( typename Base::InternalType& orig, bool b ) {
1159 if ( b ) Base::merge( orig, 1 );
1160 }
1161 };
1162
1163
1164 template <atomicity Atomicity, typename Arithmetic = double>
1165 using MsgAccumulator = GenericAccumulator<bool, unsigned long, Atomicity, Identity, Identity, Handler<Atomicity>>;
1166 }
1167
1168 template <MSG::Level level, atomicity Atomicity = atomicity::full>
1169 class MsgCounter : public PrintableCounter, public details::MsgCounter::MsgAccumulator<Atomicity> {
1170 public:
1171 inline static const std::string typeString{ "counter:MsgCounter" };
1172 template <typename OWNER>
1173 MsgCounter( OWNER* o, std::string const& ms, unsigned long nMax = 10 )
1174 : m_monitoringHub{ &o->serviceLocator()->monitoringHub() }, logger( o ), msg( ms ), max( nMax ) {
1175 m_monitoringHub->registerEntity( o->name(), ms, typeString, *this );
1176 }
1177 template <typename OWNER>
1178 MsgCounter( OWNER* o, std::string const& ms, int nMax ) : MsgCounter( o, ms, static_cast<unsigned long>( nMax ) ) {}
1179 MsgCounter& operator++() {
1180 ( *this ) += true;
1181 return *this;
1182 }
1183 MsgCounter& operator+=( const bool by ) {
1184 details::MsgCounter::MsgAccumulator<Atomicity>::operator+=( by );
1185 if ( by ) log();
1186 return *this;
1187 }
1188 MsgCounter( MsgCounter const& ) = delete;
1189 MsgCounter& operator=( MsgCounter const& ) = delete;
1190 ~MsgCounter() {
1191 if ( m_monitoringHub ) m_monitoringHub->removeEntity( *this );
1192 }
1193 template <typename stream>
1194 stream& printImpl( stream& o, bool tableFormat ) const {
1195 return o << boost::format{ tableFormat ? "|%|10d| |" : "#=%|-7lu|" } % this->value();
1196 }
1197 using PrintableCounter::print;
1198 std::ostream& print( std::ostream& os, bool tableFormat ) const override { return printImpl( os, tableFormat ); }
1199 MsgStream& print( MsgStream& os, bool tableFormat ) const override { return printImpl( os, tableFormat ); }
1200 bool toBePrinted() const override { return this->value() > 0; }
1201 friend void reset( MsgCounter& c ) { c.reset(); }
1202 friend void mergeAndReset( MsgCounter& c, MsgCounter& o ) { c.mergeAndReset( o ); }
1203 friend void to_json( nlohmann::json& j, MsgCounter const& c ) {
1204 j = { { "type", c.typeString }, { "empty", c.value() == 0 },
1205 { "nEntries", c.value() }, { "level", level },
1206 { "max", c.max }, { "msg", c.msg } };
1207 }
1208 static MsgCounter fromJSON( const nlohmann::json& j ) {
1209 return { j.at( "msg" ).get<std::string>(), j.at( "max" ).get<unsigned long>(),
1210 j.at( "nEntries" ).get<unsigned long>() };
1211 }
1212
1213 private:
1214 MsgCounter( std::string const& ms, unsigned long nMax, unsigned long count )
1215 : details::MsgCounter::MsgAccumulator<Atomicity>{ count }, msg( ms ), max( nMax ) {}
1216
1217 Monitoring::Hub* m_monitoringHub{ nullptr };
1218 const CommonMessagingBase* logger{ nullptr };
1219 std::string msg;
1220 unsigned long max;
1221 void log() {
1222 if ( this->value() <= max && logger ) {
1223 if ( this->value() == max ) {
1224 logger->msgStream( level ) << "Suppressing message: " << std::quoted( msg, '\'' ) << endmsg;
1225 } else {
1226 logger->msgStream( level ) << msg << endmsg;
1227 }
1228 }
1229 }
1230 };
1231
1232
1233
1234
1235
1236
1237 template <typename Counter, typename Container, typename Fun>
1238 void accumulate( Counter& counter, const Container& container, Fun f = Identity{} ) {
1239 auto b = counter.buffer();
1240 for ( const auto& elem : container ) b += f( elem );
1241 }
1242
1243 }