Hermes
profiler.h
Go to the documentation of this file.
1 
35 #ifndef HERMES_HERMES_COMMON_PROFILER_H
36 #define HERMES_HERMES_COMMON_PROFILER_H
37 
38 #include <hermes/common/defs.h>
39 #include <hermes/colors/argb_colors.h>
40 #include <functional>
41 #include <chrono>
42 #include <vector>
43 #include <stack>
44 
45 namespace hermes::profiler {
46 
47 // *********************************************************************************************************************
48 // Profiler
49 // *********************************************************************************************************************
83 class Profiler {
84 public:
86  struct BlockDescriptor {
91  BlockDescriptor(u32 id, u32 color, u32 line, const char *name);
94  explicit BlockDescriptor(const char *name,
95  u32 color);
96  u32 color{};
97  u32 id{};
98  u32 line{};
99  const char *name{};
100  };
101 
103  class Block {
104  friend Profiler;
105  public:
107  Block() = default;
110  explicit Block(u32 desc_id);
113  [[nodiscard]] inline u64 begin() const noexcept { return start_; }
116  [[nodiscard]] inline u64 end() const noexcept { return end_; }
119  [[nodiscard]] inline u64 duration() const noexcept { return end_ - start_; }
120 
122  u32 level{0};
123  private:
124  void start();
125  void finish();
126 
127  u64 start_{0};
128  u64 end_{0};
129  };
130 
132  class ScopedBlock {
133  public:
135  explicit ScopedBlock(u32 block_descriptor_id);
136  ~ScopedBlock();
137 
138  private:
139  Block block_;
140  };
141  // *******************************************************************************************************************
142  // STATIC METHODS
143  // *******************************************************************************************************************
144  // access
147  static const std::vector<Block> &blockList();
151  static const BlockDescriptor &blockDescriptor(const Block &block);
152  //
155  static u64 initTime();
158  static i64 cpuFrequency();
161  static bool isEnabled();
163  static void enable();
165  static void disable();
170  static u32 pushBlockDescriptor(const char *name, u32 color = argb_colors::Default);
174  static void startBlock(Block &block);
177  static void endBlock();
180  static void setMaxBlockCount(size_t max_block_count);
182  static void reset();
185  static void iterateBlocks(const std::function<void(const Block &)> &f);
186  // output
188  static std::string dump();
189  // *******************************************************************************************************************
190  // CONSTRUCTORS
191  // *******************************************************************************************************************
192  ~Profiler() = default;
193  // assignment
194  Profiler(Profiler &&other) = delete;
195  Profiler(const Profiler &other) = delete;
196  // *******************************************************************************************************************
197  // OPERATORS
198  // *******************************************************************************************************************
199  Profiler &operator=(const Profiler &other) = delete;
200  Profiler &operator=(Profiler &&other) = delete;
201 
202 private:
203  Profiler();
206  static Profiler &instance() {
207  static Profiler _instance;
208  return _instance;
209  }
210 
211  u64 profiler_start_time_{};
212  i64 cpu_frequency_{};
213  bool enabled{true};
214  size_t max_block_count_{0};
215  u64 block_list_start_{0};
217  std::vector<BlockDescriptor *> block_descriptors_{};
218  std::vector<Block> block_list_;
219  std::stack<u32> block_stack_;
220 };
221 
224 static inline u64 now() {
225  // high res option
226  return static_cast<u64>(std::chrono::high_resolution_clock::now().time_since_epoch().count());
227  // steady option
228  return static_cast<u64>(std::chrono::steady_clock::now().time_since_epoch().count());
229  //
230 #if (defined(__GNUC__) || defined(__ICC))
231  // part of code from google/benchmark library (Licensed under the Apache License, Version 2.0)
232  // see https://github.com/google/benchmark/blob/master/src/cycleclock.h#L111
233 #if defined(__i386__)
234  int64_t ret;
235  __asm__ volatile("rdtsc" : "=A"(ret));
236  return ret;
237 #elif defined(__x86_64__) || defined(__amd64__)
238  uint64_t low, high;
239  __asm__ volatile("rdtsc" : "=a"(low), "=d"(high));
240  return (high << 32) | low;
241 #endif
242 #endif
243 }
247 static inline u64 ns2ticks(u64 ns) {
248  return static_cast<u64>(ns * Profiler::cpuFrequency() / 1000000000LL);
249 }
253 static inline u64 us2ticks(u64 us) {
254  return static_cast<u64>(us * Profiler::cpuFrequency() / 1000000LL);
255 }
259 static inline u64 ms2ticks(u64 ms) {
260  return static_cast<u64>(ms * Profiler::cpuFrequency() / 1000LL);
261 }
265 static inline u64 s2ticks(u64 s) {
266  return static_cast<u64>(s * Profiler::cpuFrequency());
267 }
271 static inline u64 ticks2ns(u64 ticks) {
272  return static_cast<u64>(ticks * 1000000000LL / Profiler::cpuFrequency());
273  // no chrono support TODO
274  return static_cast<u64>(ticks / Profiler::cpuFrequency());
275 }
279 static inline u64 ticks2us(u64 ticks) {
280  return static_cast<u64>(ticks * 1000000LL / Profiler::cpuFrequency());
281  // no chrono support TODO
282  return static_cast<u64>(ticks * 1000 / Profiler::cpuFrequency());
283 }
287 static inline u64 ticks2ms(u64 ticks) {
288  return static_cast<u64>(ticks * 1000LL / Profiler::cpuFrequency());
289  // no chrono support TODO
290  return static_cast<u64>(ticks * 1000000LL / Profiler::cpuFrequency());
291 }
295 static inline u64 ticks2s(u64 ticks) {
296  return static_cast<u64>(ticks / Profiler::cpuFrequency());
297  // no chrono support TODO
298  return static_cast<u64>(ticks * 1000000000LL / Profiler::cpuFrequency());
299 }
302 static inline i64 computeCPUFrequency() {
303  return std::chrono::high_resolution_clock::period::den / std::chrono::high_resolution_clock::period::num;
304 }
305 #define HERMES_PROFILE_ENABLED
306 
307 #ifdef HERMES_PROFILE_ENABLED
308 
313 template<class ... TArgs>
314 inline constexpr u32 extract_color(TArgs...);
317 template<>
318 inline constexpr u32 extract_color<>() {
319  return hermes::argb_colors::Default;
320 }
324 template<class T>
325 inline constexpr u32 extract_color(T) {
326  return hermes::argb_colors::Default;
327 }
331 template<>
332 inline constexpr u32 extract_color<u32>(u32 _color) {
333  return _color;
334 }
340 template<class ... TArgs>
341 inline constexpr u32 extract_color(u32 _color, TArgs...) {
342  return _color;
343 }
349 template<class T, class ... TArgs>
350 inline constexpr u32 extract_color(T, TArgs... _args) {
351  return extract_color(_args...);
352 }
353 
354 }
355 
359 #define HERMES_TOKEN_JOIN(x, y) x ## y
360 
364 #define HERMES_TOKEN_CONCATENATE(x, y) HERMES_TOKEN_JOIN(x, y)
365 
369 #define HERMES_PROFILE_START_BLOCK(name, ...) \
370  static u32 HERMES_TOKEN_CONCATENATE(hermes_block_desc_id_, __LINE__) = \
371  hermes::profiler::Profiler::pushBlockDescriptor(name, hermes::profiler::extract_color(__VA_ARGS__)); \
372  hermes::profiler::Profiler::Block HERMES_TOKEN_CONCATENATE(block, __LINE__)\
373  (HERMES_TOKEN_CONCATENATE(hermes_block_desc_id_, __LINE__)); \
374  hermes::profiler::Profiler::startBlock(HERMES_TOKEN_CONCATENATE(block, __LINE__))
375 
377 #define HERMES_PROFILE_END_BLOCK hermes::profiler::Profiler::endBlock();
378 
382 #define HERMES_PROFILE_SCOPE(name, ...) \
383 static u32 HERMES_TOKEN_CONCATENATE(hermes_block_desc_id_, __LINE__) = \
384  hermes::profiler::Profiler::pushBlockDescriptor(name, hermes::profiler::extract_color(__VA_ARGS__)); \
385  hermes::profiler::Profiler::ScopedBlock HERMES_TOKEN_CONCATENATE(block, __LINE__)\
386  (HERMES_TOKEN_CONCATENATE(hermes_block_desc_id_, __LINE__))
387 
390 #define HERMES_PROFILE_FUNCTION(...) HERMES_PROFILE_SCOPE(__func__, ## __VA_ARGS__)
391 
393 #define HERMES_ENABLE_PROFILER hermes::profiler::Profiler::enable();
394 
396 #define HERMES_DISABLE_PROFILER hermes::profiler::Profiler::disable();
397 
399 #define HERMES_RESET_PROFILER hermes::profiler::Profiler::reset();
400 
401 #endif
402 
403 #endif //HERMES_HERMES_COMMON_PROFILER_H
404 
Holds a labeled profiler block with start/end time points.
Definition: profiler.h:103
u32 descriptor_id
block descriptor identifier
Definition: profiler.h:121
u64 begin() const noexcept
block start time point (in ticks)
Definition: profiler.h:113
u64 duration() const noexcept
block duration (in ticks)
Definition: profiler.h:119
u32 level
profile stack level
Definition: profiler.h:122
u64 end() const noexcept
block end time point (in ticks)
Definition: profiler.h:116
RAII Profiler Block.
Definition: profiler.h:132
ScopedBlock(u32 block_descriptor_id)
Definition: profiler.cpp:186
Singleton code profiler.
Definition: profiler.h:83
static u32 pushBlockDescriptor(const char *name, u32 color=argb_colors::Default)
Registers a new block description.
Definition: profiler.cpp:45
static std::string dump()
Dumps profiling into a string.
Definition: profiler.cpp:91
static bool isEnabled()
Checks if Profiler is currently enabled.
Definition: profiler.cpp:127
static const std::vector< Block > & blockList()
Raw block data.
Definition: profiler.cpp:119
static i64 cpuFrequency()
Computed CPU frequency.
Definition: profiler.cpp:146
static u64 initTime()
Get time point when Profiler was instantiated.
Definition: profiler.cpp:142
static void enable()
Enables Profiler.
Definition: profiler.cpp:131
static void startBlock(Block &block)
Starts a new block by taking this call time point.
Definition: profiler.cpp:52
static void disable()
Disables Profiler.
Definition: profiler.cpp:135
static const BlockDescriptor & blockDescriptor(const Block &block)
Get block descriptor from block.
Definition: profiler.cpp:123
static void setMaxBlockCount(size_t max_block_count)
Sets a limit into the maximum number of stored blocks.
Definition: profiler.cpp:150
static void endBlock()
Finishes the block at the top of the stack.
Definition: profiler.cpp:74
static void reset()
Clears all blocks.
Definition: profiler.cpp:154
static void iterateBlocks(const std::function< void(const Block &)> &f)
Iterates over stored blocks sequentially.
Definition: profiler.cpp:160
Data type definitions.
uint64_t u64
64 bit size unsigned integer type
Definition: defs.h:89
uint32_t u32
32 bit size unsigned integer type
Definition: defs.h:88
int64_t i64
64 bit size integer type
Definition: defs.h:84
constexpr u32 extract_color(TArgs...)
Auxiliary function to pick variadic color argument.
Describes a block label.
Definition: profiler.h:86
u32 line
code line
Definition: profiler.h:98
BlockDescriptor(u32 id, u32 color, u32 line, const char *name)
Definition: profiler.cpp:35
const char * name
block name
Definition: profiler.h:99
u32 color
block color
Definition: profiler.h:96