openMSX
ProfileCounters.hh
Go to the documentation of this file.
1 #ifndef PROFILECOUNTERS_HH
2 #define PROFILECOUNTERS_HH
3 
4 #include "enumerate.hh"
5 #include <iostream>
6 
7 //
8 // Quick and dirty reflection on C++ enums (in the future replace with c++23 reflexpr).
9 //
10 
11 // Print an enum type as a string, for example:
12 // os << EnumTypeName<SomeEnumType>() << '\n';
13 template<typename E> struct EnumTypeName {};
14 // You _must_ overload 'operator<<' for all enum types for which you want this to work.
15 template<typename E> std::ostream& operator<<(std::ostream& os, EnumTypeName<E>) = delete;
16 
17 // Print an enum value as a string, for example:
18 // os << EnumValueName{myEnumValue} << '\n';
19 template<typename E> struct EnumValueName
20 {
21  EnumValueName(E e_) : e(e_) {}
22  E e;
23 };
24 // You _must_ overload 'operator<<' for all enum types for which you want this to work.
25 template<typename E> std::ostream& operator<<(std::ostream& os, EnumValueName<E> evn) = delete;
26 
27 
28 
29 
30 // A collection of (simple) profile counters:
31 // - Counters start at zero.
32 // - An individual counter can be incremented by 1 via 'tick(<counter-id>)'.
33 // - When this 'ProfileCounters' object is destoyed it prints the value of each
34 // counter.
35 //
36 // Template parameters:
37 // - bool ENABLED:
38 // when false, the optimizer should be able to completely optimize-out all
39 // profile related code
40 // - typename ENUM:
41 // Must be a c++ enum (or enum class) which satisfies the following requirements:
42 // * The numerical values must be 0, 1, ... IOW the values must be usable as
43 // indices in an array. (This is automatically the case if you don't
44 // manually assign numeric values).
45 // * There must be an enum value with the name 'NUM' which has a numerical
46 // value equal to the number of other values in this enum. (This is
47 // automatically the case if you put 'NUM' last in the list of enum
48 // values).
49 // * You must overload the following two functions for the type 'ENUM':
50 // std::ostream& operator<<(std::ostream& os, EnumTypeName<ENUM>);
51 // std::ostream& operator<<(std::ostream& os, EnumValueName<ENUM> evn);
52 //
53 // Example usage:
54 // enum class WidgetProfileCounter {
55 // CALCULATE,
56 // INVALIDATE,
57 // NUM // must be last
58 // };
59 // std::ostream& operator<<(std::ostream& os, EnumTypeName<WidgetProfileCounter>)
60 // {
61 // return os << "WidgetProfileCounter";
62 // }
63 // std::ostream& operator<<(std::ostream& os, EnumValueName<WidgetProfileCounter> evn)
64 // {
65 // std::string_view names[size_t(WidgetProfileCounter::NUM)] = {
66 // "calculate"sv, "invalidate"sv
67 // };
68 // return os << names[size_t(evn.e)];
69 // }
70 //
71 // constexpr bool PRINT_WIDGET_PROFILE = true; // possibly depending on some #define
72 //
73 // struct Widget : private ProfileCounters<PRINT_WIDGET_PROFILE, WidgetProfileCounter>
74 // {
75 // void calculate() {
76 // tick(WidgetProfileCounter::CALCULATE);
77 // // ...
78 // }
79 // void invalidate() {
80 // tick(WidgetProfileCounter::CALCULATE);
81 // // ...
82 // }
83 // };
84 
85 template<bool ENABLED, typename ENUM>
87 {
88 public:
89  // Print counters on destruction.
91  std::cout << "-- Profile counters: " << EnumTypeName<ENUM>() << " -- " << static_cast<void*>(this) << '\n';
92  for (auto [i, count] : enumerate(counters)) {
93  std::cout << EnumValueName{ENUM(i)} << ": " << count << '\n';
94  }
95  }
96 
97  // Increment
98  void tick(ENUM e) const {
99  ++counters[size_t(e)];
100  }
101 
102 private:
103  static constexpr auto NUM = size_t(ENUM::NUM); // value 'ENUM::NUM' must exist
104  mutable unsigned counters[NUM] = {};
105 };
106 
107 
108 // Specialization for when profiling is disabled.
109 // This class is simple enough so that it can be completely optimized away.
110 template<typename ENUM>
111 class ProfileCounters<false, ENUM>
112 {
113 public:
114  void tick(ENUM) const { /*nothing*/ }
115 };
116 
117 #endif
std::ostream & operator<<(std::ostream &os, EnumTypeName< E >)=delete
void tick(ENUM e) const
constexpr auto enumerate(Iterable &&iterable)
Heavily inspired by Nathan Reed's blog post: Python-Like enumerate() In C++17 http://reedbeta....
Definition: enumerate.hh:28
ALWAYS_INLINE unsigned count(const uint8_t *pIn, const uint8_t *pMatch, const uint8_t *pInLimit)
Definition: lz4.cc:207
constexpr unsigned NUM
Definition: CacheLine.hh:8