quickprof.h

Go to the documentation of this file.
00001 /************************************************************************
00002 * QuickProf                                                             *
00003 * http://quickprof.sourceforge.net                                      *
00004 * Copyright (C) 2006-2008                                               *
00005 * Tyler Streeter (http://www.tylerstreeter.net)                         *
00006 *                                                                       *
00007 * This library is free software; you can redistribute it and/or         *
00008 * modify it under the terms of EITHER:                                  *
00009 *   (1) The GNU Lesser General Public License as published by the Free  *
00010 *       Software Foundation; either version 2.1 of the License, or (at  *
00011 *       your option) any later version. The text of the GNU Lesser      *
00012 *       General Public License is included with this library in the     *
00013 *       file license-LGPL.txt.                                          *
00014 *   (2) The BSD-style license that is included with this library in     *
00015 *       the file license-BSD.txt.                                       *
00016 *   (3) The zlib/libpng license that is included with this library in   *
00017 *       the file license-zlib-libpng.txt.                               *
00018 *                                                                       *
00019 * This library is distributed in the hope that it will be useful,       *
00020 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00021 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files    *
00022 * license-LGPL.txt, license-BSD.txt, and license-zlib-libpng.txt for    *
00023 * more details.                                                         *
00024 ************************************************************************/
00025 
00026 // Please visit the project website (http://quickprof.sourceforge.net) 
00027 // for usage instructions.
00028 
00029 #ifndef QUICK_PROF_H
00030 #define QUICK_PROF_H
00031 
00032 #include <iostream>
00033 #include <fstream>
00034 #include <sstream>
00035 #include <map>
00036 #include <cmath>
00037 
00038 #if defined(WIN32) || defined(_WIN32)
00039         #define USE_WINDOWS_TIMERS
00040         #include <windows.h>
00041         #include <time.h>
00042 #else
00043         #include <sys/time.h>
00044 #endif
00045 
00046 /// Use this macro to access the profiler singleton.  For example: 
00047 /// PROFILER.init();
00048 /// ...
00049 /// PROFILER.beginBlock("foo");
00050 /// foo();
00051 /// PROFILER.endBlock("foo");
00052 #define PROFILER quickprof::Profiler::instance()
00053 
00054 /// The main namespace that contains everything.
00055 namespace quickprof
00056 {
00057         /// A simple data structure representing a single timed block 
00058         /// of code.
00059         struct ProfileBlock
00060         {
00061                 ProfileBlock()
00062                 {
00063                         currentBlockStartMicroseconds = 0;
00064                         currentCycleTotalMicroseconds = 0;
00065                         avgCycleTotalMicroseconds = 0;
00066                         totalMicroseconds = 0;
00067                 }
00068 
00069                 /// The starting time (in us) of the current block update.
00070                 unsigned long long int currentBlockStartMicroseconds;
00071 
00072                 /// The accumulated time (in us) spent in this block during the 
00073                 /// current profiling cycle.
00074                 unsigned long long int currentCycleTotalMicroseconds;
00075 
00076                 /// The accumulated time (in us) spent in this block during the 
00077                 /// past profiling cycle.
00078                 double avgCycleTotalMicroseconds;
00079 
00080                 /// The total accumulated time (in us) spent in this block.
00081                 unsigned long long int totalMicroseconds;
00082         };
00083 
00084         /// A cross-platform clock class inspired by the Timer classes in 
00085         /// Ogre (http://www.ogre3d.org).
00086         class Clock
00087         {
00088         public:
00089                 Clock()
00090                 {
00091 #ifdef USE_WINDOWS_TIMERS
00092                         QueryPerformanceFrequency(&mClockFrequency);
00093 #endif
00094                         reset();
00095                 }
00096 
00097                 ~Clock()
00098                 {
00099                 }
00100 
00101                 /**
00102                 Resets the initial reference time.
00103                 */
00104                 void reset()
00105                 {
00106 #ifdef USE_WINDOWS_TIMERS
00107                         QueryPerformanceCounter(&mStartTime);
00108                         mStartTick = GetTickCount();
00109                         mPrevClockCycles = 0;
00110 #else
00111                         gettimeofday(&mStartTime, NULL);
00112 #endif
00113                 }
00114 
00115                 /**
00116                 Returns the time in us since the last call to reset or since 
00117                 the Clock was created.
00118 
00119                 @return The requested time in microseconds.  Assuming 64-bit 
00120                 integers are available, the return value is valid for 2^63 
00121                 clock cycles (over 104 years w/ clock frequency 2.8 GHz).
00122                 */
00123                 unsigned long long int getTimeMicroseconds()
00124                 {
00125 #ifdef USE_WINDOWS_TIMERS
00126                         // Compute the number of elapsed clock cycles since the 
00127                         // clock was created/reset.  Using 64-bit signed ints, this 
00128                         // is valid for 2^63 clock cycles (over 104 years w/ clock 
00129                         // frequency 2.8 GHz).
00130                         LARGE_INTEGER currentTime;
00131                         QueryPerformanceCounter(&currentTime);
00132                         LONGLONG clockCycles = currentTime.QuadPart - 
00133                                 mStartTime.QuadPart;
00134 
00135                         // Compute the total elapsed seconds.  This is valid for 2^63 
00136                         // clock cycles (over 104 years w/ clock frequency 2.8 GHz).
00137                         LONGLONG sec = clockCycles / mClockFrequency.QuadPart;
00138 
00139                         // Check for unexpected leaps in the Win32 performance counter.  
00140                         // (This is caused by unexpected data across the PCI to ISA 
00141                         // bridge, aka south bridge.  See Microsoft KB274323.)  Avoid 
00142                         // the problem with GetTickCount() wrapping to zero after 47 
00143                         // days (because it uses 32-bit unsigned ints to represent 
00144                         // milliseconds).
00145                         LONGLONG msec1 = sec * 1000 + (clockCycles - sec * 
00146                                 mClockFrequency.QuadPart) * 1000 / mClockFrequency.QuadPart;
00147                         DWORD tickCount = GetTickCount();
00148                         if (tickCount < mStartTick)
00149                         {
00150                                 mStartTick = tickCount;
00151                         }
00152                         LONGLONG msec2 = (LONGLONG)(tickCount - mStartTick);
00153                         LONGLONG msecDiff = msec1 - msec2;
00154                         if (msecDiff < -100 || msecDiff > 100)
00155                         {
00156                                 // Adjust the starting time forwards.
00157                                 LONGLONG adjustment = (std::min)(msecDiff * 
00158                                         mClockFrequency.QuadPart / 1000, clockCycles - 
00159                                         mPrevClockCycles);
00160                                 mStartTime.QuadPart += adjustment;
00161                                 clockCycles -= adjustment;
00162 
00163                                 // Update the measured seconds with the adjustments.
00164                                 sec = clockCycles / mClockFrequency.QuadPart;
00165                         }
00166 
00167                         // Compute the milliseconds part.  This is always valid since 
00168                         // it will never be greater than 1000000.
00169                         LONGLONG usec = (clockCycles - sec * mClockFrequency.QuadPart) * 
00170                                 1000000 / mClockFrequency.QuadPart;
00171 
00172                         // Store the current elapsed clock cycles for adjustments next 
00173                         // time.
00174                         mPrevClockCycles = clockCycles;
00175 
00176                         // The return value here is valid for 2^63 clock cycles (over 
00177                         // 104 years w/ clock frequency 2.8 GHz).
00178                         return sec * 1000000 + usec;
00179 #else
00180                         // Assuming signed 32-bit integers for tv_sec and tv_usec, and 
00181                         // casting the seconds difference to a 64-bit unsigned long long 
00182                         // int, the return value here is valid for over 136 years.
00183                         struct timeval currentTime;
00184                         gettimeofday(&currentTime, NULL);
00185                         return (unsigned long long int)(currentTime.tv_sec - 
00186                                 mStartTime.tv_sec) * 1000000 + (currentTime.tv_usec - 
00187                                 mStartTime.tv_usec);
00188 #endif
00189                 }
00190 
00191         private:
00192 #ifdef USE_WINDOWS_TIMERS
00193                 LARGE_INTEGER mClockFrequency;
00194                 DWORD mStartTick;
00195                 LONGLONG mPrevClockCycles;
00196                 LARGE_INTEGER mStartTime;
00197 #else
00198                 struct timeval mStartTime;
00199 #endif
00200         };
00201 
00202         /// A set of ways to represent timing results.
00203         enum TimeFormat
00204         {
00205                 SECONDS,
00206                 MILLISECONDS,
00207                 MICROSECONDS,
00208                 PERCENT
00209         };
00210 
00211         /// A singleton class that manages timing for a set of profiling blocks.
00212         class Profiler
00213         {
00214         public:
00215                 /**
00216                 Useful for creating multiple Profiler instances.
00217 
00218                 Normally the Profiler class should be accessed only through the 
00219                 singleton instance method, which provides global access to a single 
00220                 static Profiler instance.  However, it is also possible to create 
00221                 several local Profiler instances, if necessary.
00222                 */
00223                 inline Profiler();
00224 
00225                 inline ~Profiler();
00226 
00227                 /**
00228                 Accesses the singleton instance.
00229 
00230                 @return The Profiler instance.
00231                 */
00232                 inline static Profiler& instance();
00233 
00234                 /**
00235                 Initializes the profiler. 
00236 
00237                 This must be called first.  If this is never called, the profiler 
00238                 is effectively disabled, and all other functions will return 
00239                 immediately.  This can be called more than once to re-initialize the 
00240                 profiler, which erases all previous profiling block names and their 
00241                 timing data.
00242 
00243                 @param smoothing      The measured duration for each profile 
00244                               block can be averaged across multiple 
00245                               cycles, and this parameter defines the 
00246                               smoothness of this averaging process.
00247                               The higher the value, the smoother the 
00248                               resulting average durations will appear.  
00249                               Leaving it at zero will essentially 
00250                               disable the smoothing effect.  More 
00251                               specifically, this parameter is a time 
00252                               constant (defined in terms of cycles) that 
00253                               defines an exponentially-weighted moving 
00254                               average.  For example, a value of 4.0 
00255                               means the past four cycles will contribute 
00256                               63% of the current weighted average.  This 
00257                               value must be >= 0.
00258                 @param outputFilename If defined, enables timing data to be 
00259                               printed to a data file for later analysis.
00260                 @param printPeriod    Defines how often data is printed to the 
00261                               file, in number of profiling cycles.  For 
00262                               example, set this to 1 if you want data 
00263                               printed after each cycle, or 5 if you want 
00264                               it printed every 5 cycles.  It is a good 
00265                               idea to increase this if you don't want 
00266                               huge data files.  Keep in mind, however, 
00267                               that when you increase this, you might 
00268                               want to increase the smoothing 
00269                               parameter.  (A good heuristic is to set 
00270                               the smoothing parameter equal to the 
00271                               print period.)  This value must be >= 1.
00272                 @param printFormat    Defines the format used when printing data 
00273                               to a file.
00274                 */
00275                 inline void init(double smoothing=0.0, 
00276                         const std::string outputFilename="", size_t printPeriod=1,
00277                         TimeFormat printFormat=MILLISECONDS);
00278 
00279                 /**
00280                 Begins timing the named block of code.
00281 
00282                 @param name The name of the block.
00283                 */
00284                 inline void beginBlock(const std::string& name);
00285 
00286                 /**
00287                 Defines the end of the named timing block.
00288 
00289                 @param name The name of the block.
00290                 */
00291                 inline void endBlock(const std::string& name);
00292 
00293                 /**
00294                 Defines the end of a profiling cycle. 
00295 
00296                 Use this regularly by calling it at the end of all timing blocks.  
00297                 This is necessary for smoothing and for file output, but not if 
00298                 you just want a total summary at the end of execution (i.e. from 
00299                 getSummary).  This must not be called within a timing block.
00300                 */
00301                 inline void endCycle();
00302 
00303                 /**
00304                 Returns the average time used in the named block per profiling cycle.
00305                 
00306                 If smoothing is disabled (see init), this returns the most recent 
00307                 duration measurement.
00308 
00309                 @param name   The name of the block.
00310                 @param format The desired time format to use for the result.
00311                 @return       The block's average duration per cycle.
00312                 */
00313                 inline double getAvgDuration(const std::string& name, 
00314                         TimeFormat format)const;
00315 
00316                 /**
00317                 Returns the total time spent in the named block since the profiler was 
00318                 initialized.
00319 
00320                 @param name   The name of the block.
00321                 @param format The desired time format to use for the result.
00322                 @return       The block total time.
00323                 */
00324                 inline double getTotalDuration(const std::string& name, 
00325                         TimeFormat format);
00326 
00327                 /**
00328                 Computes the elapsed time since the profiler was initialized.
00329 
00330                 @param format The desired time format to use for the result.
00331                 @return The elapsed time.
00332                 */
00333                 inline double getTimeSinceInit(TimeFormat format);
00334 
00335                 /**
00336                 Returns a summary of total times in each block.
00337 
00338                 @param format The desired time format to use for the results.
00339                 @return       The timing summary as a string.
00340                 */
00341                 inline std::string getSummary(TimeFormat format=PERCENT);
00342 
00343         private:
00344                 /**
00345                 Returns everything to its initial state.
00346 
00347                 Deallocates memory, closes output files, and resets all variables.  
00348                 This is called when the profiler is re-initialized and when the 
00349                 process exits.
00350                 */
00351                 inline void destroy();
00352 
00353                 /**
00354                 Prints an error message to standard output.
00355 
00356                 @param msg The string to print.
00357                 */
00358                 inline void printError(const std::string& msg)const;
00359 
00360                 /**
00361                 Returns a named profile block.
00362 
00363                 @param name The name of the block to return.
00364                 @return     The named ProfileBlock, or NULL if it can't be found.
00365                 */
00366                 inline ProfileBlock* getProfileBlock(const std::string& name)const;
00367 
00368                 /**
00369                 Returns the appropriate suffix string for the given time format.
00370 
00371                 @return The suffix string.
00372                 */
00373                 inline std::string getSuffixString(TimeFormat format)const;
00374 
00375                 /// Determines whether the profiler is enabled.
00376                 bool mEnabled;
00377 
00378                 /// The clock used to time profile blocks.
00379                 Clock mClock;
00380 
00381                 /// The starting time (in us) of the current profiling cycle.
00382                 unsigned long long int mCurrentCycleStartMicroseconds;
00383 
00384                 /// The average profiling cycle duration (in us).  If smoothing is 
00385                 /// disabled, this is the same as the duration of the most recent 
00386                 /// cycle.
00387                 double mAvgCycleDurationMicroseconds;
00388 
00389                 /// Internal map of named profile blocks.
00390                 std::map<std::string, ProfileBlock*> mProfileBlocks;
00391 
00392                 /// The data output file used if this feature is enabled in init.
00393                 std::ofstream mOutputFile;
00394 
00395                 /// Tracks whether we have begun printing data to the output file.
00396                 bool mFirstFileOutput;
00397 
00398                 /// A pre-computed scalar used to update exponentially-weighted moving 
00399                 /// averages.
00400                 double mMovingAvgScalar;
00401 
00402                 /// Determines how often (in number of profiling cycles) timing data 
00403                 /// is printed to the output file.
00404                 size_t mPrintPeriod;
00405 
00406                 /// The time format used when printing timing data to the output file.
00407                 TimeFormat mPrintFormat;
00408 
00409                 /// Keeps track of how many cycles have elapsed (for printing).
00410                 size_t mCycleCounter;
00411 
00412                 /// Used to update the initial average cycle times.
00413                 bool mFirstCycle;
00414         };
00415 
00416         Profiler::Profiler()
00417         {
00418                 mEnabled = false;
00419                 mCurrentCycleStartMicroseconds = 0;
00420                 mAvgCycleDurationMicroseconds = 0;
00421                 mFirstFileOutput = true;
00422                 mMovingAvgScalar = 0;
00423                 mPrintPeriod = 1;
00424                 mPrintFormat = SECONDS;
00425                 mCycleCounter = 0;
00426                 mFirstCycle = true;
00427         }
00428 
00429         Profiler::~Profiler()
00430         {
00431                 // This is called when the program exits because the singleton 
00432                 // instance is static.
00433 
00434                 destroy();
00435         }
00436 
00437         Profiler& Profiler::instance()
00438         {
00439                 static Profiler self;
00440                 return self;
00441         }
00442 
00443         void Profiler::destroy()
00444         {
00445                 mEnabled = false;
00446                 mClock.reset();
00447                 mCurrentCycleStartMicroseconds = 0;
00448                 mAvgCycleDurationMicroseconds = 0;
00449                 while (!mProfileBlocks.empty())
00450                 {
00451                         delete (*mProfileBlocks.begin()).second;
00452                         mProfileBlocks.erase(mProfileBlocks.begin());
00453                 }
00454                 if (mOutputFile.is_open())
00455                 {
00456                         mOutputFile.close();
00457                 }
00458                 mFirstFileOutput = true;
00459                 mMovingAvgScalar = 0;
00460                 mPrintPeriod = 1;
00461                 mPrintFormat = SECONDS;
00462                 mCycleCounter = 0;
00463                 mFirstCycle = true;
00464         }
00465 
00466         void Profiler::init(double smoothing, const std::string outputFilename, 
00467                 size_t printPeriod, TimeFormat printFormat)
00468         {
00469                 if (mEnabled)
00470                 {
00471                         // Reset everything to its initial state and re-initialize.
00472                         destroy();
00473                         std::cout << "[QuickProf] Re-initializing profiler, " 
00474                                 << "erasing all profiling blocks" << std::endl;
00475                 }
00476 
00477                 mEnabled = true;
00478 
00479                 if (smoothing <= 0)
00480                 {
00481                         if (smoothing < 0)
00482                         {
00483                                 printError("Smoothing parameter must be >= 0. Using 0.");
00484                         }
00485 
00486                         mMovingAvgScalar = 0;
00487                 }
00488                 else
00489                 {
00490                         // Treat smoothing as a time constant.
00491                         mMovingAvgScalar = ::exp(-1 / smoothing);
00492                 }
00493 
00494                 if (!outputFilename.empty())
00495                 {
00496                         mOutputFile.open(outputFilename.c_str());
00497                 }
00498 
00499                 if (printPeriod < 1)
00500                 {
00501                         printError("Print period must be >= 1. Using 1.");
00502                         mPrintPeriod = 1;
00503                 }
00504                 else
00505                 {
00506                         mPrintPeriod = printPeriod;
00507                 }
00508                 mPrintFormat = printFormat;
00509 
00510                 mClock.reset();
00511 
00512                 // Set the start time for the first cycle.
00513                 mCurrentCycleStartMicroseconds = mClock.getTimeMicroseconds();
00514         }
00515 
00516         void Profiler::beginBlock(const std::string& name)
00517         {
00518                 if (!mEnabled)
00519                 {
00520                         return;
00521                 }
00522 
00523                 if (name.empty())
00524                 {
00525                         printError("Cannot allow unnamed profile blocks.");
00526                         return;
00527                 }
00528 
00529                 ProfileBlock* block = NULL;
00530 
00531                 std::map<std::string, ProfileBlock*>::iterator iter = 
00532                         mProfileBlocks.find(name);
00533                 if (mProfileBlocks.end() == iter)
00534                 {
00535                         // The named block does not exist.  Create a new ProfileBlock.
00536                         block = new ProfileBlock();
00537                         mProfileBlocks[name] = block;
00538                 }
00539                 else
00540                 {
00541                         block = iter->second;
00542                 }
00543 
00544                 // We do this at the end to get more accurate results.
00545                 block->currentBlockStartMicroseconds = mClock.getTimeMicroseconds();
00546         }
00547 
00548         void Profiler::endBlock(const std::string& name)
00549         {
00550                 if (!mEnabled)
00551                 {
00552                         return;
00553                 }
00554 
00555                 // We do this at the beginning to get more accurate results.
00556                 unsigned long long int endTick = mClock.getTimeMicroseconds();
00557 
00558                 ProfileBlock* block = getProfileBlock(name);
00559                 if (!block)
00560                 {
00561                         return;
00562                 }
00563 
00564                 unsigned long long int blockDuration = endTick - 
00565                         block->currentBlockStartMicroseconds;
00566                 block->currentCycleTotalMicroseconds += blockDuration;
00567                 block->totalMicroseconds += blockDuration;
00568         }
00569 
00570         void Profiler::endCycle()
00571         {
00572                 if (!mEnabled)
00573                 {
00574                         return;
00575                 }
00576 
00577                 // Update the average total cycle time.
00578                 // On the first cycle we set the average cycle time equal to the 
00579                 // measured cycle time.  This avoids having to ramp up the average 
00580                 // from zero initially.
00581                 unsigned long long int currentCycleDurationMicroseconds = 
00582                         mClock.getTimeMicroseconds() - mCurrentCycleStartMicroseconds;
00583                 if (mFirstCycle)
00584                 {
00585                         mAvgCycleDurationMicroseconds = 
00586                                 (double)currentCycleDurationMicroseconds;
00587                 }
00588                 else
00589                 {
00590                         mAvgCycleDurationMicroseconds = mMovingAvgScalar * 
00591                                 mAvgCycleDurationMicroseconds + (1 - mMovingAvgScalar) 
00592                                 * (double)currentCycleDurationMicroseconds;
00593                 }
00594 
00595                 // Update the average cycle time for each block.
00596                 std::map<std::string, ProfileBlock*>::iterator blocksBegin = 
00597                         mProfileBlocks.begin();
00598                 std::map<std::string, ProfileBlock*>::iterator blocksEnd = 
00599                         mProfileBlocks.end();
00600                 std::map<std::string, ProfileBlock*>::iterator iter = blocksBegin;
00601                 for (; iter != blocksEnd; ++iter)
00602                 {
00603                         ProfileBlock* block = iter->second;
00604 
00605                         // On the first cycle we set the average cycle time equal to the 
00606                         // measured cycle time.  This avoids having to ramp up the average 
00607                         // from zero initially.
00608                         if (mFirstCycle)
00609                         {
00610                                 block->avgCycleTotalMicroseconds = 
00611                                         (double)block->currentCycleTotalMicroseconds;
00612                         }
00613                         else
00614                         {
00615                                 block->avgCycleTotalMicroseconds = mMovingAvgScalar * 
00616                                         block->avgCycleTotalMicroseconds + (1 - mMovingAvgScalar) * 
00617                                         (double)block->currentCycleTotalMicroseconds;
00618                         }
00619 
00620                         block->currentCycleTotalMicroseconds = 0;
00621                 }
00622 
00623                 if (mFirstCycle)
00624                 {
00625                         mFirstCycle = false;
00626                 }
00627 
00628                 // If enough cycles have passed, print data to the output file.
00629                 if (mOutputFile.is_open() && mCycleCounter % mPrintPeriod == 0)
00630                 {
00631                         mCycleCounter = 0;
00632 
00633                         if (mFirstFileOutput)
00634                         {
00635                                 // On the first iteration, print a header line that shows the 
00636                                 // names of each data column (i.e. profiling block names).
00637                                 mOutputFile << "# t(s)";
00638 
00639                                 std::string suffix = getSuffixString(mPrintFormat);
00640                                 for (iter = blocksBegin; iter != blocksEnd; ++iter)
00641                                 {
00642                                         mOutputFile  << " " << (*iter).first << "(" << suffix << ")";
00643                                 }
00644 
00645                                 mOutputFile << std::endl;
00646                                 mFirstFileOutput = false;
00647                         }
00648 
00649                         mOutputFile << getTimeSinceInit(SECONDS) * (double)0.000001;
00650 
00651                         // Print the cycle time for each block.
00652                         for (iter = blocksBegin; iter != blocksEnd; ++iter)
00653                         {
00654                                 mOutputFile << " " << getAvgDuration((*iter).first, 
00655                                         mPrintFormat);
00656                         }
00657 
00658                         mOutputFile << std::endl;
00659                 }
00660 
00661                 ++mCycleCounter;
00662                 mCurrentCycleStartMicroseconds = mClock.getTimeMicroseconds();
00663         }
00664 
00665         double Profiler::getAvgDuration(const std::string& name, 
00666                 TimeFormat format)const
00667         {
00668                 if (!mEnabled)
00669                 {
00670                         return 0;
00671                 }
00672 
00673                 ProfileBlock* block = getProfileBlock(name);
00674                 if (!block)
00675                 {
00676                         return 0;
00677                 }
00678 
00679                 double result = 0;
00680 
00681                 switch(format)
00682                 {
00683                         case SECONDS:
00684                                 result = block->avgCycleTotalMicroseconds * (double)0.000001;
00685                                 break;
00686                         case MILLISECONDS:
00687                                 result = block->avgCycleTotalMicroseconds * (double)0.001;
00688                                 break;
00689                         case MICROSECONDS:
00690                                 result = block->avgCycleTotalMicroseconds;
00691                                 break;
00692                         case PERCENT:
00693                         {
00694                                 if (0 == mAvgCycleDurationMicroseconds)
00695                                 {
00696                                         result = 0;
00697                                 }
00698                                 else
00699                                 {
00700                                         result = 100.0 * block->avgCycleTotalMicroseconds / 
00701                                                 mAvgCycleDurationMicroseconds;
00702                                 }
00703                                 break;
00704                         }
00705                         default:
00706                                 break;
00707                 }
00708 
00709                 return result;
00710         }
00711 
00712         double Profiler::getTotalDuration(const std::string& name, 
00713                 TimeFormat format)
00714         {
00715                 if (!mEnabled)
00716                 {
00717                         return 0;
00718                 }
00719 
00720                 ProfileBlock* block = getProfileBlock(name);
00721                 if (!block)
00722                 {
00723                         return 0;
00724                 }
00725 
00726                 double blockTotalMicroseconds = (double)block->totalMicroseconds;
00727                 double result = 0;
00728 
00729                 switch(format)
00730                 {
00731                         case SECONDS:
00732                                 result = blockTotalMicroseconds * (double)0.000001;
00733                                 break;
00734                         case MILLISECONDS:
00735                                 result = blockTotalMicroseconds * (double)0.001;
00736                                 break;
00737                         case MICROSECONDS:
00738                                 result = blockTotalMicroseconds;
00739                                 break;
00740                         case PERCENT:
00741                                 {
00742                                         double microsecondsSinceInit = getTimeSinceInit(MICROSECONDS);
00743                                         if (0 == microsecondsSinceInit)
00744                                         {
00745                                                 result = 0;
00746                                         }
00747                                         else
00748                                         {
00749                                                 result = 100.0 * blockTotalMicroseconds / 
00750                                                         microsecondsSinceInit;
00751                                         }
00752                                 }
00753                                 break;
00754                         default:
00755                                 break;
00756                 }
00757 
00758                 return result;
00759         }
00760 
00761         double Profiler::getTimeSinceInit(TimeFormat format)
00762         {
00763                 double timeSinceInit = 0;
00764 
00765                 switch(format)
00766                 {
00767                         case SECONDS:
00768                                 timeSinceInit = (double)mClock.getTimeMicroseconds() * (double)0.000001;
00769                                 break;
00770                         case MILLISECONDS:
00771                                 timeSinceInit = (double)mClock.getTimeMicroseconds() * (double)0.001;
00772                                 break;
00773                         case MICROSECONDS:
00774                                 timeSinceInit = (double)mClock.getTimeMicroseconds();
00775                                 break;
00776                         case PERCENT:
00777                         {
00778                                 timeSinceInit = 100;
00779                                 break;
00780                         }
00781                         default:
00782                                 break;
00783                 }
00784 
00785                 if (timeSinceInit < 0)
00786                 {
00787                         timeSinceInit = 0;
00788                 }
00789 
00790                 return timeSinceInit;
00791         }
00792 
00793         std::string Profiler::getSummary(TimeFormat format)
00794         {
00795                 if (!mEnabled)
00796                 {
00797                         return "";
00798                 }
00799 
00800                 std::ostringstream oss;
00801                 std::string suffix = getSuffixString(format);
00802 
00803                 std::map<std::string, ProfileBlock*>::iterator blocksBegin = 
00804                         mProfileBlocks.begin();
00805                 std::map<std::string, ProfileBlock*>::iterator blocksEnd = 
00806                         mProfileBlocks.end();
00807                 std::map<std::string, ProfileBlock*>::iterator iter = blocksBegin;
00808                 for (; iter != blocksEnd; ++iter)
00809                 {
00810                         if (iter != blocksBegin)
00811                         {
00812                                 oss << "\n";
00813                         }
00814 
00815                         oss << iter->first;
00816                         oss << ": ";
00817                         oss << getTotalDuration(iter->first, format);
00818                         oss << " ";
00819                         oss << suffix;
00820                 }
00821 
00822                 return oss.str();
00823         }
00824 
00825         void Profiler::printError(const std::string& msg)const
00826         {
00827                 std::cout << "[QuickProf error] " << msg << std::endl;
00828         }
00829 
00830         ProfileBlock* Profiler::getProfileBlock(const std::string& name)const
00831         {
00832                 std::map<std::string, ProfileBlock*>::const_iterator iter = 
00833                         mProfileBlocks.find(name);
00834                 if (mProfileBlocks.end() == iter)
00835                 {
00836                         // The named block does not exist.  Print an error.
00837                         printError("The profile block named '" + name + 
00838                                 "' does not exist.");
00839                         return NULL;
00840                 }
00841                 else
00842                 {
00843                         return iter->second;
00844                 }
00845         }
00846 
00847         std::string Profiler::getSuffixString(TimeFormat format)const
00848         {
00849                 std::string suffix;
00850                 switch(format)
00851                 {
00852                         case SECONDS:
00853                                 suffix = "s";
00854                                 break;
00855                         case MILLISECONDS:
00856                                 suffix = "ms";
00857                                 break;
00858                         case MICROSECONDS:
00859                                 suffix = "us";
00860                                 break;
00861                         case PERCENT:
00862                         {
00863                                 suffix = "%";
00864                                 break;
00865                         }
00866                         default:
00867                                 break;
00868                 }
00869 
00870                 return suffix;
00871         }
00872 };
00873 
00874 #endif

Generated on Fri Oct 30 16:29:01 2009 for Robot Simulator of the Robotics Group for Self-Organization of Control by  doxygen 1.4.7