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