perf.h

Go to the documentation of this file.
00001 /*
00002  * perf.h
00003  *
00004  * Copyright (C) 2006,2007,2010  Thomas A. Vaughan
00005  * All rights reserved.
00006  *
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions are met:
00010  *     * Redistributions of source code must retain the above copyright
00011  *       notice, this list of conditions and the following disclaimer.
00012  *     * Redistributions in binary form must reproduce the above copyright
00013  *       notice, this list of conditions and the following disclaimer in the
00014  *       documentation and/or other materials provided with the distribution.
00015  *     * Neither the name of the <organization> nor the
00016  *       names of its contributors may be used to endorse or promote products
00017  *       derived from this software without specific prior written permission.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THOMAS A. VAUGHAN ''AS IS'' AND ANY
00020  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00021  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00022  * DISCLAIMED. IN NO EVENT SHALL THOMAS A. VAUGHAN BE LIABLE FOR ANY
00023  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00024  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00025  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00026  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00027  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00028  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029  *
00030  *
00031  * Performance timers for (duh) timing.  Should be threadsafe!
00032  */
00033 
00034 #ifndef WAVEPACKET_PERF_H__
00035 #define WAVEPACKET_PERF_H__
00036 
00037 // includes --------------------------------------------------------------------
00038 #include "common/common.h"
00039 
00040 #ifdef WIN32
00041 #include <winsock2.h>
00042 int gettimeofday(OUT struct timeval * tv, OUT struct timezone * tz);
00043 #endif  // WIN32
00044 
00045 
00046 namespace perf {
00047 
00048 
00049 /// \ingroup general
00050 /*@{*/
00051 
00052 
00053 ////////////////////////////////////////////////////////////////////////////////
00054 ///
00055 /// \defgroup perf Performance Timers API
00056 ///
00057 /// A set of simple timers (and time objects) used to quickly generate
00058 /// information about how the code is performing.
00059 ///
00060 ////////////////////////////////////////////////////////////////////////////////
00061 /*@{*/
00062 
00063 /// yes, my own time_t for convenience in the perf library
00064 struct time_t {
00065         // constructor, manipulators
00066         time_t(IN long in_sec, IN long in_usec) throw() {
00067                         this->set(in_sec, in_usec);
00068                 }
00069         time_t(void) throw() { this->clear(); }
00070 
00071         void increment(IN const time_t& t) throw() {
00072                         // increment uSeconds, and account for rollover
00073                         useconds += t.useconds;
00074                         int nSecs = useconds / 1000000;
00075                         useconds = useconds % 1000000;
00076 
00077                         // now increment seconds
00078                         seconds += nSecs;
00079                         seconds += t.seconds;
00080                 }
00081 
00082         void decrement(IN const time_t& t) throw() {
00083 
00084                         // DPRINTF("Have: %ld sec  %ld usec", seconds, useconds);
00085                         // DPRINTF("  dec %ld sec  %ld usec", t.seconds, t.useconds);
00086 
00087                         // decrement uSeconds, borrow if necessary
00088                         if (t.useconds > useconds) {
00089                                 useconds += 1000000;
00090                                 --seconds;
00091                         }
00092 
00093                         useconds -= t.useconds;
00094                         seconds -= t.seconds;
00095 
00096                         ASSERT(useconds >= 0 && useconds < 1000000,
00097                             "Bad microseconds: %ld", useconds);
00098                         if (seconds < 0) {
00099                                 DPRINTF("Negative seconds!");
00100                                 DPRINTF("Input: seconds=%ld  useconds=%ld",
00101                                     t.seconds, t.useconds);
00102                                 DPRINTF("Local: seconds=%ld  useconds=%ld",
00103                                     seconds, useconds);
00104                                 // ASSERT(false, "Input > Local?");
00105 
00106                                 // this happens when someone resets the system
00107                                 //   clock while we're timing.  Just use zero
00108                                 seconds = 0;
00109                                 useconds = 0;
00110                         }
00111                         // DPRINTF("  now %ld sec  %ld usec", seconds, useconds);
00112                 }
00113 
00114         bool isGreaterThan(IN const time_t& t) const throw() {
00115                         if (seconds > t.seconds)
00116                                 return true;
00117                         if (seconds < t.seconds)
00118                                 return false;
00119                         return (useconds > t.useconds);
00120                 }
00121 
00122         double getSeconds(void) const throw() {
00123                         return (1.0 * seconds) + (1.0e-6 * useconds);
00124                 }
00125 
00126         long getMicroseconds(void) const throw() {
00127                         return useconds;
00128                 }
00129 
00130         void clear(void) throw() {
00131                         seconds = useconds = 0;
00132                 }
00133 
00134         void set(IN long in_sec, IN long in_usec) throw() {
00135                         ASSERT(in_sec >= 0, "Invalid seconds: %ld", in_sec);
00136                         ASSERT(in_usec >= 0 && in_usec < 1000000,
00137                             "Invalid microseconds: %ld", in_usec);
00138 
00139                         seconds = in_sec;
00140                         useconds = in_usec;
00141                 }
00142 
00143 private:
00144         // data fields
00145         long    seconds;
00146         long    useconds;
00147 };
00148 
00149 
00150 
00151 ////////////////////////////////////////////////////////////////////////////////
00152 ///
00153 ///     Timer class -- just throw one of these on the stack with a unique name
00154 ///
00155 ///     When the timer destructs, it will register the time.  At the end of
00156 ///     program execution (actually, at any time!) you can call
00157 ///     getTimingSummary() and retrieve the list of all timers encountered and
00158 ///     basic statistics.
00159 ///
00160 /// Example:
00161 /// \code
00162 ///     void myFunction(void) {
00163 ///             perf::Timer timer("myFunction");
00164 ///             dosomething();
00165 ///             dosomething_else();
00166 ///             {
00167 ///                     perf::Timer timer("myFunction--expensive");
00168 ///                     dosomething_expensive();
00169 //              }
00170 ///     }
00171 /// \endcode
00172 ////////////////////////////////////////////////////////////////////////////////
00173 
00174 class Timer {
00175 public:
00176         Timer(const char * name);
00177         ~Timer(void);
00178 
00179 private:
00180         // disallowed operations
00181         Timer(const Timer&);
00182         const Timer& operator = (const Timer&);
00183 
00184         // private data
00185         time_t          m_start_time;
00186         void           *m_context;
00187 };
00188 
00189 
00190 
00191 ////////////////////////////////////////////////////////////////////////////////
00192 //
00193 //      DebugTimer -- prints to stderr on destruction
00194 //
00195 ////////////////////////////////////////////////////////////////////////////////
00196 
00197 class DebugTimer {
00198 public:
00199         DebugTimer(IN const char * msg);
00200         ~DebugTimer(void) throw();
00201 
00202 private:
00203         DebugTimer(const DebugTimer&);
00204         const DebugTimer& operator = (const DebugTimer&);
00205 
00206         // data
00207         time_t          m_start_time;
00208         std::string     m_msg;
00209 };
00210 
00211 
00212 
00213 ////////////////////////////////////////////////////////////////////////////////
00214 //
00215 //      Other public APIs (reporting mostly)
00216 //
00217 ////////////////////////////////////////////////////////////////////////////////
00218 
00219 /// return time_t object containing current time
00220 time_t getNow(void) throw();
00221 
00222 /// you can disable the timing system
00223 /// it is better to remove verbose timers, however!
00224 ///
00225 /// TODO: remove this function altogether?
00226 void enableTimers(IN bool enabled) throw();     // enabled by default
00227 
00228 
00229 /// return a string containing (human-readable) formatted timing information
00230 void getTimingSummary(OUT std::string&);
00231 
00232 /// dumps timing summary to the given stream
00233 void dumpTimingSummary(IO std::ostream&);
00234 
00235 };      // perf namespace
00236 
00237 
00238 /*@}*/  // end documentation block
00239 
00240 
00241 #endif  // WAVEPACKET_PERF_H__
00242