Profiler.h 8.4 KB

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