Pyrogenesis  trunk
Profile.h
Go to the documentation of this file.
1 /* Copyright (C) 2013 Wildfire Games.
2  * This file is part of 0 A.D.
3  *
4  * 0 A.D. is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * 0 A.D. is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 /*
19  * GPG3-style hierarchical profiler
20  */
21 
22 #ifndef INCLUDED_PROFILE
23 #define INCLUDED_PROFILE
24 
25 #include <vector>
26 
27 #include "lib/adts/ring_buf.h"
28 #include "ps/Profiler2.h"
29 #include "ps/Singleton.h"
30 #include "ps/ThreadUtil.h"
31 
32 #include <boost/flyweight.hpp>
33 #include <boost/flyweight/key_value.hpp>
34 #include <boost/flyweight/no_locking.hpp>
35 #include <boost/flyweight/no_tracking.hpp>
36 
37 #define PROFILE_AMORTIZE_FRAMES 30
38 #define PROFILE_AMORTIZE_TURNS 1
39 
40 class CProfileManager;
41 class CProfileNodeTable;
42 
43 class CStr8;
44 class CStrW;
45 
46 // To profile scripts usefully, we use a call hook that's called on every enter/exit,
47 // and need to find the function name. But most functions are anonymous so we make do
48 // with filename plus line number instead.
49 // Computing the names is fairly expensive, and we need to return an interned char*
50 // for the profiler to hold a copy of, so we use boost::flyweight to construct interned
51 // strings per call location.
52 //
53 // TODO: Check again how much the overhead for getting filename and line really is and if
54 // it has increased with the new approach after the SpiderMonkey 31 upgrade.
55 //
56 // Flyweight types (with no_locking because the call hooks are only used in the
57 // main thread, and no_tracking because we mustn't delete values the profiler is
58 // using and it's not going to waste much memory)
59 typedef boost::flyweight<
60  std::string,
61  boost::flyweights::no_tracking,
62  boost::flyweights::no_locking
64 
66 {
68 
69  friend class CProfileManager;
70  friend class CProfileNodeTable;
71 
72  const char* name;
73 
78 
83 
88 
89  double start;
91  int recursion;
92 
94  std::vector<CProfileNode*> children;
95  std::vector<CProfileNode*> script_children;
97 
98 public:
99  typedef std::vector<CProfileNode*>::iterator profile_iterator;
100  typedef std::vector<CProfileNode*>::const_iterator const_profile_iterator;
101 
102  CProfileNode( const char* name, CProfileNode* parent );
103  ~CProfileNode();
104 
105  const char* GetName() const { return name; }
106 
107  double GetFrameCalls() const;
108  double GetFrameTime() const;
109  double GetTurnCalls() const;
110  double GetTurnTime() const;
111  double GetFrameMallocs() const;
112  double GetTurnMallocs() const;
113 
114  const CProfileNode* GetChild( const char* name ) const;
115  const CProfileNode* GetScriptChild( const char* name ) const;
116  const std::vector<CProfileNode*>* GetChildren() const { return( &children ); }
117  const std::vector<CProfileNode*>* GetScriptChildren() const { return( &script_children ); }
118 
119  bool CanExpand();
120 
121  CProfileNode* GetChild( const char* name );
122  CProfileNode* GetScriptChild( const char* name );
123  CProfileNode* GetParent() const { return( parent ); }
124 
125  // Resets timing information for this node and all its children
126  void Reset();
127  // Resets frame timings for this node and all its children
128  void Frame();
129  // Resets turn timings for this node and all its children
130  void Turn();
131  // Enters the node
132  void Call();
133  // Leaves the node. Returns true if the node has actually been left
134  bool Return();
135 };
136 
137 class CProfileManager : public Singleton<CProfileManager>
138 {
141 
143 
144  void PerformStructuralReset();
145 
146 public:
147  CProfileManager();
148  ~CProfileManager();
149 
150  // Begins timing for a named subsection
151  void Start( const char* name );
152  void StartScript( const char* name );
153 
154  // Ends timing for the current subsection
155  void Stop();
156 
157  // Resets all timing information
158  void Reset();
159  // Resets frame timing information
160  void Frame();
161  // Resets turn timing information
162  // (Must not be called before Frame)
163  void Turn();
164  // Resets absolutely everything, at the end of this frame
165  void StructuralReset();
166 
167  inline const CProfileNode* GetCurrent() { return( current ); }
168  inline const CProfileNode* GetRoot() { return( root ); }
169 };
170 
171 #define g_Profiler CProfileManager::GetSingleton()
172 
174 {
175 public:
176  CProfileSample(const char* name)
177  {
179  {
180  // The profiler is only safe to use on the main thread
182 
183  g_Profiler.Start(name);
184  }
185  }
187  {
189  g_Profiler.Stop();
190  }
191 };
192 
194 {
195 public:
196  CProfileSampleScript( const char* name )
197  {
199  {
200  // The profiler is only safe to use on the main thread,
201  // but scripts get run on other threads too so we need to
202  // conditionally enable the profiler.
203  // (This usually only gets used in debug mode so performance
204  // doesn't matter much.)
206  g_Profiler.StartScript( name );
207  }
208  }
210  {
213  g_Profiler.Stop();
214  }
215 };
216 
217 // Put a PROFILE("xyz") block at the start of all code to be profiled.
218 // Profile blocks last until the end of the containing scope.
219 #define PROFILE(name) CProfileSample __profile(name)
220 // Cheat a bit to make things slightly easier on the user
221 #define PROFILE_START(name) { CProfileSample __profile(name)
222 #define PROFILE_END(name) }
223 
224 // Do both old and new profilers simultaneously (1+2=3), for convenience.
225 #define PROFILE3(name) PROFILE(name); PROFILE2(name)
226 
227 // Also do GPU
228 #define PROFILE3_GPU(name) PROFILE(name); PROFILE2(name); PROFILE2_GPU(name)
229 
230 #endif // INCLUDED_PROFILE
RingBuf< double, PROFILE_AMORTIZE_TURNS > time_per_turn
Definition: Profile.h:82
const CProfileNode * GetChild(const char *name) const
Definition: Profile.cpp:323
RingBuf< int, PROFILE_AMORTIZE_TURNS > calls_per_turn
Definition: Profile.h:77
void Turn()
Definition: Profile.cpp:413
CProfileSample(const char *name)
Definition: Profile.h:176
double GetFrameCalls() const
Definition: Profile.cpp:293
const char * GetName() const
Definition: Profile.h:105
bool Return()
Definition: Profile.cpp:665
const std::vector< CProfileNode * > * GetScriptChildren() const
Definition: Profile.h:117
const CProfileNode * GetCurrent()
Definition: Profile.h:167
RingBuf< int, PROFILE_AMORTIZE_FRAMES > calls_per_frame
Definition: Profile.h:76
CProfileNode * parent
Definition: Profile.h:93
std::vector< CProfileNode * > children
Definition: Profile.h:94
const CProfileNode * GetRoot()
Definition: Profile.h:168
double time_turn_current
Definition: Profile.h:80
long mallocs_turn_current
Definition: Profile.h:85
double start
Definition: Profile.h:89
int calls_turn_current
Definition: Profile.h:75
CProfileNode * GetParent() const
Definition: Profile.h:123
Class CProfileNodeTable: Implement ProfileViewer&#39;s AbstractProfileTable interface in order to display...
Definition: Profile.cpp:51
boost::flyweight< std::string, boost::flyweights::no_tracking, boost::flyweights::no_locking > StringFlyweight
Definition: Profile.h:44
void Frame()
Definition: Profile.cpp:396
~CProfileNode()
Definition: Profile.cpp:274
NONCOPYABLE(CProfileNode)
CProfileNodeTable * display_table
Definition: Profile.h:96
CProfileNode * root
Definition: Profile.h:139
Definition: Profile.h:173
#define ENSURE(expr)
ensure the expression <expr> evaluates to non-zero.
Definition: debug.h:287
int recursion
Definition: Profile.h:91
CProfileSampleScript(const char *name)
Definition: Profile.h:196
std::vector< CProfileNode * >::const_iterator const_profile_iterator
Definition: Profile.h:100
#define g_Profiler
Definition: Profile.h:171
~CProfileSampleScript()
Definition: Profile.h:209
Definition: Profile.h:193
bool needs_structural_reset
Definition: Profile.h:142
New profiler (complementing the older CProfileManager)
CProfileNode * current
Definition: Profile.h:140
static bool IsInitialised()
Definition: Singleton.h:63
double GetFrameMallocs() const
Definition: Profile.cpp:313
const std::vector< CProfileNode * > * GetChildren() const
Definition: Profile.h:116
Definition: Profile.h:137
Definition: Profile.h:65
long mallocs_frame_current
Definition: Profile.h:84
void Call()
Definition: Profile.cpp:654
const CProfileNode * GetScriptChild(const char *name) const
Definition: Profile.cpp:333
~CProfileSample()
Definition: Profile.h:186
double GetTurnTime() const
Definition: Profile.cpp:308
double time_frame_current
Definition: Profile.h:79
friend class CProfileManager
Definition: Profile.h:69
RingBuf< double, PROFILE_AMORTIZE_FRAMES > time_per_frame
Definition: Profile.h:81
CProfileNode(const char *name, CProfileNode *parent)
Definition: Profile.cpp:262
void Reset()
Definition: Profile.cpp:372
int calls_frame_current
Definition: Profile.h:74
double GetFrameTime() const
Definition: Profile.cpp:298
bool IsMainThread()
Returns whether the current thread is the &#39;main&#39; thread (i.e.
Definition: ThreadUtil.cpp:25
Definition: Singleton.h:34
const char * name
Definition: Profile.h:72
long start_mallocs
Definition: Profile.h:90
RingBuf< long, PROFILE_AMORTIZE_FRAMES > mallocs_per_frame
Definition: Profile.h:86
RingBuf< long, PROFILE_AMORTIZE_TURNS > mallocs_per_turn
Definition: Profile.h:87
std::vector< CProfileNode * > script_children
Definition: Profile.h:95
double GetTurnMallocs() const
Definition: Profile.cpp:318
bool CanExpand()
Definition: Profile.cpp:367
std::vector< CProfileNode * >::iterator profile_iterator
Definition: Profile.h:99
double GetTurnCalls() const
Definition: Profile.cpp:303