TachyonUI 0.1.0
High-performance UI for building tools.
Loading...
Searching...
No Matches
gui_profiler.h
Go to the documentation of this file.
1#pragma once
2
3// Hierarchical CPU timing: scoped zones accumulated into a per-frame tree, keyed by
4// the hash of their call path (parent path + name) so nodes are stable across frames.
5//
6// Hot path: each TACHYON_PROFILE_SCOPE site caches its node index, and timestamps are raw
7// ticks (rdtsc on x86) converted to ms only at frame end.
8//
9// See engine design doc 28 (Diagnostics).
10
11#include <stdint.h>
12#include <span>
13
14#include <gui_core/gui_base_types.h> // SteadyClockNowNanos
15#include <gui_core/gui_hash.h> // Hash::CalculateConst / Combine
16
18{
21
24 class ProfilerCollector;
25
26 ProfilerCollector& MainThreadCollector();
27
29 void SetProfilingEnabled(bool enabled);
30
33 void BeginFrame(ProfilerCollector& collector);
34 void EndFrame (ProfilerCollector& collector);
36
38 void Reset(ProfilerCollector& collector);
39
44 {
45 uint64_t nameHash = 0;
46 const char* name = "";
47 const char* file = "";
48 int line = 0;
49 bool isWait = false;
50
51 uint64_t cachedKey = 0;
52 int32_t cachedIndex = -1;
53 uint32_t cachedGeneration = 0;
54 };
55
59 void EnterScope(ProfilerCollector& collector, ScopeLocation& loc) noexcept;
60 void ExitScope (ProfilerCollector& collector) noexcept;
62
64 void EnterScope(ProfilerCollector& collector, uint64_t nameHash, const char* name,
65 bool isWait = false, const char* file = "", int line = 0) noexcept;
66
69 {
70 public:
71 ScopedTimer(ProfilerCollector& collector, ScopeLocation& loc) noexcept
72 : m_collector(collector), m_armed(IsProfilingEnabled())
73 {
74 if (m_armed) EnterScope(m_collector, loc);
75 }
76 ~ScopedTimer() noexcept { if (m_armed) ExitScope(m_collector); }
77
78 ScopedTimer(const ScopedTimer&) = delete;
80
81 private:
82 ProfilerCollector& m_collector;
83 bool m_armed;
84 };
85
88 {
89 uint64_t key = 0;
90 uint64_t parentKey = 0;
91 const char* name = "";
92 const char* file = "";
93 int32_t line = 0;
94 int32_t depth = 0;
95 int32_t callCount = 0;
96 double totalMs = 0.0;
97 double selfMs = 0.0;
98 double minMs = 0.0;
99 double maxMs = 0.0;
100 bool isWait = false;
101 };
102
104 std::span<const ProfileSample> LastFrameSamples(const ProfilerCollector& collector);
105
107 double LastFrameTotalMs(const ProfilerCollector& collector);
109}
110
111// Define TACHYON_PROFILE_ENABLED=0 to compile every macro out.
112#ifndef TACHYON_PROFILE_ENABLED
113# define TACHYON_PROFILE_ENABLED 1
114#endif
115
116#if TACHYON_PROFILE_ENABLED
117# define TACHYON_PROFILE_CONCAT2(a, b) a##b
118# define TACHYON_PROFILE_CONCAT(a, b) TACHYON_PROFILE_CONCAT2(a, b)
119
120 // name must be a string literal so the hash folds at compile time.
121# define TACHYON_PROFILE_SCOPE(name) \
122 static ::tachyon::Diagnostics::ScopeLocation TACHYON_PROFILE_CONCAT(s_profLoc_, __LINE__) \
123 { ::tachyon::Hash::CalculateConst(name), name, __FILE__, __LINE__, false }; \
124 ::tachyon::Diagnostics::ScopedTimer TACHYON_PROFILE_CONCAT(profTimer_, __LINE__)( \
125 ::tachyon::Diagnostics::MainThreadCollector(), TACHYON_PROFILE_CONCAT(s_profLoc_, __LINE__))
126
127# define TACHYON_PROFILE_SCOPE_WAIT(name) \
128 static ::tachyon::Diagnostics::ScopeLocation TACHYON_PROFILE_CONCAT(s_profLoc_, __LINE__) \
129 { ::tachyon::Hash::CalculateConst(name), name, __FILE__, __LINE__, true }; \
130 ::tachyon::Diagnostics::ScopedTimer TACHYON_PROFILE_CONCAT(profTimer_, __LINE__)( \
131 ::tachyon::Diagnostics::MainThreadCollector(), TACHYON_PROFILE_CONCAT(s_profLoc_, __LINE__))
132
133 // Times a scope from a caller-owned ScopeLocation (e.g. an entry of a per-stage table).
134# define TACHYON_PROFILE_SCOPE_REF(locationLValue) \
135 ::tachyon::Diagnostics::ScopedTimer TACHYON_PROFILE_CONCAT(profTimer_, __LINE__)( \
136 ::tachyon::Diagnostics::MainThreadCollector(), (locationLValue))
137
138 // Root frame scope plus collector frame boundaries; wrap the whole loop iteration.
139# define TACHYON_PROFILE_FRAME_BEGIN(name) \
140 do { \
141 static ::tachyon::Diagnostics::ScopeLocation TACHYON_PROFILE_CONCAT(s_frameLoc_, __LINE__) \
142 { ::tachyon::Hash::CalculateConst(name), name, __FILE__, __LINE__, false }; \
143 ::tachyon::Diagnostics::BeginFrame(::tachyon::Diagnostics::MainThreadCollector()); \
144 ::tachyon::Diagnostics::EnterScope(::tachyon::Diagnostics::MainThreadCollector(), \
145 TACHYON_PROFILE_CONCAT(s_frameLoc_, __LINE__)); \
146 } while (0)
147# define TACHYON_PROFILE_FRAME_END() \
148 do { \
149 ::tachyon::Diagnostics::ExitScope(::tachyon::Diagnostics::MainThreadCollector()); \
150 ::tachyon::Diagnostics::EndFrame(::tachyon::Diagnostics::MainThreadCollector()); \
151 } while (0)
152#else
153# define TACHYON_PROFILE_SCOPE(name) ((void)0)
154# define TACHYON_PROFILE_SCOPE_WAIT(name) ((void)0)
155# define TACHYON_PROFILE_SCOPE_REF(locationLValue) ((void)0)
156# define TACHYON_PROFILE_FRAME_BEGIN(name) ((void)0)
157# define TACHYON_PROFILE_FRAME_END() ((void)0)
158#endif
ScopedTimer(const ScopedTimer &)=delete
~ScopedTimer() noexcept
Definition gui_profiler.h:76
ScopedTimer & operator=(const ScopedTimer &)=delete
ScopedTimer(ProfilerCollector &collector, ScopeLocation &loc) noexcept
Definition gui_profiler.h:71
void Reset(ProfilerCollector &collector)
Discards all nodes and history; cached scope sites re-resolve.
void BeginFrame(ProfilerCollector &collector)
Frame boundaries: call once each, around all scopes for the frame.
double LastFrameTotalMs(const ProfilerCollector &collector)
Smoothed total of the root scope(s): the frame total, in milliseconds.
ProfilerCollector & MainThreadCollector()
void EnterScope(ProfilerCollector &collector, ScopeLocation &loc) noexcept
Cached scope entry / exit, as the macros use.
void ExitScope(ProfilerCollector &collector) noexcept
Cached scope entry / exit, as the macros use.
void SetProfilingEnabled(bool enabled)
std::span< const ProfileSample > LastFrameSamples(const ProfilerCollector &collector)
The nodes of the last finalized frame, depth-first. Valid until the next EndFrame.
void EndFrame(ProfilerCollector &collector)
Frame boundaries: call once each, around all scopes for the frame.
Definition gui_logging.h:24
One finalized node, depth-first. Durations are windowed averages (~4 updates/s).
Definition gui_profiler.h:88
const char * name
Definition gui_profiler.h:91
double minMs
Definition gui_profiler.h:98
int32_t depth
Definition gui_profiler.h:94
uint64_t parentKey
Definition gui_profiler.h:90
bool isWait
Definition gui_profiler.h:100
double selfMs
Definition gui_profiler.h:97
double totalMs
Definition gui_profiler.h:96
const char * file
Definition gui_profiler.h:92
int32_t callCount
Definition gui_profiler.h:95
int32_t line
Definition gui_profiler.h:93
double maxMs
Definition gui_profiler.h:99
uint64_t key
Definition gui_profiler.h:89
Per-call-site descriptor, static at each TACHYON_PROFILE_SCOPE site.
Definition gui_profiler.h:44
uint32_t cachedGeneration
Definition gui_profiler.h:53
uint64_t cachedKey
Definition gui_profiler.h:51
int line
Definition gui_profiler.h:48
const char * name
Definition gui_profiler.h:46
int32_t cachedIndex
Definition gui_profiler.h:52
uint64_t nameHash
Definition gui_profiler.h:45
const char * file
Definition gui_profiler.h:47
bool isWait
Definition gui_profiler.h:49