Robot Simulator of the Robotics Group for Self-Organization of Control: quickprof.h Source File

# 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