debug.h

Go to the documentation of this file.
00001 /*****************************************************************************/
00002 /*!
00003  * \file debug.h
00004  * \brief Description: Collection of debugging macros and functions. 
00005  * 
00006  * Author: Sergey Berezin
00007  * 
00008  * Created: Thu Dec  5 13:12:59 2002
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 #ifndef _CVC_lite__debug_h
00031 #define _CVC_lite__debug_h
00032 
00033 #include <string>
00034 #include <iostream>
00035 #include <sstream>
00036 #include <vector>
00037 #include "exception.h"
00038 
00039 /*! @brief If something goes horribly wrong, print a message and abort
00040   immediately with exit(1). */
00041 /*! This macro stays even in the non-debug build, so the end users can
00042   send us meaningful bug reports. */
00043 
00044 #define FatalAssert(cond, msg) if(!(cond)) \
00045  CVCL::fatalError(__FILE__, __LINE__, #cond, msg)
00046 
00047 namespace CVCL {
00048   //! Function for fatal exit.
00049   /*! It just exits with code 1, but is provided here for the debugger
00050    to set a breakpoint to.  For this reason, it is not inlined. */
00051   extern void fatalError(const std::string& file, int line,
00052                          const std::string& cond, const std::string& msg);
00053 }
00054 
00055 #ifdef DEBUG
00056 
00057 #include "compat_hash_map.h"
00058 #include "compat_hash_set.h"
00059 
00060 //! Any debugging code must be within IF_DEBUG(...)
00061 #define IF_DEBUG(code) code
00062 
00063 //! Print a value conditionally.
00064 /*!  If 'cond' is true, print 'pre', then 'v', then 'post'.  The type
00065  of v must have overloaded operator<<.  It expects a ';' after it. */
00066 #define DBG_PRINT(cond, pre, v, post) if(cond) CVCL::debugger.getOS() \
00067   << (pre) << (v) << (post) << std::endl
00068 
00069 //! Print a message conditionally
00070 #define DBG_PRINT_MSG(cond, msg) \
00071   if(cond) CVCL::debugger.getOS() << (msg) << std::endl
00072 
00073 /*! @brief Same as DBG_PRINT, only takes a flag name instead of a
00074   general condition */
00075 #define TRACE(flag, pre, v, post) \
00076   DBG_PRINT(CVCL::debugger.trace(flag), pre, v, post)
00077 
00078 //! Same as TRACE, but for a simple message
00079 #define TRACE_MSG(flag, msg) \
00080   DBG_PRINT_MSG(CVCL::debugger.trace(flag), msg)
00081 
00082 //! Sanity check for debug build.  It disappears in the production code.
00083 #define DebugAssert(cond, str) if(!(cond)) \
00084  CVCL::debugError(__FILE__, __LINE__, #cond, str)
00085 
00086 
00087 namespace CVCL {
00088 
00089 /*! @brief A class which sets a boolean value to true when created,
00090  * and resets to false when deleted.
00091  *
00092  * Useful for tracking when the control is within a certain method or
00093  * not.  For example, TheoryCore::addFact() uses d_inAddFact to check
00094  * that certain other methods are only called from within addFact().
00095  * However, when an exception is thrown, this variable is not reset.
00096  * The watcher class will reset the variable even in those cases.
00097  */
00098 class ScopeWatcher {
00099  private:
00100   bool *d_flag;
00101 public:
00102   ScopeWatcher(bool *flag): d_flag(flag) { *d_flag = true; }
00103   ~ScopeWatcher() { *d_flag = false; }
00104 };
00105 
00106   class Expr;
00107   //! Our exception to throw
00108   class DebugException: public Exception {
00109   public:
00110     // Constructor
00111     DebugException(const std::string& msg): Exception(msg) { }
00112     // Printing
00113     virtual std::string toString() const {
00114       return "Assertion violation " + d_msg;
00115     }
00116   }; // end of class DebugException
00117 
00118   //! Similar to fatalError to raise an exception when DebugAssert fires.
00119   /*! This does not necessarily cause the program to quit. */
00120   extern void debugError(const std::string& file, int line,
00121                          const std::string& cond, const std::string& msg)
00122     throw(Exception);
00123 
00124   // First, wrapper classes for flags, counters, and timers.  Later,
00125   // we overload some operators like '=', '++', etc. for those
00126   // classes.
00127 
00128   //! Boolean flag (can only be true or false)
00129   class DebugFlag {
00130   private:
00131     bool* d_flag; // We don't own the pointer
00132   public:
00133     // Constructor: takes the pointer to the actual flag, normally
00134     // stored in class Debug below.
00135     DebugFlag(bool& flag) : d_flag(&flag) { }
00136     // Destructor
00137     ~DebugFlag() { }
00138     // Auto-cast to boolean
00139     operator bool() { return *d_flag; }
00140 
00141     // Setting and resetting by ++ and --
00142     // Prefix versions:
00143     bool operator--() { *d_flag = false; return false; }
00144     bool operator++() { *d_flag = true; return true; }
00145     // Postfix versions:
00146     bool operator--(int) { bool x=*d_flag; *d_flag=false; return x; }
00147     bool operator++(int) { bool x=*d_flag; *d_flag=true; return x; }
00148     // Can be assigned only a boolean value
00149     DebugFlag& operator=(bool x) { *d_flag=(x!=false); return *this; }
00150     // Comparisons
00151     friend bool operator==(const DebugFlag& f1, const DebugFlag& f2);
00152     friend bool operator!=(const DebugFlag& f1, const DebugFlag& f2);
00153     // Printing
00154     friend std::ostream& operator<<(std::ostream& os, const DebugFlag& f);
00155   }; // end of class DebugFlag
00156 
00157   //! Checks if the *values* of the flags are equal
00158   inline bool operator==(const DebugFlag& f1, const DebugFlag& f2) {
00159     return (*f1.d_flag) == (*f2.d_flag);
00160   }
00161   //! Checks if the *values* of the flags are disequal
00162   inline bool operator!=(const DebugFlag& f1, const DebugFlag& f2) {
00163     return (*f1.d_flag) != (*f2.d_flag);
00164   }
00165   //! Printing flags
00166   inline std::ostream& operator<<(std::ostream& os, const DebugFlag& f) {
00167     if(*f.d_flag) return(os << "true");
00168     else return(os << "false");
00169   }
00170 
00171   //! Integer counter for debugging purposes.
00172   /*! Intended use is to count events (e.g. number of function calls),
00173     but can be used to store any integer value (e.g. size of some data
00174     structure) */
00175   class DebugCounter {
00176   private:
00177     int* d_counter; //!< We don't own the pointer
00178   public:
00179     //! Constructor
00180     /*!  Takes the pointer to the actual counter, normally stored in
00181       class Debug below. */
00182     DebugCounter(int& c) : d_counter(&c) { }
00183     //! Destructor
00184     ~DebugCounter() { }
00185     //! Auto-cast to int.
00186     /*! In particular, arithmetic comparisons like <, >, <=, >= will
00187       work because of this. */
00188     operator int() { return *d_counter; }
00189 
00190     // Auto-increment operators
00191 
00192     //! Prefix auto-decrement
00193     int operator--() { return --(*d_counter); }
00194     //! Prefix auto-increment
00195     int operator++() { return ++(*d_counter); }
00196     //! Postfix auto-decrement
00197     int operator--(int) { return (*d_counter)--; }
00198     //! Postfix auto-increment
00199     int operator++(int) { return (*d_counter)++; }
00200     //! Value assignment.
00201     DebugCounter& operator=(int x) { *d_counter=x; return *this; }
00202     DebugCounter& operator+=(int x) { *d_counter+=x; return *this; }
00203     DebugCounter& operator-=(int x) { *d_counter-=x; return *this; }
00204     //! Assignment from another counter.
00205     /*! It copies the value, not the pointer */
00206     DebugCounter& operator=(const DebugCounter& x)
00207       { *d_counter=*x.d_counter; return *this; }
00208     /*! It copies the value, not the pointer */
00209     DebugCounter& operator-=(const DebugCounter& x)
00210       { *d_counter-=*x.d_counter; return *this; }
00211     /*! It copies the value, not the pointer */
00212     DebugCounter& operator+=(const DebugCounter& x)
00213       { *d_counter+=*x.d_counter; return *this; }
00214     // Comparisons to integers and other DebugCounters
00215     friend bool operator==(const DebugCounter& c1, const DebugCounter& c2);
00216     friend bool operator!=(const DebugCounter& c1, const DebugCounter& c2);
00217     friend bool operator==(int c1, const DebugCounter& c2);
00218     friend bool operator!=(int c1, const DebugCounter& c2);
00219     friend bool operator==(const DebugCounter& c1, int c2);
00220     friend bool operator!=(const DebugCounter& c1, int c2);
00221     //! Printing counters
00222     friend std::ostream& operator<<(std::ostream& os, const DebugCounter& f);
00223   }; // end of class DebugCounter
00224 
00225   inline bool operator==(const DebugCounter& c1, const DebugCounter& c2) {
00226     return (*c1.d_counter) == (*c2.d_counter);
00227   }
00228   inline bool operator!=(const DebugCounter& c1, const DebugCounter& c2) {
00229     return (*c1.d_counter) != (*c2.d_counter);
00230   }
00231   inline bool operator==(int c1, const DebugCounter& c2) {
00232     return c1 == (*c2.d_counter);
00233   }
00234   inline bool operator!=(int c1, const DebugCounter& c2) {
00235     return c1 != (*c2.d_counter);
00236   }
00237   inline bool operator==(const DebugCounter& c1, int c2) {
00238     return (*c1.d_counter) == c2;
00239   }
00240   inline bool operator!=(const DebugCounter& c1, int c2) {
00241     return (*c1.d_counter) != c2;
00242   }
00243   inline std::ostream& operator<<(std::ostream& os, const DebugCounter& c) {
00244     return (os << *c.d_counter);
00245   }
00246 
00247   //! A class holding the time value.
00248   /*! What exactly is time is not exposed.  It can be the system's
00249     struct timeval, or it can be the (subset of the) user/system/real
00250     time tuple. */
00251   class DebugTime;
00252 
00253   //! Time counter.
00254   /*! Intended use is to store time intervals or accumulated time for
00255     multiple events (e.g. time spent to execute certain lines of code,
00256     or accumulated time spent in a particular function). */
00257   class DebugTimer {
00258   private:
00259     DebugTime* d_time; //!< The time value
00260     bool d_clean_time; //!< Set if we own *d_time
00261   public:
00262     //! Constructor: takes the pointer to the actual time value.
00263     /*! It is either stored in class Debug below (then the timer is
00264       "public"), or we own it, making the timer "private". */
00265     DebugTimer(DebugTime* time, bool take_time = false)
00266       : d_time(time), d_clean_time(take_time) { }
00267     /*! @brief Copy constructor: copy the *pointer* from public
00268       timers, and *value* from private.  */
00269     /*! The reason for different behavior for public and private time
00270       is the following.  When you modify a public timer, you want the
00271       changes to show in the central database and everywhere else,
00272       whereas private timers are used as independent temporary
00273       variables holding intermediate time values. */
00274     DebugTimer(const DebugTimer& timer);
00275     //! Assignment: same logistics as for the copy constructor
00276     DebugTimer& operator=(const DebugTimer& timer);
00277 
00278     //! Destructor
00279     ~DebugTimer();
00280 
00281     // Operators
00282     //! Set time to zero
00283     void reset();
00284     DebugTimer& operator+=(const DebugTimer& timer);
00285     DebugTimer& operator-=(const DebugTimer& timer);
00286     //! Produces new "private" timer
00287     DebugTimer operator+(const DebugTimer& timer);
00288     //! Produces new "private" timer
00289     DebugTimer operator-(const DebugTimer& timer);
00290 
00291     // Our friends
00292     friend class Debug;
00293     // Comparisons
00294     friend bool operator==(const DebugTimer& t1, const DebugTimer& t2);
00295     friend bool operator!=(const DebugTimer& t1, const DebugTimer& t2);
00296     friend bool operator<(const DebugTimer& t1, const DebugTimer& t2);
00297     friend bool operator>(const DebugTimer& t1, const DebugTimer& t2);
00298     friend bool operator<=(const DebugTimer& t1, const DebugTimer& t2);
00299     friend bool operator>=(const DebugTimer& t1, const DebugTimer& t2);
00300 
00301     //! Print the timer's value
00302     friend std::ostream& operator<<(std::ostream& os, const DebugTimer& timer);
00303   }; // end of class DebugTimer
00304 
00305   //! The heart of the Bug Extermination Kingdom.
00306   /*! This class exposes many important components of the entire
00307     CVC-lite system for use in debugging, keeps all the flags,
00308     counters, and timers in the central database, and provides timing
00309     and printing functions. */
00310 
00311   class Debug {
00312   private:
00313     //! Command line options for tracing; these override the TRACE command
00314     const std::vector<std::pair<std::string,bool> >* d_traceOptions;
00315     //! name of dump file
00316     const std::string* d_dumpName;
00317     // Output control
00318     std::ostream* d_os;
00319     // Stream for dumping trace to file ("dump-trace" option)
00320     std::ostream* d_osDumpTrace;
00321     //! Private hasher class for strings
00322     class stringHash {
00323     public:
00324       size_t operator()(const std::string& s) const {
00325         std::hash<char*> h;
00326         return h(s.c_str());
00327       }
00328     }; // end of stringHash
00329     // Hash tables for storing flags, counters, and timers
00330     typedef std::hash_map<std::string, bool, stringHash> FlagMap;
00331     typedef std::hash_map<std::string, int, stringHash> CounterMap;
00332     typedef std::hash_map<std::string, DebugTime*, stringHash> TimerMap;
00333     FlagMap d_flags;       //!< Set of flags
00334     FlagMap d_traceFlags;  //!< Set of trace flags
00335     CounterMap d_counters; //!< Set of counters
00336     /*! Note, that the d_timers map does *not* own the pointers; so
00337       the objects in d_timers must be destroyed explicitly in our
00338       destructor. */
00339     TimerMap d_timers;     //!< Set of timers
00340 
00341   public:
00342     //! Constructor
00343     Debug(): d_traceOptions(NULL), d_os(&std::cerr), d_osDumpTrace(NULL) { }
00344     //! Destructor (must destroy objects it d_timers)
00345     ~Debug();
00346     //! Must be called before Debug class can be safely used
00347     void init(const std::vector<std::pair<std::string,bool> >* traceOptions,
00348               const std::string* dumpName);
00349     //! Accessing flags by name.
00350     /*! If a flag doesn't exist, it is created and initialized to
00351       false. */
00352     DebugFlag flag(const std::string& name)
00353       { return DebugFlag(d_flags[name]); }
00354     //! Accessing tracing flags by name.
00355     /*! If a flag doesn't exist, it is created and initialized to
00356       false. */
00357     DebugFlag traceFlag(const std::string& name)
00358       { return DebugFlag(d_traceFlags[name]); }
00359     //! Accessing tracing flag by char* name (mostly for GDB)
00360     DebugFlag traceFlag(char* name);
00361     //! Set tracing of everything on (1) and off (0) [for use in GDB]
00362     void traceAll(bool enable = true);
00363     //! Accessing counters by name.
00364     /*! If a counter doesn't exist, it is created and initialized to 0. */
00365     DebugCounter counter(const std::string& name)
00366       { return DebugCounter(d_counters[name]); }
00367     //! Accessing timers by name.
00368     /*! If a timer doesn't exist, it is created and initialized to 0. */
00369     DebugTimer timer(const std::string& name);
00370 
00371     //! Check whether to print trace info for a particular flag.
00372     /*! Trace flags are the same DebugFlag objects, but live in a
00373       different namespace from the normal debug flags */
00374     bool trace(const std::string& name);
00375 
00376     // Timer functions
00377 
00378     //! Create a new "private" timer, initially set to 0. 
00379     /*! The new timer will not be added to the set of timers, will not
00380      have a name, and will not be printed by 'printAll()'.  It is
00381      intended to be used to measure time intervals which are later
00382      added or assigned to the named timers. */
00383     static DebugTimer newTimer();
00384 
00385     //! Set the timer to the current time (whatever that means)
00386     void setCurrentTime(DebugTimer& timer);
00387     void setCurrentTime(const std::string& name) {
00388       DebugTimer t(timer(name));
00389       setCurrentTime(t);
00390     }
00391     /*! @brief Set the timer to the difference between current time
00392       and the time stored in the timer: timer = currentTime -
00393       timer. */
00394     /*! Intended to obtain the time interval since the last call to
00395       setCurrentTime() with that timer. */
00396     void setElapsed(DebugTimer& timer);
00397     
00398     //! Return the ostream used for debugging output
00399     std::ostream& getOS() { return *d_os; }
00400     //! Return the ostream for dumping trace
00401     std::ostream& getOSDumpTrace();
00402 
00403     //! Print an entry to the dump file
00404     void dumpTrace(const std::string& title,
00405                    const std::vector<std::pair<std::string,std::string> >&
00406                    fields);
00407     //! Set the debugging ostream
00408     void setOS(std::ostream& os) { d_os = &os; }
00409 
00410     //! Print all the collected data if "DEBUG" flag is set to 'os'
00411     void printAll(std::ostream& os);
00412     /*! @brief Print all the collected data if "DEBUG" flag is set to
00413       the default debug stream */
00414     void printAll() { printAll(*d_os); }
00415 
00416     // Generally useful functions
00417     //! Get the current scope level
00418     int scopeLevel();
00419 
00420   }; // end of class Debug
00421 
00422   extern Debug debugger;
00423 
00424 } // end of namespace CVCL
00425 
00426 #else  // if DEBUG is not defined
00427 
00428 // All debugging macros are empty here
00429 
00430 #define IF_DEBUG(code)
00431 
00432 #define DebugAssert(cond, str)
00433 
00434 #define DBG_PRINT(cond, pre, v, post)
00435 #define TRACE(cond, pre, v, post)
00436 
00437 #define DBG_PRINT_MSG(cond, msg)
00438 #define TRACE_MSG(flag, msg)
00439 
00440 #endif // DEBUG
00441 
00442 #include "cvclutil.h"
00443 
00444 #endif // _CVC_lite__debug_h

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