debug.cpp

Go to the documentation of this file.
00001 /*****************************************************************************/
00002 /*!
00003  * \file debug.cpp
00004  * \brief Description: Implementation of debugging facilities.
00005  * 
00006  * Author: Sergey Berezin
00007  * 
00008  * Created: Fri Jan 31 11:48:37 2003
00009  *
00010  * <hr>
00011  * Copyright (C) 2003 by the Board of Trustees of Leland Stanford
00012  * Junior University and by New York University. 
00013  *
00014  * License to use, copy, modify, sell and/or distribute this software
00015  * and its documentation for any purpose is hereby granted without
00016  * royalty, subject to the terms and conditions defined in the \ref
00017  * LICENSE file provided with this distribution.  In particular:
00018  *
00019  * - The above copyright notice and this permission notice must appear
00020  * in all copies of the software and related documentation.
00021  *
00022  * - THE SOFTWARE IS PROVIDED "AS-IS", WITHOUT ANY WARRANTIES,
00023  * EXPRESSED OR IMPLIED.  USE IT AT YOUR OWN RISK.
00024  * 
00025  * <hr>
00026  * 
00027  */
00028 /*****************************************************************************/
00029 
00030 #include <fstream>
00031 
00032 #include "debug.h"
00033 
00034 using namespace std;
00035 
00036 namespace CVCL {
00037   
00038 // Function for fatal exit.  It just exits with code 1, but is
00039 // provided here for the debugger to set a breakpoint to.  For this
00040 // reason, it is not inlined.
00041 void fatalError(const std::string& file, int line,
00042                 const std::string& cond, const std::string& msg) {
00043   cerr <<  "\n**** Fatal error in " << file << ":" << line
00044        << " (" << cond << ")\n" << msg << endl << flush;
00045   exit(1);
00046 }
00047   
00048 } // end of namespace CVCL
00049 
00050 #ifdef DEBUG
00051 
00052 #include <sys/time.h>
00053 #include <iomanip>
00054 
00055 namespace CVCL {
00056 // Similar to fatalError to raise an exception when DebugAssert fires.
00057 // This does not necessarily cause the program to quit.
00058 void debugError(const std::string& file, int line,
00059                 const std::string& cond, const std::string& msg)
00060   throw(Exception) {
00061   ostringstream ss;
00062   ss << "in " << file << ":" << line << " (" << cond << ")\n" << msg;
00063   throw DebugException(ss.str());
00064 }
00065   
00066 
00067 class DebugTime {
00068 public:
00069   timeval d_tv;  // Make it public.  What the heck, anyways...
00070   // Constructors
00071   DebugTime() {
00072     d_tv.tv_sec = 0;
00073     d_tv.tv_usec = 0;
00074   }
00075   DebugTime(const timeval& tv): d_tv(tv) { }
00076 
00077   // Set time to zero
00078   void reset() {
00079     d_tv.tv_sec = 0;
00080     d_tv.tv_usec = 0;
00081   }
00082     
00083   // Incremental assignments
00084   DebugTime& operator+=(const DebugTime& t) {
00085     d_tv.tv_sec += t.d_tv.tv_sec;
00086     d_tv.tv_usec += t.d_tv.tv_usec;
00087     while(d_tv.tv_usec >= 1000000) {
00088       d_tv.tv_usec -= 1000000;
00089       d_tv.tv_sec++;
00090     }
00091     return *this;
00092   }
00093   DebugTime& operator-=(const DebugTime& t) {
00094     while(d_tv.tv_usec < t.d_tv.tv_usec) {
00095       d_tv.tv_usec += 1000000;
00096       d_tv.tv_sec--;
00097     }
00098     d_tv.tv_sec -= t.d_tv.tv_sec;
00099     d_tv.tv_usec -= t.d_tv.tv_usec;
00100     return *this;
00101   }
00102 
00103   friend class DebugTimer;
00104   friend bool operator==(const DebugTime& t1, const DebugTime& t2);
00105   friend bool operator!=(const DebugTime& t1, const DebugTime& t2);
00106 
00107   friend bool operator<(const DebugTimer& t1, const DebugTimer& t2);
00108   friend bool operator>(const DebugTimer& t1, const DebugTimer& t2);
00109   friend bool operator<=(const DebugTimer& t1, const DebugTimer& t2);
00110   friend bool operator>=(const DebugTimer& t1, const DebugTimer& t2);
00111 
00112   friend ostream& operator<<(ostream& os, const DebugTime& t);
00113   friend ostream& operator<<(ostream& os, const DebugTimer& t);
00114 };
00115 
00116 DebugTime operator+(const DebugTime& t1, const DebugTime& t2) {
00117   DebugTime res(t1);
00118   res += t2;
00119   return res;
00120 }
00121 DebugTime operator-(const DebugTime& t1, const DebugTime& t2) {
00122   DebugTime res(t1);
00123   res -= t2;
00124   return res;
00125 }
00126 
00127 bool operator==(const DebugTime& t1, const DebugTime& t2) {
00128   return(t1.d_tv.tv_sec == t2.d_tv.tv_sec
00129          && t1.d_tv.tv_usec == t2.d_tv.tv_usec);
00130 }
00131 
00132 bool operator!=(const DebugTime& t1, const DebugTime& t2) {
00133   return !(t1 == t2);
00134 }
00135 
00136 ////////////////////////////////////////////////////////////////////////
00137 // Class DebugTimer
00138 ////////////////////////////////////////////////////////////////////////
00139 
00140 // Destructor
00141 DebugTimer::~DebugTimer() {
00142   if(d_clean_time)
00143     delete d_time;
00144 }
00145 
00146 void Debug::init(const vector<pair<string,bool> >* traceOptions,
00147                  const string* dumpName)
00148 {
00149   d_traceOptions = traceOptions;
00150   d_dumpName = dumpName;
00151 }
00152 
00153 
00154 DebugFlag
00155 Debug::traceFlag(char* name) { return traceFlag(std::string(name)); }
00156 
00157 void
00158 Debug::traceAll(bool enable) { traceFlag("ALL") = enable; }
00159 
00160 // Copy constructor: copy the *pointer* from public timers, and
00161 // value from private.  The reason is, when you modify a public
00162 // timer, you want the changes to show in the central database and
00163 // everywhere else, whereas private timers are used as independent
00164 // temporary variables holding intermediate time values.
00165 DebugTimer::DebugTimer(const DebugTimer& timer) {
00166   d_clean_time = timer.d_clean_time;
00167   if(d_clean_time) {
00168     // We are copying a private timer; make our own copy
00169     d_time = new DebugTime(*timer.d_time);
00170     d_clean_time = true;
00171   } else {
00172     // This is a public timer; just grab the pointer
00173     d_time = timer.d_time;
00174   }
00175 }
00176 // Assignment: same logistics as for the copy constructor, but need
00177 // to take care of our own pointer
00178 DebugTimer& DebugTimer::operator=(const DebugTimer& timer) {
00179   // Check for self-assignment
00180   if(&timer == this) return *this;
00181 
00182   if(timer.d_clean_time) {
00183     // We are copying a private timer
00184     if(d_clean_time) // We already have a private pointer, reuse it
00185       *d_time = *timer.d_time;
00186     else { // Create a new storage
00187       d_time = new DebugTime(*timer.d_time);
00188       d_clean_time = true;
00189     }
00190   } else {
00191     // This is a public timer
00192     if(d_clean_time) // We own our pointer, clean it up first
00193       delete d_time;
00194     d_time = timer.d_time;
00195     d_clean_time = false; 
00196   }
00197   return *this;
00198 }
00199 
00200 void DebugTimer::reset() {
00201   d_time->reset();
00202 }
00203 
00204 DebugTimer& DebugTimer::operator+=(const DebugTimer& timer) {
00205   (*d_time) += *(timer.d_time);
00206   return *this;
00207 }
00208 
00209 DebugTimer& DebugTimer::operator-=(const DebugTimer& timer) {
00210   (*d_time) -= *(timer.d_time);
00211   return *this;
00212 }
00213 
00214 // These will produce new "private" timers
00215 DebugTimer DebugTimer::operator+(const DebugTimer& timer) {
00216   return DebugTimer(new DebugTime((*d_time) + (*timer.d_time)),
00217                     true /* take the new DebugTime */);
00218 }
00219 
00220 DebugTimer DebugTimer::operator-(const DebugTimer& timer) {
00221   return DebugTimer(new DebugTime((*d_time) - (*timer.d_time)),
00222                     true /* take the new DebugTime */);
00223 }
00224 
00225 // Comparisons
00226 bool operator==(const DebugTimer& t1, const DebugTimer& t2) {
00227   return(*t1.d_time == *t2.d_time);
00228 }
00229 bool operator!=(const DebugTimer& t1, const DebugTimer& t2) {
00230   return(*t1.d_time != *t2.d_time);
00231 }
00232 bool operator<(const DebugTimer& t1, const DebugTimer& t2) {
00233   return((*t1.d_time).d_tv.tv_sec < (*t2.d_time).d_tv.tv_sec
00234          || ((*t1.d_time).d_tv.tv_sec == (*t2.d_time).d_tv.tv_sec
00235              && (*t1.d_time).d_tv.tv_usec < (*t2.d_time).d_tv.tv_usec));
00236 }
00237 bool operator>(const DebugTimer& t1, const DebugTimer& t2) {
00238   return((*t1.d_time).d_tv.tv_sec > (*t2.d_time).d_tv.tv_sec
00239          || ((*t1.d_time).d_tv.tv_sec == (*t2.d_time).d_tv.tv_sec
00240              && (*t1.d_time).d_tv.tv_usec > (*t2.d_time).d_tv.tv_usec));
00241 }
00242 bool operator<=(const DebugTimer& t1, const DebugTimer& t2) {
00243   return((*t1.d_time).d_tv.tv_sec <= (*t2.d_time).d_tv.tv_sec
00244          || ((*t1.d_time).d_tv.tv_sec == (*t2.d_time).d_tv.tv_sec
00245              && (*t1.d_time).d_tv.tv_usec <= (*t2.d_time).d_tv.tv_usec));
00246 }
00247 bool operator>=(const DebugTimer& t1, const DebugTimer& t2) {
00248   return((*t1.d_time).d_tv.tv_sec >= (*t2.d_time).d_tv.tv_sec
00249          || ((*t1.d_time).d_tv.tv_sec == (*t2.d_time).d_tv.tv_sec
00250              && (*t1.d_time).d_tv.tv_usec >= (*t2.d_time).d_tv.tv_usec));
00251 }
00252 
00253 // Print the time and timer's values
00254 ostream& operator<<(ostream& os, const DebugTime& t) {
00255   os << t.d_tv.tv_sec << "." << setfill('0') << setw(6) << t.d_tv.tv_usec;
00256   return os;
00257 }
00258 ostream& operator<<(ostream& os, const DebugTimer& timer) {
00259   return(os << *timer.d_time);
00260 }
00261   
00262 ////////////////////////////////////////////////////////////////////////
00263 // Class Debug
00264 ////////////////////////////////////////////////////////////////////////
00265 
00266 // Destructor: destroy all the pointers in d_timers
00267 Debug::~Debug() {
00268   TimerMap::iterator i, iend;
00269   for(i = d_timers.begin(), iend = d_timers.end(); i != iend; ++i)
00270     delete (*i).second;
00271   if(d_osDumpTrace != NULL)
00272     delete d_osDumpTrace;
00273 }
00274 
00275 bool
00276 Debug::trace(const string& name) {
00277   // First, check if this flag was set in the command line.  Walk the
00278   // vector backwards, so that the last +/-trace takes effect.
00279   if(d_traceOptions != NULL) {
00280     vector<pair<string,bool> >::const_reverse_iterator i, iend;
00281     for(i=d_traceOptions->rbegin(), iend=d_traceOptions->rend(); i!=iend; ++i)
00282       if((*i).first == name || (*i).first == "ALL") return (*i).second;
00283   }
00284   return traceFlag(name) || traceFlag("ALL");
00285 }
00286 
00287 
00288 DebugTimer Debug::timer(const string& name) {
00289   // See if we already have the timer 
00290   if(d_timers.count(name) > 0) return(DebugTimer(d_timers[name]));
00291   else {
00292     // Create a new timer
00293     DebugTime *t = new DebugTime();
00294     d_timers[name] = t;
00295     return DebugTimer(t);
00296   }
00297 }
00298 
00299 DebugTimer Debug::newTimer() {
00300   return DebugTimer(new DebugTime(), true /* take the pointer */);
00301 }
00302 
00303 void Debug::setCurrentTime(DebugTimer& timer) {
00304   struct timezone tz;
00305   DebugAssert(gettimeofday(&((*timer.d_time).d_tv), &tz) == 0,
00306               "Debug::setCurrentTime() failed");
00307 }
00308 // Set the timer to the difference between current time and the
00309 // time stored in the timer: timer = currentTime - timer.
00310 // Intended to obtain the time interval since the last call to
00311 // setCurrentTime() with that timer.
00312 void Debug::setElapsed(DebugTimer& timer) {
00313   struct timezone tz;
00314   DebugTime t;
00315   DebugAssert(gettimeofday(&(t.d_tv), &tz) == 0,
00316               "Debug::setElapsed() failed");
00317   *timer.d_time = t - (*timer.d_time);
00318 }
00319 
00320 /*! If the stream is not initialized, open the file
00321  * If the filename is empty or "-", then return
00322  * cout (but do not initialize the stream in this case).
00323  */
00324   
00325 ostream& Debug::getOSDumpTrace() {
00326   if(d_osDumpTrace != NULL) return *d_osDumpTrace;
00327   // Check if the flag has a file name in it
00328   if(*d_dumpName == "" || *d_dumpName == "-") return cout;
00329   d_osDumpTrace = new ofstream(d_dumpName->c_str());
00330   return *d_osDumpTrace;
00331 }
00332 
00333 
00334 // Print an entry to the dump-sat file: free-form message
00335 void Debug::dumpTrace(const std::string& title, 
00336                       const vector<pair<string,string> >& fields) {
00337   ostream& os = getOSDumpTrace();
00338   os << "[" << title << "]\n";
00339   for(size_t i=0, iend=fields.size(); i<iend; ++i)
00340     os << fields[i].first << " = " << fields[i].second << "\n";
00341   os << endl;
00342 }
00343 
00344 
00345 // Print all the collected data if "DEBUG" flag is set
00346 void Debug::printAll(ostream& os) {
00347   if(!trace("DEBUG")) return;
00348   // Flags
00349   os << endl
00350      << "********************************" << endl
00351      << "******* Debugging Info *********" << endl
00352      << "********************************" << endl;
00353 
00354   if(d_flags.size() > 0) {
00355     os << endl << "************ Flags *************" << endl << endl;
00356     for(FlagMap::iterator
00357           i = d_flags.begin(), iend = d_flags.end(); i != iend; ++i)
00358       os << (*i).first << " = " << (*i).second << endl;
00359   }
00360 
00361   if(d_counters.size() > 0) {
00362     os << endl << "*********** Counters ***********" << endl << endl;
00363     for(CounterMap::iterator
00364           i = d_counters.begin(), iend = d_counters.end(); i != iend; ++i)
00365       os << (*i).first << " = " << (*i).second << endl;
00366   }
00367 
00368   if(d_timers.size() > 0) {
00369     os << endl << "************ Timers ************" << endl << endl;
00370     for(TimerMap::iterator
00371           i = d_timers.begin(), iend = d_timers.end(); i != iend; ++i)
00372       os << (*i).first << " = " << *((*i).second) << endl;
00373   }
00374 
00375   os << endl
00376      << "********************************" << endl
00377      << "**** End of Debugging Info *****" << endl
00378      << "********************************" << endl;
00379 }
00380 
00381 // Global debugger.  It must be initialized in main() through its
00382 // init() method.
00383 Debug debugger;
00384 
00385 } // end of namespace CVCL
00386 
00387 #endif

Generated on Thu Apr 13 16:57:30 2006 for CVC Lite by  doxygen 1.4.4