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';
13template<typename E> struct EnumTypeName {};
14// You _must_ overload 'operator<<' for all enum types for which you want this to work.
15template<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';
19template<typename E> struct EnumValueName
20{
21 EnumValueName(E e_) : e(e_) {}
23};
24// You _must_ overload 'operator<<' for all enum types for which you want this to work.
25template<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
85template<bool ENABLED, typename ENUM>
87{
88public:
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
102private:
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.
110template<typename ENUM>
111class ProfileCounters<false, ENUM>
112{
113public:
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:146
constexpr double e
Definition: Math.hh:18
constexpr unsigned NUM
Definition: CacheLine.hh:8