00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "stdmisc.h"
00025
00026 #include "nel/misc/hierarchical_timer.h"
00027 #include "nel/misc/common.h"
00028 #include "nel/misc/debug.h"
00029 #include "nel/misc/command.h"
00030 #include "nel/misc/system_info.h"
00031
00032 #ifdef NL_CPU_INTEL
00033 #include "nel/misc/time_nl.h"
00034 #endif
00035
00036 #include <map>
00037
00038 namespace NLMISC
00039 {
00040
00041 bool CSimpleClock::_InitDone = false;
00042 uint64 CSimpleClock::_StartStopNumTicks = 0;
00043
00044
00045
00046 CHTimer::CNode CHTimer::_RootNode;
00047 CHTimer::CNode *CHTimer::_CurrNode = &_RootNode;
00048 CSimpleClock CHTimer::_PreambuleClock;
00049 CHTimer CHTimer::_RootTimer("root", true);
00050 bool CHTimer::_Benching = false;
00051 bool CHTimer::_BenchStartedOnce = false;
00052 double CHTimer::_MsPerTick;
00053 bool CHTimer::_WantStandardDeviation = false;
00054 CHTimer *CHTimer::_CurrTimer = &_RootTimer;
00055 sint64 CHTimer::_AfterStopEstimateTime= 0;
00056 bool CHTimer::_AfterStopEstimateTimeDone= false;
00057
00058
00059
00060
00061
00062
00063
00064
00065 void CSimpleClock::init()
00066 {
00067 if (_InitDone) return;
00068 const uint numSamples = 10000;
00069
00070 CSimpleClock observedClock;
00071 CSimpleClock measuringClock;
00072
00073 measuringClock.start();
00074 for(uint l = 0; l < numSamples; ++l)
00075 {
00076 observedClock.start();
00077 observedClock.stop();
00078 }
00079 measuringClock.stop();
00080
00081 _StartStopNumTicks = (measuringClock.getNumTicks() >> 1) / numSamples;
00082 _InitDone = true;
00083 }
00084
00085
00086
00087
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116 CHTimer::CNode::~CNode()
00117 {
00118 releaseSons();
00119 for(uint k = 0; k < Sons.size(); ++k)
00120 delete Sons[k];
00121 }
00122
00123
00124 void CHTimer::CNode::releaseSons()
00125 {
00126 for(uint k = 0; k < Sons.size(); ++k)
00127 delete Sons[k];
00128 Sons.clear();
00129 }
00130
00131
00132 void CHTimer::CNode::displayPath(CLog *log) const
00133 {
00134 std::string path;
00135 getPath(path);
00136 log->displayRawNL(("HTIMER: " + path).c_str());
00137 }
00138
00139
00140 void CHTimer::CNode::getPath(std::string &path) const
00141 {
00142 path.clear();
00143 const CNode *currNode = this;
00144 do
00145 {
00146 path = path.empty() ? currNode->Owner->getName()
00147 : currNode->Owner->getName() + std::string("::") + path;
00148 currNode = currNode->Parent;
00149 }
00150 while (currNode);
00151 }
00152
00153
00154
00155 uint CHTimer::CNode::getNumNodes() const
00156 {
00157 uint sum = 1;
00158 for(uint k = 0; k < Sons.size(); ++k)
00159 {
00160 sum += Sons[k]->getNumNodes();
00161 }
00162 return sum;
00163 }
00164
00165
00166
00167 void CHTimer::walkTreeToCurrent()
00168 {
00169 if (_IsRoot) return;
00170 bool found = false;
00171 for(uint k = 0; k < _CurrNode->Sons.size(); ++k)
00172 {
00173 if (_CurrNode->Sons[k]->Owner == this)
00174 {
00175 _CurrNode = _CurrNode->Sons[k];
00176 found = true;
00177 break;
00178 }
00179 }
00180 if (!found)
00181 {
00182
00183 _CurrNode->Sons.push_back(new CNode(this, _CurrNode));
00184 _CurrNode->Sons.back()->Parent = _CurrNode;
00185 _CurrNode = _CurrNode->Sons.back();
00186 }
00187 }
00188
00189
00190
00191
00192 void CHTimer::estimateAfterStopTime()
00193 {
00194 if(_AfterStopEstimateTimeDone)
00195 return;
00196 const uint numSamples = 1000;
00197
00198
00199 clear();
00200
00201 {
00202 #ifdef NL_CPU_INTEL
00203 double freq = (double) CSystemInfo::getProcessorFrequency(false);
00204 _MsPerTick = 1000 / (double) freq;
00205 #else
00206 _MsPerTick = CTime::ticksToSecond(1000);
00207 #endif
00208 CSimpleClock::init();
00209 }
00210
00211
00212 _Benching = true;
00213 _BenchStartedOnce = true;
00214 _RootNode.Owner = &_RootTimer;
00215 _WantStandardDeviation = false;
00216 _RootTimer.before();
00217
00218 for(uint i=0;i<numSamples;i++)
00219 {
00220 static NLMISC::CHTimer estimateSampleTimer("sampleTimer");
00221 estimateSampleTimer.before();
00222 estimateSampleTimer.after();
00223 }
00224
00225 _RootTimer.after();
00226 _Benching = false;
00227
00228
00229 _AfterStopEstimateTime= (_RootNode.TotalTime-_RootNode.SonsTotalTime) / numSamples;
00230
00231 _AfterStopEstimateTimeDone= true;
00232
00233
00234 clear();
00235 }
00236
00237
00238
00239 void CHTimer::startBench(bool wantStandardDeviation , bool quick, bool reset)
00240 {
00241 nlassert(!_Benching);
00242
00243
00244 estimateAfterStopTime();
00245
00246 if(reset)
00247 clear();
00248
00249 if(reset)
00250 {
00251 #ifdef NL_CPU_INTEL
00252 double freq = (double) CSystemInfo::getProcessorFrequency(quick);
00253 _MsPerTick = 1000 / (double) freq;
00254 #else
00255 _MsPerTick = CTime::ticksToSecond(1000);
00256 #endif
00257 CSimpleClock::init();
00258 }
00259
00260
00261 if (reset)
00262 clearSessionStats();
00263
00264
00265 clearSessionCurrent();
00266
00267
00268 _Benching = true;
00269 _BenchStartedOnce = true;
00270 _RootNode.Owner = &_RootTimer;
00271 _WantStandardDeviation = wantStandardDeviation;
00272 _RootTimer.before();
00273 }
00274
00275
00276 void CHTimer::endBench()
00277 {
00278 if (!_Benching)
00279 return;
00280
00281 if (_CurrNode == &_RootNode)
00282 {
00283 _RootTimer.after();
00284 }
00285 else
00286 {
00287 nlwarning("HTIMER: Stopping the bench inside a benched functions !");
00288 }
00289 _Benching = false;
00290
00291
00292 updateSessionStats();
00293 }
00294
00295
00296 void CHTimer::display(CLog *log, TSortCriterion criterion, bool displayInline , bool displayEx)
00297 {
00298 CSimpleClock benchClock;
00299 benchClock.start();
00300 if(!_BenchStartedOnce)
00301 {
00302 benchClock.stop();
00303 _CurrNode->SonsPreambule += benchClock.getNumTicks();
00304 return;
00305 }
00306 log->displayNL("HTIMER: =========================================================================");
00307 log->displayRawNL("HTIMER: Bench cumuled results");
00308 typedef std::map<CHTimer *, TNodeVect> TNodeMap;
00309 TNodeMap nodeMap;
00310 TNodeVect nodeLeft;
00311 nodeLeft.push_back(&_RootNode);
00312
00314 while (!nodeLeft.empty())
00315 {
00316 CNode *currNode = nodeLeft.back();
00317 nodeMap[currNode->Owner].push_back(currNode);
00318 nodeLeft.pop_back();
00319 nodeLeft.insert(nodeLeft.end(), currNode->Sons.begin(), currNode->Sons.end());
00320 }
00321
00322
00323 typedef std::vector<CTimerStat> TTimerStatVect;
00324 typedef std::vector<CTimerStat *> TTimerStatPtrVect;
00325 TTimerStatVect stats(nodeMap.size());
00326 TTimerStatPtrVect statsPtr(stats.size());
00327
00328 uint k = 0;
00329 for(TNodeMap::iterator it = nodeMap.begin(); it != nodeMap.end(); ++it)
00330 {
00331 statsPtr[k] = &stats[k];
00332 stats[k].Timer = it->first;
00333 stats[k].buildFromNodes(&(it->second[0]), it->second.size(), _MsPerTick);
00334 ++k;
00335 }
00336
00337
00338 if (criterion != NoSort)
00339 {
00340 CStatSorter sorter(criterion);
00341 std::sort(statsPtr.begin(), statsPtr.end(), sorter);
00342 }
00343
00344
00345 CStats rootStats;
00346 rootStats.buildFromNode( &_RootNode, _MsPerTick);
00347
00348
00349 uint maxNodeLenght = 0;
00350 std::string format;
00351 if (displayInline)
00352 {
00353 for(TTimerStatPtrVect::iterator statIt = statsPtr.begin(); statIt != statsPtr.end(); ++statIt)
00354 {
00355 maxNodeLenght = std::max(maxNodeLenght, (uint)strlen((*statIt)->Timer->_Name));
00356 }
00357 format = "HTIMER: %-" + NLMISC::toString(maxNodeLenght + 1) + "s %s";
00358 }
00359 std::string statsInline;
00360
00361 log->displayRawNL(format.c_str(), "", " | total | local | visits | loc%/ glb% | sessn max | min | max | mean");
00362
00363 for(TTimerStatPtrVect::iterator statIt = statsPtr.begin(); statIt != statsPtr.end(); ++statIt)
00364 {
00365 if (!displayInline)
00366 {
00367 log->displayRawNL("HTIMER: =================================");
00368 log->displayRawNL("HTIMER: Node %s", (*statIt)->Timer->_Name);
00369 (*statIt)->display(log, displayEx, _WantStandardDeviation);
00370 }
00371 else
00372 {
00373 (*statIt)->getStats(statsInline, displayEx, rootStats.TotalTime, _WantStandardDeviation);
00374 char out[4096];
00375 NLMISC::smprintf(out, 2048, format.c_str(), (*statIt)->Timer->_Name, statsInline.c_str());
00376 log->displayRawNL(out);
00377 }
00378 }
00379 benchClock.stop();
00380 _CurrNode->SonsPreambule += benchClock.getNumTicks();
00381 }
00382
00383
00384 void CHTimer::displayByExecutionPath(CLog *log, TSortCriterion criterion, bool displayInline, bool alignPaths, bool displayEx)
00385 {
00386 CSimpleClock benchClock;
00387 benchClock.start();
00388 log->displayRawNL("HTIMER: =========================================================================");
00389 log->displayRawNL("HTIMER: Bench by execution path");
00390 nlassert(_BenchStartedOnce);
00391
00392 typedef std::vector<CNodeStat> TNodeStatVect;
00393 typedef std::vector<CNodeStat *> TNodeStatPtrVect;
00394
00395 TNodeStatVect nodeStats;
00396 nodeStats.reserve(_RootNode.getNumNodes());
00397 TNodeVect nodeLeft;
00398 nodeLeft.push_back(&_RootNode);
00400 while (!nodeLeft.empty())
00401 {
00402 CNode *currNode = nodeLeft.back();
00403
00404 nodeStats.push_back(CNodeStat());
00405 nodeStats.back().buildFromNode(currNode, _MsPerTick);
00406 nodeStats.back().Node = currNode;
00407
00408 nodeLeft.pop_back();
00409 nodeLeft.insert(nodeLeft.end(), currNode->Sons.begin(), currNode->Sons.end());
00410
00411 }
00412
00414
00415 TNodeStatPtrVect nodeStatsPtrs(nodeStats.size());
00416 for(uint k = 0; k < nodeStats.size(); ++k)
00417 {
00418 nodeStatsPtrs[k] = &nodeStats[k];
00419 }
00420
00421
00422 if (criterion != NoSort)
00423 {
00424 CStatSorter sorter(criterion);
00425 std::sort(nodeStatsPtrs.begin(), nodeStatsPtrs.end(), sorter);
00426 }
00427
00428
00429 CStats rootStats;
00430 rootStats.buildFromNode(&_RootNode, _MsPerTick);
00431
00432
00433 std::string statsInline;
00434 std::string nodePath;
00435
00436 std::string format;
00437 if (displayInline)
00438 {
00439 if (alignPaths)
00440 {
00441 uint maxSize = 0;
00442 std::string np;
00443 for(TNodeStatPtrVect::iterator it = nodeStatsPtrs.begin(); it != nodeStatsPtrs.end(); ++it)
00444 {
00445 (*it)->Node->getPath(np);
00446 maxSize = std::max(maxSize, (uint)np.size());
00447 }
00448 format = "HTIMER: %-" + NLMISC::toString(maxSize) +"s %s";
00449 }
00450 else
00451 {
00452 format = "HTIMER: %s %s";
00453 }
00454 }
00455
00456 log->displayRawNL(format.c_str(), "", " | total | local | visits | loc%/ glb% | sessn max | min | max | mean");
00457
00458 for(TNodeStatPtrVect::iterator it = nodeStatsPtrs.begin(); it != nodeStatsPtrs.end(); ++it)
00459 {
00460 if (!displayInline)
00461 {
00462 log->displayRawNL("HTIMER: =================================");
00463 (*it)->Node->displayPath(log);
00464 (*it)->display(log, displayEx, _WantStandardDeviation);
00465 }
00466 else
00467 {
00468 (*it)->getStats(statsInline, displayEx, rootStats.TotalTime, _WantStandardDeviation);
00469 (*it)->Node->getPath(nodePath);
00470
00471 char out[2048];
00472 NLMISC::smprintf(out, 2048, format.c_str(), nodePath.c_str(), statsInline.c_str());
00473 log->displayRawNL(out);
00474 }
00475 }
00476 benchClock.stop();
00477 _CurrNode->SonsPreambule += benchClock.getNumTicks();
00478 }
00479
00480
00481 void CHTimer::displayHierarchical(CLog *log, bool displayEx ,uint labelNumChar , uint indentationStep )
00482 {
00483 CSimpleClock benchClock;
00484 benchClock.start();
00485 log->displayNL("HTIMER: =========================================================================");
00486 log->displayRawNL("HTIMER: Hierarchical display of bench");
00487 nlassert(_BenchStartedOnce);
00488 typedef std::map<CHTimer *, TNodeVect> TNodeMap;
00489 TNodeMap nodeMap;
00490 TNodeVect nodeLeft;
00491 nodeLeft.push_back(&_RootNode);
00493 while (!nodeLeft.empty())
00494 {
00495 CNode *currNode = nodeLeft.back();
00496 nodeMap[currNode->Owner].push_back(currNode);
00497 nodeLeft.pop_back();
00498 nodeLeft.insert(nodeLeft.end(), currNode->Sons.begin(), currNode->Sons.end());
00499
00500 }
00501 log->displayRawNL("HTIMER: %*s | total | local | visits | loc%%/ glb%% | sessn max | min | max | mean", labelNumChar, "");
00502
00504 CStats rootStats;
00505 rootStats.buildFromNode(&_RootNode, _MsPerTick);
00506
00508 CStats currNodeStats;
00509 std::vector<uint> sonsIndex;
00510 uint depth = 0;
00511 CHTimer *currTimer = &_RootTimer;
00512 sonsIndex.push_back(0);
00513 bool displayStat = true;
00514 std::string resultName;
00515 std::string resultStats;
00516 while (!sonsIndex.empty())
00517 {
00518 if (displayStat)
00519 {
00520 resultName.resize(labelNumChar);
00521 std::fill(resultName.begin(), resultName.end(), '.');
00522 uint startIndex = depth * indentationStep;
00523 uint endIndex = std::min(startIndex + (uint)::strlen(currTimer->_Name), labelNumChar);
00524 if ((sint) (endIndex - startIndex) >= 1)
00525 {
00526 std::copy(currTimer->_Name, currTimer->_Name + (endIndex - startIndex), resultName.begin() + startIndex);
00527 }
00528 TNodeVect &execNodes = nodeMap[currTimer];
00529 if (execNodes.size() > 0)
00530 {
00531 currNodeStats.buildFromNodes(&execNodes[0], execNodes.size(), _MsPerTick);
00532 currNodeStats.getStats(resultStats, displayEx, rootStats.TotalTime, _WantStandardDeviation);
00533 log->displayRawNL("HTIMER: %s", (resultName + resultStats).c_str());
00534 }
00535 }
00536 if (sonsIndex.back() == currTimer->_Sons.size())
00537 {
00538 sonsIndex.pop_back();
00539 currTimer = currTimer->_Parent;
00540 displayStat = false;
00541 -- depth;
00542 }
00543 else
00544 {
00545 currTimer = currTimer->_Sons[sonsIndex.back()];
00546 ++ sonsIndex.back();
00547 sonsIndex.push_back(0);
00548 displayStat = true;
00549 ++ depth;
00550 }
00551 }
00552 benchClock.stop();
00553 _CurrNode->SonsPreambule += benchClock.getNumTicks();
00554 }
00555
00556
00557
00558 void CHTimer::displayHierarchicalByExecutionPath(CLog *log, bool displayEx, uint labelNumChar, uint indentationStep)
00559 {
00560 displayHierarchicalByExecutionPathSorted(log, NoSort, displayEx, labelNumChar, indentationStep);
00561 }
00562
00563
00564
00565 void CHTimer::displayHierarchicalByExecutionPathSorted(CLog *log, TSortCriterion criterion, bool displayEx, uint labelNumChar, uint indentationStep)
00566 {
00567
00568 CSimpleClock benchClock;
00569 benchClock.start();
00570 nlassert(_BenchStartedOnce);
00571
00572
00573 CStats rootStats;
00574 rootStats.buildFromNode(&_RootNode, _MsPerTick);
00575
00576
00577
00578 CLog::TDisplayInfo dummyDspInfo;
00579 log->displayRawNL("HTIMER: =========================================================================");
00580 log->displayRawNL("HTIMER: Hierarchical display of bench by execution path");
00581 log->displayRawNL("HTIMER: %*s | total | local | visits | loc%%/ glb%% | sessn max | min | max | mean", labelNumChar, "");
00582
00583
00584
00585 std::list< CExamStackEntry > examStack;
00586
00587
00588 examStack.push_back( CExamStackEntry( &_RootNode ) );
00589 CStats currNodeStats;
00590 std::string resultName;
00591 std::string resultStats;
00592
00593 while (!examStack.empty())
00594 {
00595 CNode *node = examStack.back().Node;
00596 std::vector<CNode*> &children= examStack.back().Children;
00597 uint child = examStack.back().CurrentChild;
00598
00599
00600 if (child == 0)
00601 {
00602
00603
00604
00605
00606 children.resize(node->Sons.size());
00607
00608
00609 if(criterion == NoSort)
00610 {
00611 children= node->Sons;
00612 }
00613
00614 else
00615 {
00616 std::vector<CNodeStat> stats;
00617 std::vector<CNodeStat *> ptrStats;
00618 stats.resize(children.size());
00619 ptrStats.resize(children.size());
00620
00621
00622 uint i;
00623 for(i=0; i<children.size(); i++)
00624 {
00625 CNode *childNode= node->Sons[i];
00626 stats[i].buildFromNode(childNode, _MsPerTick);
00627 stats[i].Node = childNode;
00628 ptrStats[i]= &stats[i];
00629 }
00630
00631
00632 CStatSorter sorter;
00633 sorter.Criterion= criterion;
00634 std::sort(ptrStats.begin(), ptrStats.end(), sorter);
00635
00636
00637 for(i=0; i<children.size(); i++)
00638 {
00639 children[i]= ptrStats[i]->Node;
00640 }
00641 }
00642
00643
00644
00645
00646
00647 resultName.resize(labelNumChar);
00648 std::fill(resultName.begin(), resultName.end(), '.');
00649 uint startIndex = (examStack.size()-1) * indentationStep;
00650 uint endIndex = std::min(startIndex + (uint)::strlen(node->Owner->_Name), labelNumChar);
00651 if ((sint) (endIndex - startIndex) >= 1)
00652 {
00653 std::copy(node->Owner->_Name, node->Owner->_Name + (endIndex - startIndex), resultName.begin() + startIndex);
00654 }
00655
00656
00657 currNodeStats.buildFromNode(node, _MsPerTick);
00658 currNodeStats.getStats(resultStats, displayEx, rootStats.TotalTime, _WantStandardDeviation);
00659
00660
00661 log->displayRawNL("HTIMER: %s", (resultName + resultStats).c_str());
00662 }
00663
00664
00665 if (child >= children.size())
00666 {
00667 examStack.pop_back();
00668 continue;
00669 }
00670
00671
00672 ++(examStack.back().CurrentChild);
00673
00674
00675 examStack.push_back( CExamStackEntry( children[child] ) );
00676 }
00677
00678
00679 benchClock.stop();
00680 _CurrNode->SonsPreambule += benchClock.getNumTicks();
00681 }
00682
00683
00684 void CHTimer::displaySummary(CLog *log, TSortCriterion criterion, bool displayEx, uint labelNumChar, uint indentationStep, uint maxDepth)
00685 {
00686
00687 CSimpleClock benchClock;
00688 benchClock.start();
00689 nlassert(_BenchStartedOnce);
00690
00691
00692 CStats rootStats;
00693 rootStats.buildFromNode(&_RootNode, _MsPerTick);
00694
00695
00696
00697 CLog::TDisplayInfo dummyDspInfo;
00698 log->displayRawNL("HTIMER: =========================================================================");
00699 log->displayRawNL("HTIMER: Hierarchical display of bench by execution path");
00700 log->displayRawNL("HTIMER: %*s | total | local | visits | loc%%/ glb%% | sessn max | min | max | mean", labelNumChar, "");
00701
00702
00703
00704 std::list< CExamStackEntry > examStack;
00705
00706
00707 examStack.push_back( CExamStackEntry( &_RootNode ) );
00708 CStats currNodeStats;
00709 std::string resultName;
00710 std::string resultStats;
00711
00712 while (!examStack.empty())
00713 {
00714 CNode *node = examStack.back().Node;
00715 std::vector<CNode*> &children= examStack.back().Children;
00716 uint child = examStack.back().CurrentChild;
00717 uint depth = examStack.back().Depth;
00718
00719
00720 if (child == 0)
00721 {
00722
00723
00724
00725
00726 children.resize(node->Sons.size());
00727
00728
00729 if(criterion == NoSort)
00730 {
00731 children= node->Sons;
00732 }
00733
00734 else
00735 {
00736 std::vector<CNodeStat> stats;
00737 std::vector<CNodeStat *> ptrStats;
00738 stats.resize(children.size());
00739 ptrStats.resize(children.size());
00740
00741
00742 uint i;
00743 for(i=0; i<children.size(); i++)
00744 {
00745 CNode *childNode= node->Sons[i];
00746 stats[i].buildFromNode(childNode, _MsPerTick);
00747 stats[i].Node = childNode;
00748 ptrStats[i]= &stats[i];
00749 }
00750
00751
00752 CStatSorter sorter;
00753 sorter.Criterion= criterion;
00754 std::sort(ptrStats.begin(), ptrStats.end(), sorter);
00755
00756
00757 for(i=0; i<children.size(); i++)
00758 {
00759 children[i]= ptrStats[i]->Node;
00760 }
00761 }
00762
00763
00764
00765
00766
00767 resultName.resize(labelNumChar);
00768 std::fill(resultName.begin(), resultName.end(), '.');
00769 uint startIndex = (examStack.size()-1) * indentationStep;
00770 uint endIndex = std::min(startIndex + (uint)::strlen(node->Owner->_Name), labelNumChar);
00771 if ((sint) (endIndex - startIndex) >= 1)
00772 {
00773 std::copy(node->Owner->_Name, node->Owner->_Name + (endIndex - startIndex), resultName.begin() + startIndex);
00774 }
00775
00776
00777 currNodeStats.buildFromNode(node, _MsPerTick);
00778 currNodeStats.getStats(resultStats, displayEx, rootStats.TotalTime, _WantStandardDeviation);
00779
00780
00781 log->displayRawNL("HTIMER: %s", (resultName + resultStats).c_str());
00782 }
00783
00784
00785 if (child >= children.size())
00786 {
00787 examStack.pop_back();
00788 continue;
00789 }
00790
00791
00792 ++(examStack.back().CurrentChild);
00793
00794
00795 if (depth+1 < maxDepth)
00796 examStack.push_back( CExamStackEntry( children[child], depth+1 ) );
00797 }
00798
00799
00800 benchClock.stop();
00801 _CurrNode->SonsPreambule += benchClock.getNumTicks();
00802 }
00803
00804
00805 void CHTimer::clear()
00806 {
00807
00808 nlassert(_CurrNode == &_RootNode);
00809 _RootNode.releaseSons();
00810 _CurrNode = &_RootNode;
00811 _RootNode.reset();
00812 }
00813
00814
00815 void CHTimer::CStats::buildFromNode(CNode *node, double msPerTick)
00816 {
00817 buildFromNodes(&node, 1, msPerTick);
00818 }
00819
00820
00821 void CHTimer::CStats::buildFromNodes(CNode **nodes, uint numNodes, double msPerTick)
00822 {
00823 TotalTime = 0;
00824 TotalTimeWithoutSons = 0;
00825 NumVisits = 0;
00826
00827 uint64 minTime = (uint64) -1;
00828 uint64 maxTime = 0;
00829 uint64 sessionMaxTime = 0;
00830
00831 uint k, l;
00832 for(k = 0; k < numNodes; ++k)
00833 {
00834 TotalTime += nodes[k]->TotalTime * msPerTick;
00835 TotalTimeWithoutSons += (nodes[k]->TotalTime - nodes[k]->LastSonsTotalTime) * msPerTick;
00836 NumVisits += nodes[k]->NumVisits;
00837 minTime = std::min(minTime, nodes[k]->MinTime);
00838 maxTime = std::max(maxTime, nodes[k]->MaxTime);
00839 sessionMaxTime = std::max(sessionMaxTime, nodes[k]->SessionMax);
00840 }
00841 if (minTime == (uint64) -1)
00842 {
00843 minTime = 0;
00844 }
00845 MinTime = minTime * msPerTick;
00846 MaxTime = maxTime * msPerTick;
00847 SessionMaxTime = sessionMaxTime * msPerTick;
00848
00849 if (NumVisits > 0)
00850 MeanTime = TotalTime / NumVisits;
00851 else
00852 MeanTime = 0.0;
00853
00854
00855 double varianceSum = 0;
00856 uint numMeasures = 0;
00857 for(k = 0; k < numNodes; ++k)
00858 {
00859 numMeasures += nodes[k]->Measures.size();
00860 for(l = 0; l < nodes[k]->Measures.size(); ++l)
00861 {
00862 varianceSum += NLMISC::sqr(nodes[k]->Measures[l] - MeanTime);
00863 }
00864 }
00865 TimeStandardDeviation = numMeasures == 0 ? 0
00866 : ::sqrt(varianceSum / (numMeasures +1));
00867 }
00868
00869
00870 void CHTimer::CStats::display(CLog *log, bool displayEx, bool wantStandardDeviation )
00871 {
00872 log->displayRawNL("HTIMER: Total time = %.3f ms", (float) TotalTime);
00873 log->displayRawNL("HTIMER: Total time without sons = %.3f ms", (float) TotalTimeWithoutSons);
00874 log->displayRawNL(("HTIMER: Num visits = " + NLMISC::toString(NumVisits)).c_str());
00875 if (displayEx)
00876 {
00877 log->displayRawNL("HTIMER: Min time = %.3f ms", (float) MinTime);
00878 log->displayRawNL("HTIMER: Max time = %.3f ms", (float) MaxTime);
00879 log->displayRawNL("HTIMER: Mean time = %.3f ms", (float) MeanTime);
00880 if (wantStandardDeviation)
00881 {
00882 log->displayRawNL("HTIMER: Standard deviation = %.3f ms", (float) TimeStandardDeviation);
00883 }
00884 log->displayRawNL("HTIMER: Session Max time = %.3f ms", (float) SessionMaxTime);
00885
00886 }
00887 }
00888
00889
00890
00891 void CHTimer::CStats::getStats(std::string &dest, bool statEx, double rootTotalTime, bool wantStandardDeviation )
00892 {
00893 char buf[1024];
00894 if (!wantStandardDeviation)
00895 {
00896 if (!statEx)
00897 {
00898 NLMISC::smprintf(buf, 1024, " | %10.3f | %10.3f | %12s ", (float) TotalTime, (float) TotalTimeWithoutSons, toString(NumVisits).c_str());
00899 }
00900 else
00901 {
00902 NLMISC::smprintf(buf, 1024, " | %10.3f | %10.3f | %12s | %5.1f/%5.1f | %9.3f | %9.3f | %9.3f | %9.3f",
00903 (float) TotalTime, (float) TotalTimeWithoutSons, toString(NumVisits).c_str(),
00904 float(100*TotalTimeWithoutSons/rootTotalTime), float(100*TotalTime/rootTotalTime),
00905 (float) SessionMaxTime,
00906 (float) MinTime, (float) MaxTime, (float) MeanTime
00907 );
00908 }
00909 }
00910 else
00911 {
00912 if (!statEx)
00913 {
00914 NLMISC::smprintf(buf, 1024, " | %10.3f | %10.3f | %12s | std deviation %9.3f", (float) TotalTime, (float) TotalTimeWithoutSons, toString(NumVisits).c_str(), (float) TimeStandardDeviation);
00915 }
00916 else
00917 {
00918 NLMISC::smprintf(buf, 1024, " | %10.3f | %10.3f | %12s | %5.1f/%5.1f | %9.3f | %9.3f | %9.3f | %9.3f | std deviation %9.3f",
00919 (float) TotalTime, (float) TotalTimeWithoutSons, toString(NumVisits).c_str(),
00920 float(100*TotalTimeWithoutSons/rootTotalTime), float(100*TotalTime/rootTotalTime),
00921 (float) SessionMaxTime,
00922 (float) MinTime, (float) MaxTime, (float) MeanTime,
00923 (float) TimeStandardDeviation
00924 );
00925 }
00926 }
00927 dest = buf;
00928 }
00929
00930
00931
00932 bool CHTimer::CStatSorter::operator()(const CHTimer::CStats *lhs, const CHTimer::CStats *rhs)
00933 {
00934 switch(Criterion)
00935 {
00936 case CHTimer::TotalTime: return lhs->TotalTime >= rhs->TotalTime;
00937 case CHTimer::TotalTimeWithoutSons: return lhs->TotalTimeWithoutSons >= rhs->TotalTimeWithoutSons;
00938 case CHTimer::MeanTime: return lhs->MeanTime >= rhs->MeanTime;
00939 case CHTimer::NumVisits: return lhs->NumVisits >= rhs->NumVisits;
00940 case CHTimer::MaxTime: return lhs->MaxTime >= rhs->MaxTime;
00941 case CHTimer::MinTime: return lhs->MinTime < rhs->MinTime;
00942 case CHTimer::MaxSession: return lhs->SessionMaxTime > rhs->SessionMaxTime;
00943 default:
00944 nlassert(0);
00945 break;
00946 }
00947 return false;
00948 }
00949
00950
00951
00952 void CHTimer::doBefore()
00953 {
00954 _PreambuleClock.start();
00955 walkTreeToCurrent();
00956 ++ _CurrNode->NumVisits;
00957 _CurrNode->SonsPreambule = 0;
00958 if (!_Parent && _CurrTimer != this)
00959 {
00960 _Parent = _CurrTimer;
00961
00962 _Parent->_Sons.push_back(this);
00963 }
00964 _CurrTimer = this;
00965 _PreambuleClock.stop();
00966 if (_CurrNode->Parent)
00967 {
00968 _CurrNode->Parent->SonsPreambule += _PreambuleClock.getNumTicks();
00969 }
00970 _CurrNode->Clock.start();
00971 }
00972
00973
00974 void CHTimer::doAfter(bool displayAfter)
00975 {
00976 _CurrNode->Clock.stop();
00977 _PreambuleClock.start();
00978
00979
00980
00981 sint64 numTicks = _CurrNode->Clock.getNumTicks() - _CurrNode->SonsPreambule - (CSimpleClock::getStartStopNumTicks());
00982
00983 numTicks= std::max((sint64)0, numTicks);
00984
00985 if(_CurrNode->TotalTime + numTicks < _CurrNode->SonsTotalTime)
00986 numTicks= _CurrNode->SonsTotalTime - _CurrNode->TotalTime;
00987
00988 _CurrNode->TotalTime += numTicks;
00989 _CurrNode->MinTime = std::min(_CurrNode->MinTime, (uint64)numTicks);
00990 _CurrNode->MaxTime = std::max(_CurrNode->MaxTime, (uint64)numTicks);
00991 _CurrNode->LastSonsTotalTime = _CurrNode->SonsTotalTime;
00992
00993 _CurrNode->SessionCurrent += (uint64)numTicks;
00994
00995 if (displayAfter)
00996 {
00997 nlinfo("HTIMER: %s %.3fms loop number %d", _Name, numTicks * _MsPerTick, _CurrNode->NumVisits);
00998 }
00999
01000 if (_WantStandardDeviation)
01001 {
01002 _CurrNode->Measures.push_back(numTicks * _MsPerTick);
01003 }
01004
01005 if (_Parent)
01006 {
01007 _CurrTimer = _Parent;
01008 }
01009
01010 if (_CurrNode->Parent)
01011 {
01012 CNode *curNode= _CurrNode;
01013 CNode *parent= _CurrNode->Parent;
01014 parent->SonsTotalTime += numTicks;
01015 _PreambuleClock.stop();
01016
01017
01018
01019
01020
01021
01022
01023
01024 parent->SonsPreambule += _PreambuleClock.getNumTicks() + curNode->SonsPreambule + _AfterStopEstimateTime;
01025
01026 _CurrNode= parent;
01027 }
01028 else
01029 {
01030 _PreambuleClock.stop();
01031 }
01032 }
01033
01034
01035
01036
01037
01038
01039
01040 void CHTimer::clearSessionCurrent()
01041 {
01042 _RootNode.resetSessionCurrent();
01043 }
01044
01045
01046
01047
01048 void CHTimer::clearSessionStats()
01049 {
01050 _RootNode.resetSessionStats();
01051 }
01052
01053
01054
01055
01056 void CHTimer::updateSessionStats()
01057 {
01058 if (_RootNode.SessionCurrent > _RootNode.SessionMax)
01059 _RootNode.spreadSession();
01060 }
01061
01062
01063
01064
01065
01066
01067
01068
01069 #define CASE_DISPLAYMEASURES(crit, alternative) \
01070 if (args[0] == #crit || depth == alternative) \
01071 { \
01072 CHTimer::TSortCriterion criterion = CHTimer::crit; \
01073 if (hasDepth && depth != alternative) \
01074 CHTimer::displaySummary(&log, criterion, true, 64, 2, depth); \
01075 else \
01076 CHTimer::display(&log, criterion); \
01077 } \
01078 else
01079
01080 NLMISC_CATEGORISED_COMMAND(nel,displayMeasures, "display hierarchical timer", "[TotalTime(=-2)|NoSort(=-3)|TotalTimeWithoutSons(=-4)|MeanTime(=-5)|NumVisits(=-6)|MaxTime(=-7)|MinTime(=-8)|MaxSession(=-9)] [depth]")
01081 {
01082 if (args.size() < 1)
01083 {
01084 CHTimer::display(&log);
01085 CHTimer::displayHierarchicalByExecutionPathSorted (&log, CHTimer::TotalTime, true, 64);
01086 return true;
01087 }
01088
01089 sint depth = 0;
01090 bool hasDepth = (sscanf(args[0].c_str(), "%d", &depth) == 1 || (args.size() > 1 && sscanf(args[1].c_str(), "%d", &depth) == 1));
01091
01092 CASE_DISPLAYMEASURES(NoSort, -3)
01093 CASE_DISPLAYMEASURES(TotalTime, -2)
01094 CASE_DISPLAYMEASURES(TotalTimeWithoutSons, -4)
01095 CASE_DISPLAYMEASURES(MeanTime, -5)
01096 CASE_DISPLAYMEASURES(NumVisits, -6)
01097 CASE_DISPLAYMEASURES(MaxTime, -7)
01098 CASE_DISPLAYMEASURES(MinTime, -8)
01099 CASE_DISPLAYMEASURES(MaxSession, -9)
01100 {
01101 if (hasDepth)
01102 CHTimer::displaySummary(&log, CHTimer::TotalTime, true, 64, 2, depth);
01103 else
01104 CHTimer::display(&log, CHTimer::TotalTime);
01105 }
01106
01107 return true;
01108 }
01109
01110 }
01111