Profiler.h 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. // Copyright (c) 2008-2023 the Urho3D project
  2. // License: MIT
  3. #pragma once
  4. #include "../Container/Str.h"
  5. #include "../Core/Thread.h"
  6. #include "../Core/Timer.h"
  7. #ifdef URHO3D_TRACY_PROFILING
  8. #define TRACY_ENABLE 1
  9. #include "Tracy/Tracy.hpp"
  10. #endif
  11. namespace Urho3D
  12. {
  13. /// Profiling data for one block in the profiling tree.
  14. /// @nobind
  15. class URHO3D_API ProfilerBlock
  16. {
  17. public:
  18. /// Construct with the specified parent block and name.
  19. ProfilerBlock(ProfilerBlock* parent, const char* name) :
  20. name_(nullptr),
  21. time_(0),
  22. maxTime_(0),
  23. count_(0),
  24. parent_(parent),
  25. frameTime_(0),
  26. frameMaxTime_(0),
  27. frameCount_(0),
  28. intervalTime_(0),
  29. intervalMaxTime_(0),
  30. intervalCount_(0),
  31. totalTime_(0),
  32. totalMaxTime_(0),
  33. totalCount_(0)
  34. {
  35. if (name)
  36. {
  37. size_t size = (size_t)String::CStringLength(name) + 1;
  38. name_ = new char[size];
  39. memcpy(name_, name, size);
  40. }
  41. }
  42. /// Destruct. Free the child blocks.
  43. virtual ~ProfilerBlock()
  44. {
  45. for (Vector<ProfilerBlock*>::Iterator i = children_.Begin(); i != children_.End(); ++i)
  46. {
  47. delete *i;
  48. *i = nullptr;
  49. }
  50. delete [] name_;
  51. }
  52. /// Begin timing.
  53. void Begin()
  54. {
  55. timer_.Reset();
  56. ++count_;
  57. }
  58. /// End timing.
  59. void End()
  60. {
  61. long long time = timer_.GetUSec(false);
  62. if (time > maxTime_)
  63. maxTime_ = time;
  64. time_ += time;
  65. }
  66. /// End profiling frame and update interval and total values.
  67. void EndFrame()
  68. {
  69. frameTime_ = time_;
  70. frameMaxTime_ = maxTime_;
  71. frameCount_ = count_;
  72. intervalTime_ += time_;
  73. if (maxTime_ > intervalMaxTime_)
  74. intervalMaxTime_ = maxTime_;
  75. intervalCount_ += count_;
  76. totalTime_ += time_;
  77. if (maxTime_ > totalMaxTime_)
  78. totalMaxTime_ = maxTime_;
  79. totalCount_ += count_;
  80. time_ = 0;
  81. maxTime_ = 0;
  82. count_ = 0;
  83. for (Vector<ProfilerBlock*>::Iterator i = children_.Begin(); i != children_.End(); ++i)
  84. (*i)->EndFrame();
  85. }
  86. /// Begin new profiling interval.
  87. void BeginInterval()
  88. {
  89. intervalTime_ = 0;
  90. intervalMaxTime_ = 0;
  91. intervalCount_ = 0;
  92. for (Vector<ProfilerBlock*>::Iterator i = children_.Begin(); i != children_.End(); ++i)
  93. (*i)->BeginInterval();
  94. }
  95. /// Return child block with the specified name.
  96. ProfilerBlock* GetChild(const char* name)
  97. {
  98. for (Vector<ProfilerBlock*>::Iterator i = children_.Begin(); i != children_.End(); ++i)
  99. {
  100. if (!String::Compare((*i)->name_, name, true))
  101. return *i;
  102. }
  103. auto* newBlock = new ProfilerBlock(this, name);
  104. children_.Push(newBlock);
  105. return newBlock;
  106. }
  107. /// Block name.
  108. char* name_;
  109. /// High-resolution timer for measuring the block duration.
  110. HiresTimer timer_;
  111. /// Time on current frame.
  112. long long time_;
  113. /// Maximum time on current frame.
  114. long long maxTime_;
  115. /// Calls on current frame.
  116. unsigned count_;
  117. /// Parent block.
  118. ProfilerBlock* parent_;
  119. /// Child blocks.
  120. Vector<ProfilerBlock*> children_;
  121. /// Time on the previous frame.
  122. long long frameTime_;
  123. /// Maximum time on the previous frame.
  124. long long frameMaxTime_;
  125. /// Calls on the previous frame.
  126. unsigned frameCount_;
  127. /// Time during current profiler interval.
  128. long long intervalTime_;
  129. /// Maximum time during current profiler interval.
  130. long long intervalMaxTime_;
  131. /// Calls during current profiler interval.
  132. unsigned intervalCount_;
  133. /// Total accumulated time.
  134. long long totalTime_;
  135. /// All-time maximum time.
  136. long long totalMaxTime_;
  137. /// Total accumulated calls.
  138. unsigned totalCount_;
  139. };
  140. /// Hierarchical performance profiler subsystem.
  141. class URHO3D_API Profiler : public Object
  142. {
  143. URHO3D_OBJECT(Profiler, Object);
  144. public:
  145. /// Construct.
  146. explicit Profiler(Context* context);
  147. /// Destruct.
  148. ~Profiler() override;
  149. /// Begin timing a profiling block.
  150. void BeginBlock(const char* name)
  151. {
  152. // Profiler supports only the main thread currently
  153. if (!Thread::IsMainThread())
  154. return;
  155. current_ = current_->GetChild(name);
  156. current_->Begin();
  157. }
  158. /// End timing the current profiling block.
  159. void EndBlock()
  160. {
  161. if (!Thread::IsMainThread())
  162. return;
  163. current_->End();
  164. if (current_->parent_)
  165. current_ = current_->parent_;
  166. }
  167. /// Begin the profiling frame. Called by HandleBeginFrame().
  168. void BeginFrame();
  169. /// End the profiling frame. Called by HandleEndFrame().
  170. void EndFrame();
  171. /// Begin a new interval.
  172. void BeginInterval();
  173. /// Return profiling data as text output. This method is not thread-safe.
  174. const String& PrintData(bool showUnused = false, bool showTotal = false, unsigned maxDepth = M_MAX_UNSIGNED) const;
  175. /// Return the current profiling block.
  176. const ProfilerBlock* GetCurrentBlock() { return current_; }
  177. /// Return the root profiling block.
  178. const ProfilerBlock* GetRootBlock() { return root_; }
  179. protected:
  180. /// Return profiling data as text output for a specified profiling block.
  181. void PrintData(ProfilerBlock* block, String& output, unsigned depth, unsigned maxDepth, bool showUnused, bool showTotal) const;
  182. /// Current profiling block.
  183. ProfilerBlock* current_;
  184. /// Root profiling block.
  185. ProfilerBlock* root_;
  186. /// Frames in the current interval.
  187. unsigned intervalFrames_;
  188. };
  189. /// Helper class for automatically beginning and ending a profiling block.
  190. /// @nobind
  191. class URHO3D_API AutoProfileBlock
  192. {
  193. public:
  194. /// Construct. Begin a profiling block with the specified name and optional call count.
  195. AutoProfileBlock(Profiler* profiler, const char* name) :
  196. profiler_(profiler)
  197. {
  198. if (profiler_)
  199. profiler_->BeginBlock(name);
  200. }
  201. /// Destruct. End the profiling block.
  202. ~AutoProfileBlock()
  203. {
  204. if (profiler_)
  205. profiler_->EndBlock();
  206. }
  207. private:
  208. /// Profiler.
  209. Profiler* profiler_;
  210. };
  211. #ifdef URHO3D_TRACY_PROFILING // Use Tracy profiler
  212. /// Macro for scoped profiling with a name.
  213. #define URHO3D_PROFILE(name) ZoneScopedN(#name)
  214. #elif defined(URHO3D_PROFILING) // Use default profiler
  215. /// Macro for scoped profiling with a name.
  216. #define URHO3D_PROFILE(name) Urho3D::AutoProfileBlock profile_ ## name (GetSubsystem<Urho3D::Profiler>(), #name)
  217. #else // Profiling off
  218. #define URHO3D_PROFILE(name)
  219. #endif
  220. #ifdef URHO3D_TRACY_PROFILING // Use Tracy profiler
  221. /// Macro for scoped profiling with a name and color.
  222. #define URHO3D_PROFILE_COLOR(name, color) ZoneScopedNC(#name, color)
  223. /// Macro for scoped profiling with a dynamic string name.
  224. #define URHO3D_PROFILE_STR(nameStr, size) ZoneName(nameStr, size)
  225. /// Macro for marking a game frame.
  226. #define URHO3D_PROFILE_FRAME() FrameMark
  227. /// Macro for recording name of current thread.
  228. #define URHO3D_PROFILE_THREAD(name) tracy::SetThreadName(name)
  229. /// Macro for scoped profiling of a function.
  230. #define URHO3D_PROFILE_FUNCTION() ZoneScopedN(__FUNCTION__)
  231. /// Color used for highlighting event.
  232. #define URHO3D_PROFILE_EVENT_COLOR tracy::Color::OrangeRed
  233. /// Color used for highlighting resource.
  234. #define URHO3D_PROFILE_RESOURCE_COLOR tracy::Color::MediumSeaGreen
  235. #else // Tracy profiler off
  236. #define URHO3D_PROFILE_COLOR(name, color)
  237. #define URHO3D_PROFILE_STR(nameStr, size)
  238. #define URHO3D_PROFILE_FRAME()
  239. #define URHO3D_PROFILE_THREAD(name)
  240. #define URHO3D_PROFILE_FUNCTION()
  241. #define URHO3D_PROFILE_EVENT_COLOR
  242. #define URHO3D_PROFILE_RESOURCE_COLOR
  243. #endif
  244. }