00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #ifndef NL_HIERARCHICAL_TIMER_H
00025 #define NL_HIERARCHICAL_TIMER_H
00026
00027 #include <string>
00028 #include <vector>
00029 #include <algorithm>
00030
00031 #include "types_nl.h"
00032 #include "time_nl.h"
00033 #include "debug.h"
00034
00035 #ifndef NL_NO_DEBUG
00036 # define ALLOW_TIMING_MEASURES
00037 #endif // NL_NO_DEBUG
00038
00039
00040 #ifdef ALLOW_TIMING_MEASURES
00041
00042
00043 # define H_AUTO(__name) static NLMISC::CHTimer __name##_timer(#__name); NLMISC::CAutoTimer __name##_auto(&__name##_timer);
00044
00045
00046 # define H_AUTO2 static std::string __str_##__LINE__(NLMISC::toString("%s:%d", __FUNCTION__, __LINE__)); static NLMISC::CHTimer __timer_##__LINE__(__str_##__LINE__.c_str()); NLMISC::CAutoTimer __auto_##__LINE__(&__timer_##__LINE__);
00047
00048
00049 # define H_BEFORE(__name) static NLMISC::CHTimer __name##_timer(#__name); __name##_timer.before();
00050 # define H_AFTER(__name) __name##_timer.after();
00051
00052
00053 # define H_AUTO_INST(__name) static NLMISC::CHTimer __name##_timer(#__name); NLMISC::CAutoTimerInst __name##_auto(&__name##_timer);
00054
00055
00056
00057 # define H_AUTO_DECL(__name) static NLMISC::CHTimer __name##_timer(#__name);
00058 # define H_AUTO_USE(__name) NLMISC::CAutoTimer __name##_auto(&__name##_timer);
00059
00060
00061 # define H_TIME(__name,__inst) \
00062 { \
00063 static NLMISC::CHTimer nl_h_timer(#__name); \
00064 nl_h_timer.before(); \
00065 __inst \
00066 nl_h_timer.after(); \
00067 }
00068
00069 #else
00070
00071 # define H_TIME(__name,__inst) __inst
00072 # define H_BEFORE(__name)
00073 # define H_AFTER(__name)
00074 # define H_AUTO(__name)
00075 # define H_AUTO2
00076 # define H_AUTO_INST(__name)
00077 # define H_AUTO_DECL(__name)
00078 # define H_AUTO_USE(__name)
00079 #endif
00080
00081 namespace NLMISC
00082 {
00083
00084 #ifdef NL_OS_WINDOWS
00085
00086 # pragma warning(disable:4731)
00087 #endif
00088
00089
00098 class CSimpleClock
00099 {
00100 public:
00101 CSimpleClock() : _NumTicks(0)
00102 {
00103 #ifdef NL_DEBUG
00104 _Started = false;
00105 #endif
00106 }
00107
00108 void start()
00109 {
00110 #ifdef NL_DEBUG
00111 nlassert(!_Started);
00112 _Started = true;
00113 #endif
00114 #ifdef NL_CPU_INTEL
00115 _StartTick = rdtsc();
00116 #else
00117 _StartTick = CTime::getPerformanceTime();
00118 #endif
00119 }
00120
00121 void stop()
00122 {
00123 #ifdef NL_DEBUG
00124 nlassert(_Started);
00125 _Started = false;
00126 #endif
00127 #ifdef NL_CPU_INTEL
00128 _NumTicks = rdtsc() - _StartTick;
00129 #else
00130 _NumTicks = CTime::getPerformanceTime() - _StartTick;
00131 #endif
00132 }
00133
00134 uint64 getNumTicks() const
00135 {
00136 #ifdef NL_DEBUG
00137 nlassert(!_Started);
00138 #endif
00139 nlassert(_NumTicks != 0);
00140 return _NumTicks;
00141 }
00142
00143 static void init();
00147 static uint64 getStartStopNumTicks()
00148 {
00149 return _StartStopNumTicks;
00150 }
00151 private:
00152 uint64 _StartTick;
00153 uint64 _NumTicks;
00154 #ifdef NL_DEBUG
00155 bool _Started;
00156 #endif
00157 static bool _InitDone;
00158 static uint64 _StartStopNumTicks;
00159 };
00160
00161
00185 class CHTimer
00186 {
00187 public:
00188
00189 enum TSortCriterion { NoSort,
00190 TotalTime,
00191 TotalTimeWithoutSons,
00192 MeanTime,
00193 NumVisits,
00194 MaxTime,
00195 MinTime,
00196 MaxSession,
00197 SortCriterionsLast
00198 };
00199 public:
00201 CHTimer() : _Name(NULL), _Parent(NULL), _IsRoot(false) {}
00202 CHTimer(const char *name, bool isRoot = false) : _Name(name), _Parent(NULL), _IsRoot(isRoot) {}
00204 void before()
00205 {
00206 if (_Benching)
00207 doBefore();
00208 }
00209
00210 void after()
00211 {
00212 if (_Benching)
00213 doAfter(false);
00214 }
00215 void after(bool displayAfter)
00216 {
00217 if (_Benching)
00218 doAfter(displayAfter);
00219 }
00220
00221 const char *getName() const { return _Name; }
00222 void setName(const char *name) { _Name = name; }
00227 static void startBench(bool wantStandardDeviation = false, bool quick = false, bool reset = true);
00230 static void bench() { startBench(); }
00233 static void adjust() {}
00235 static void endBench();
00236
00237 static bool benching () { return _Benching; }
00238
00242 static void display(CLog *log= InfoLog, TSortCriterion criterion = TotalTime, bool displayInline = true, bool displayEx = true);
00248 static void displayByExecutionPath(CLog *log= InfoLog, TSortCriterion criterion = TotalTime, bool displayInline = true, bool alignPaths = true, bool displayEx = true);
00249
00254 static void displayHierarchical(CLog *log= InfoLog, bool displayEx = true, uint labelNumChar = 32, uint indentationStep = 2);
00255
00260 static void displayHierarchicalByExecutionPath(CLog *log= InfoLog, bool displayEx = true, uint labelNumChar = 32, uint indentationStep = 2);
00261
00266 static void displayHierarchicalByExecutionPathSorted(CLog *log= InfoLog, TSortCriterion criterion = TotalTime, bool displayEx = true, uint labelNumChar = 32, uint indentationStep = 2);
00267
00272 static void displaySummary(CLog *log= InfoLog, TSortCriterion criterion = TotalTime, bool displayEx = true, uint labelNumChar = 32, uint indentationStep = 2, uint maxDepth = 3);
00273
00275 static void clear();
00276
00278 static void clearSessionCurrent();
00279
00281 static void clearSessionStats();
00282
00284 static void updateSessionStats();
00285
00288 private:
00289 struct CNode;
00290 typedef std::vector<CNode *> TNodeVect;
00291 typedef std::vector<CHTimer *> TTimerVect;
00292
00294 struct CNode
00295 {
00296 typedef std::vector<double> TTimeVect;
00297
00298 CNode *Parent;
00299 TNodeVect Sons;
00300 CHTimer *Owner;
00301 uint64 TotalTime;
00302 uint64 LastSonsTotalTime;
00303 uint64 SonsTotalTime;
00304 TTimeVect Measures;
00305 uint64 MinTime;
00306 uint64 MaxTime;
00307 uint64 NumVisits;
00308
00309 uint64 SessionCurrent;
00310 uint64 SessionMax;
00311
00312 uint64 SonsPreambule;
00313 CSimpleClock Clock;
00314
00315 CNode(CHTimer *owner = NULL, CNode *parent = NULL) : Parent(parent), Owner(owner)
00316 {
00317 reset();
00318 }
00319
00320 ~CNode();
00321
00322 uint getNumNodes() const;
00323
00324 void releaseSons();
00325
00326 void reset()
00327 {
00328 SonsTotalTime = 0;
00329 TotalTime = 0;
00330 MaxTime = 0;
00331 MinTime = (uint64) -1;
00332 NumVisits = 0;
00333 SonsPreambule = 0;
00334 LastSonsTotalTime = 0;
00335 SessionCurrent = 0;
00336 SessionMax = 0;
00337 NLMISC::contReset(Measures);
00338 }
00339
00340
00341 void displayPath(CLog *log) const;
00342
00343 void getPath(std::string &dest) const;
00344
00345
00346 void resetSessionCurrent()
00347 {
00348 SessionCurrent = 0;
00349 for (uint i=0; i<Sons.size(); ++i)
00350 Sons[i]->resetSessionCurrent();
00351 }
00352
00353 void resetSessionStats()
00354 {
00355 SessionCurrent = 0;
00356 SessionMax = 0;
00357 for (uint i=0; i<Sons.size(); ++i)
00358 Sons[i]->resetSessionStats();
00359 }
00360
00361 void spreadSession()
00362 {
00363 SessionMax = SessionCurrent;
00364 for (uint i=0; i<Sons.size(); ++i)
00365 Sons[i]->spreadSession();
00366 }
00367 };
00368
00372 struct CStats
00373 {
00374 double TimeStandardDeviation;
00375 double TotalTime;
00376 double TotalTimeWithoutSons;
00377 double MeanTime;
00378 uint64 NumVisits;
00379 double MinTime;
00380 double MaxTime;
00381 double SessionMaxTime;
00382
00383
00384 void buildFromNode(CNode *node, double msPerTick);
00385
00386
00387 void buildFromNodes(CNode **firstNode, uint numNodes, double msPerTick);
00388
00389
00390 void display(CLog *log, bool displayEx = false, bool wantStandardDeviation = false);
00391
00395 void getStats(std::string &dest, bool statEx, double rootTotalTime, bool wantStandardDeviation = false);
00396 };
00397
00398 struct CTimerStat : public CStats
00399 {
00400 CHTimer *Timer;
00401 };
00402
00403 struct CNodeStat : public CStats
00404 {
00405 CNode *Node;
00406 };
00407
00411 struct CStatSorter
00412 {
00413 CStatSorter(TSortCriterion criterion = TotalTime) : Criterion(criterion)
00414 {}
00415 TSortCriterion Criterion;
00416
00417 bool operator()(const CStats *lhs, const CStats *rhs);
00418 };
00419
00420
00424 struct CExamStackEntry
00425 {
00426
00427 CNode *Node;
00428
00429 uint CurrentChild;
00430
00431 std::vector<CNode*> Children;
00432
00433 uint Depth;
00434
00435 explicit CExamStackEntry(CNode *node)
00436 {
00437 Node= node;
00438 CurrentChild= 0;
00439 Depth = 0;
00440 }
00441
00442 explicit CExamStackEntry(CNode *node, uint depth)
00443 {
00444 Node= node;
00445 CurrentChild= 0;
00446 Depth = depth;
00447 }
00448 };
00449
00450
00451 void doBefore();
00452 void doAfter(bool displayAfter = false);
00453
00454 static void estimateAfterStopTime();
00455
00456 private:
00457
00458 void walkTreeToCurrent();
00459 private:
00460
00461 const char *_Name;
00462
00463 CHTimer *_Parent;
00464
00465 TTimerVect _Sons;
00466
00467 bool _IsRoot;
00468 private:
00469
00470 static CNode _RootNode;
00471
00472 static CNode *_CurrNode;
00473
00474 static CHTimer _RootTimer;
00478 static CSimpleClock _PreambuleClock;
00479
00480 static double _MsPerTick;
00481
00482 static bool _Benching;
00483
00484 static bool _BenchStartedOnce;
00485
00486 static bool _WantStandardDeviation;
00487
00488 static CHTimer *_CurrTimer;
00489
00490 static sint64 _AfterStopEstimateTime;
00491 static bool _AfterStopEstimateTimeDone;
00492 };
00493
00510 class CAutoTimer
00511 {
00512 private:
00513 CHTimer *_HTimer;
00514 public:
00515 CAutoTimer(CHTimer *timer) : _HTimer(timer) { _HTimer->before(); }
00516 ~CAutoTimer() { _HTimer->after(); }
00517 };
00518
00519
00523 class CAutoTimerInst
00524 {
00525 private:
00526 CHTimer *_HTimer;
00527 public:
00528 CAutoTimerInst(CHTimer *timer) : _HTimer(timer) { _HTimer->before(); }
00529 ~CAutoTimerInst() { _HTimer->after(true); }
00530 };
00531
00532
00533 }
00534
00535 #endif // NL_HIERARCHICAL_TIMER_H
00536
00537