Profiler.h 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. //
  2. // Copyright (c) 2008-2020 the Urho3D project.
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #pragma once
  23. #include "../Container/Str.h"
  24. #include "../Core/Thread.h"
  25. #include "../Core/Timer.h"
  26. namespace Urho3D
  27. {
  28. /// Profiling data for one block in the profiling tree.
  29. /// @nobind
  30. class URHO3D_API ProfilerBlock
  31. {
  32. public:
  33. /// Construct with the specified parent block and name.
  34. ProfilerBlock(ProfilerBlock* parent, const char* name) :
  35. name_(nullptr),
  36. time_(0),
  37. maxTime_(0),
  38. count_(0),
  39. parent_(parent),
  40. frameTime_(0),
  41. frameMaxTime_(0),
  42. frameCount_(0),
  43. intervalTime_(0),
  44. intervalMaxTime_(0),
  45. intervalCount_(0),
  46. totalTime_(0),
  47. totalMaxTime_(0),
  48. totalCount_(0)
  49. {
  50. if (name)
  51. {
  52. unsigned nameLength = String::CStringLength(name);
  53. name_ = new char[nameLength + 1];
  54. memcpy(name_, name, nameLength + 1);
  55. }
  56. }
  57. /// Destruct. Free the child blocks.
  58. virtual ~ProfilerBlock()
  59. {
  60. for (PODVector<ProfilerBlock*>::Iterator i = children_.Begin(); i != children_.End(); ++i)
  61. {
  62. delete *i;
  63. *i = nullptr;
  64. }
  65. delete [] name_;
  66. }
  67. /// Begin timing.
  68. void Begin()
  69. {
  70. timer_.Reset();
  71. ++count_;
  72. }
  73. /// End timing.
  74. void End()
  75. {
  76. long long time = timer_.GetUSec(false);
  77. if (time > maxTime_)
  78. maxTime_ = time;
  79. time_ += time;
  80. }
  81. /// End profiling frame and update interval and total values.
  82. void EndFrame()
  83. {
  84. frameTime_ = time_;
  85. frameMaxTime_ = maxTime_;
  86. frameCount_ = count_;
  87. intervalTime_ += time_;
  88. if (maxTime_ > intervalMaxTime_)
  89. intervalMaxTime_ = maxTime_;
  90. intervalCount_ += count_;
  91. totalTime_ += time_;
  92. if (maxTime_ > totalMaxTime_)
  93. totalMaxTime_ = maxTime_;
  94. totalCount_ += count_;
  95. time_ = 0;
  96. maxTime_ = 0;
  97. count_ = 0;
  98. for (PODVector<ProfilerBlock*>::Iterator i = children_.Begin(); i != children_.End(); ++i)
  99. (*i)->EndFrame();
  100. }
  101. /// Begin new profiling interval.
  102. void BeginInterval()
  103. {
  104. intervalTime_ = 0;
  105. intervalMaxTime_ = 0;
  106. intervalCount_ = 0;
  107. for (PODVector<ProfilerBlock*>::Iterator i = children_.Begin(); i != children_.End(); ++i)
  108. (*i)->BeginInterval();
  109. }
  110. /// Return child block with the specified name.
  111. ProfilerBlock* GetChild(const char* name)
  112. {
  113. for (PODVector<ProfilerBlock*>::Iterator i = children_.Begin(); i != children_.End(); ++i)
  114. {
  115. if (!String::Compare((*i)->name_, name, true))
  116. return *i;
  117. }
  118. auto* newBlock = new ProfilerBlock(this, name);
  119. children_.Push(newBlock);
  120. return newBlock;
  121. }
  122. /// Block name.
  123. char* name_;
  124. /// High-resolution timer for measuring the block duration.
  125. HiresTimer timer_;
  126. /// Time on current frame.
  127. long long time_;
  128. /// Maximum time on current frame.
  129. long long maxTime_;
  130. /// Calls on current frame.
  131. unsigned count_;
  132. /// Parent block.
  133. ProfilerBlock* parent_;
  134. /// Child blocks.
  135. PODVector<ProfilerBlock*> children_;
  136. /// Time on the previous frame.
  137. long long frameTime_;
  138. /// Maximum time on the previous frame.
  139. long long frameMaxTime_;
  140. /// Calls on the previous frame.
  141. unsigned frameCount_;
  142. /// Time during current profiler interval.
  143. long long intervalTime_;
  144. /// Maximum time during current profiler interval.
  145. long long intervalMaxTime_;
  146. /// Calls during current profiler interval.
  147. unsigned intervalCount_;
  148. /// Total accumulated time.
  149. long long totalTime_;
  150. /// All-time maximum time.
  151. long long totalMaxTime_;
  152. /// Total accumulated calls.
  153. unsigned totalCount_;
  154. };
  155. /// Hierarchical performance profiler subsystem.
  156. class URHO3D_API Profiler : public Object
  157. {
  158. URHO3D_OBJECT(Profiler, Object);
  159. public:
  160. /// Construct.
  161. explicit Profiler(Context* context);
  162. /// Destruct.
  163. ~Profiler() override;
  164. /// Begin timing a profiling block.
  165. void BeginBlock(const char* name)
  166. {
  167. // Profiler supports only the main thread currently
  168. if (!Thread::IsMainThread())
  169. return;
  170. current_ = current_->GetChild(name);
  171. current_->Begin();
  172. }
  173. /// End timing the current profiling block.
  174. void EndBlock()
  175. {
  176. if (!Thread::IsMainThread())
  177. return;
  178. current_->End();
  179. if (current_->parent_)
  180. current_ = current_->parent_;
  181. }
  182. /// Begin the profiling frame. Called by HandleBeginFrame().
  183. void BeginFrame();
  184. /// End the profiling frame. Called by HandleEndFrame().
  185. void EndFrame();
  186. /// Begin a new interval.
  187. void BeginInterval();
  188. /// Return profiling data as text output. This method is not thread-safe.
  189. const String& PrintData(bool showUnused = false, bool showTotal = false, unsigned maxDepth = M_MAX_UNSIGNED) const;
  190. /// Return the current profiling block.
  191. const ProfilerBlock* GetCurrentBlock() { return current_; }
  192. /// Return the root profiling block.
  193. const ProfilerBlock* GetRootBlock() { return root_; }
  194. protected:
  195. /// Return profiling data as text output for a specified profiling block.
  196. void PrintData(ProfilerBlock* block, String& output, unsigned depth, unsigned maxDepth, bool showUnused, bool showTotal) const;
  197. /// Current profiling block.
  198. ProfilerBlock* current_;
  199. /// Root profiling block.
  200. ProfilerBlock* root_;
  201. /// Frames in the current interval.
  202. unsigned intervalFrames_;
  203. };
  204. /// Helper class for automatically beginning and ending a profiling block.
  205. /// @nobind
  206. class URHO3D_API AutoProfileBlock
  207. {
  208. public:
  209. /// Construct. Begin a profiling block with the specified name and optional call count.
  210. AutoProfileBlock(Profiler* profiler, const char* name) :
  211. profiler_(profiler)
  212. {
  213. if (profiler_)
  214. profiler_->BeginBlock(name);
  215. }
  216. /// Destruct. End the profiling block.
  217. ~AutoProfileBlock()
  218. {
  219. if (profiler_)
  220. profiler_->EndBlock();
  221. }
  222. private:
  223. /// Profiler.
  224. Profiler* profiler_;
  225. };
  226. #ifdef URHO3D_PROFILING
  227. #define URHO3D_PROFILE(name) Urho3D::AutoProfileBlock profile_ ## name (GetSubsystem<Urho3D::Profiler>(), #name)
  228. #else
  229. #define URHO3D_PROFILE(name)
  230. #endif
  231. }