hierarchical_timer.h

Go to the documentation of this file.
00001 
00005 /* Copyright, 2000, 2001 Nevrax Ltd.
00006  *
00007  * This file is part of NEVRAX NeL Network Services.
00008  * NEVRAX NeL Network Services is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2, or (at your option)
00011  * any later version.
00012 
00013  * NEVRAX NeL Network Services is distributed in the hope that it will be useful, but
00014  * WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00016  * General Public License for more details.
00017 
00018  * You should have received a copy of the GNU General Public License
00019  * along with NEVRAX NeL Network Services; see the file COPYING. If not, write to the
00020  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00021  * MA 02111-1307, USA.
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 // You should need only this macro, bench the local scope
00043 #   define H_AUTO(__name)       static NLMISC::CHTimer  __name##_timer(#__name); NLMISC::CAutoTimer __name##_auto(&__name##_timer);
00044 
00045 // Same as H_AUTO but you don't have to give a name, it uses the function/line
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 // If you want to bench a specific part of the code
00049 #   define H_BEFORE(__name)     static NLMISC::CHTimer  __name##_timer(#__name); __name##_timer.before();
00050 #   define H_AFTER(__name)      __name##_timer.after();
00051 
00052 // Display the timer info after each loop call
00053 #   define H_AUTO_INST(__name)  static NLMISC::CHTimer  __name##_timer(#__name); NLMISC::CAutoTimerInst __name##_auto(&__name##_timer);
00054 
00055 // H_AUTO split in 2. The declaration of the static timer, and a CAutoTimer instance.
00056 // Useful to group same timer bench in different functions for example
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 // void macros
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 // Visual C++ warning : ebp maybe modified
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     // start measure
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     // end measure
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     // get measure
00134     uint64  getNumTicks() const
00135     {
00136 #ifdef NL_DEBUG
00137         nlassert(!_Started);
00138 #endif
00139         nlassert(_NumTicks != 0);
00140         return _NumTicks;
00141     }
00142     // This compute the duration of start and stop (in cycles).
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     // this enum is used to sort displayed results
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     // Ends a measuring session
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     // Get this node name
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;    // the hierarchical timer this node is associated with
00301         uint64                  TotalTime; // the total time spent in that node, including sons
00302         uint64                  LastSonsTotalTime;
00303         uint64                  SonsTotalTime; // maybe different from LastSonsTotalTime while benching the sons and if the display is called in a benched node
00304         TTimeVect               Measures;  // All time measures. Used only when standard deviation is wanted
00305         uint64                  MinTime;   // the minimum time spent in that node
00306         uint64                  MaxTime;   // the maximum time spent in that node
00307         uint64                  NumVisits; // the number of time the execution has gone through this node
00308         // session max measure
00309         uint64                  SessionCurrent;
00310         uint64                  SessionMax;
00311         //
00312         uint64                  SonsPreambule; // preamble time for the sons
00313         CSimpleClock            Clock;         // a clock to do the measures at this node
00314         // ctor
00315       CNode(CHTimer *owner = NULL, CNode    *parent = NULL) : Parent(parent), Owner(owner)
00316         {
00317             reset();
00318         }
00319         // dtor
00320         ~CNode();
00321         // Get the number of nodes in the tree starting at this node
00322         uint  getNumNodes() const;
00323         // release the sons, should not be benching when calling this
00324         void    releaseSons();
00325         // reset this node measures
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         // Display this node path
00341         void    displayPath(CLog *log) const;
00342         // Get this node path
00343         void    getPath(std::string &dest) const;
00344 
00345         // reset session current
00346         void    resetSessionCurrent()
00347         {
00348             SessionCurrent = 0;
00349             for (uint i=0; i<Sons.size(); ++i)
00350                 Sons[i]->resetSessionCurrent();
00351         }
00352         // reset all session stats
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         // spread session value through the while node tree
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         // build stats from a single node
00384         void buildFromNode(CNode *node, double msPerTick);
00385 
00386         // build stats from a vector of nodes
00387         void buildFromNodes(CNode **firstNode, uint numNodes, double msPerTick);
00388 
00389         // display stats
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     // Stats and the associated timer
00398     struct CTimerStat : public CStats
00399     {
00400         CHTimer *Timer;
00401     };
00402     // Stats and the associated node
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         // Less operator
00417         bool operator()(const CStats *lhs, const CStats *rhs);
00418     };
00419 
00420 
00424     struct  CExamStackEntry
00425     {
00426         // The node.
00427         CNode               *Node;
00428         // The current child to process.
00429         uint                CurrentChild;
00430         // The childes, sorted by specific criterion.
00431         std::vector<CNode*> Children;
00432         // The depth of the entry
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     // Real Job.
00451     void            doBefore();
00452     void            doAfter(bool displayAfter = false);
00453 
00454     static void     estimateAfterStopTime();
00455 
00456 private:
00457     // walk the tree to current execution node, creating it if necessary
00458     void            walkTreeToCurrent();
00459 private:
00460     // node name
00461     const  char                     *_Name;
00462     // the parent timer
00463     CHTimer                         *_Parent;
00464     // the sons timers
00465     TTimerVect                      _Sons;
00466     // Tells if this is a root node
00467     bool                            _IsRoot;
00468 private:
00469     // root node of the hierarchy
00470     static CNode                    _RootNode;
00471     // the current node of the execution
00472     static CNode                    *_CurrNode;
00473     // the root timer
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 } // NLMISC
00534 
00535 #endif // NL_HIERARCHICAL_TIMER_H
00536 
00537 /* End of hierarchical_timer.h */

Generated on Thu Jan 7 08:26:22 2010 for NeL by  doxygen 1.6.1