common/omdebug.h

Go to the documentation of this file.
00001 /* omdebug.h: Provide debugging message facilities
00002  *
00003  * Copyright 1999,2000,2001 BrightStation PLC
00004  * Copyright 2002 Ananova Ltd
00005  * Copyright 2003,2004,2005,2006,2007,2008 Olly Betts
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License as
00009  * published by the Free Software Foundation; either version 2 of the
00010  * License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
00020  * USA
00021  */
00022 
00023 // Note: we use macros to define our assertions, since with a template
00024 // approach the location strings typically don't get thrown away by the
00025 // compiler.
00026 
00027 #ifndef OM_HGUARD_OMDEBUG_H
00028 #define OM_HGUARD_OMDEBUG_H
00029 
00030 #ifdef XAPIAN_DEBUG_VERBOSE
00031 
00032 #include <xapian/visibility.h>
00033 
00034 #include "omtime.h"
00035 #include "output.h"
00036 #include "stringutils.h" // For STRINGIZE().
00037 
00038 #include <iomanip>
00039 #include <sstream>
00040 #include <vector>
00041 
00042 #include "safeunistd.h"
00043 
00044 inline std::ostream &
00045 operator<<(std::ostream & os, const OmTime & om_time) {
00046     return os << om_time.sec << '.' << std::setw(6) << std::setfill('0') << om_time.usec;
00047 }
00048 
00052 enum om_debug_types {
00056     OM_DEBUG_UNKNOWN,
00057 
00059     OM_DEBUG_DUMMY,
00060 
00063     OM_DEBUG_DB,
00064 
00067     OM_DEBUG_MATCH,
00068 
00071     OM_DEBUG_EXPAND,
00072 
00075     OM_DEBUG_WTCALC,
00076 
00079     OM_DEBUG_API,
00080 
00084     OM_DEBUG_APICALL,
00085 
00088     OM_DEBUG_EXCEPTION,
00089 
00092     OM_DEBUG_DBLOCK,
00093 
00096     OM_DEBUG_INDEXER,
00097 
00099     OM_DEBUG_DUMMY2,
00100 
00102     OM_DEBUG_REMOTE,
00103 
00105     OM_DEBUG_QUERYPARSER,
00106 
00108     OM_DEBUG_SPELLING,
00109 
00112     OM_DEBUG_NUMTYPES
00113 };
00114 
00117 class XAPIAN_VISIBILITY_DEFAULT OmDebug {
00118     private:
00120         OmDebug(OmDebug &);
00121 
00123         void operator=(OmDebug &);
00124 
00126         bool initialised;
00127 
00133         unsigned int wanted_types;
00134 
00136         int fd;
00137 
00138     public:
00140         void display_message(enum om_debug_types type, std::string msg);
00141 
00143         bool want_type(enum om_debug_types type);
00144 
00146         void initialise();
00147 
00149         OmDebug();
00150 
00152         ~OmDebug();
00153 };
00154 
00155 XAPIAN_VISIBILITY_DEFAULT
00156 extern OmDebug om_debug;
00157 
00159 // Don't bracket b, because it may have <<'s in it
00160 #define DEBUGMSG2(a,b) do { \
00161     if (om_debug.want_type(a)) { \
00162         std::ostringstream os; \
00163         os << b; \
00164         om_debug.display_message(a, os.str()); \
00165     } \
00166 } while (0)
00167 
00168 #define DEBUGLINE2(a,b) DEBUGMSG2(a, "Xapian " << getpid() << ": " << b << '\n')
00169 
00172 class OmDebugCall {
00173     private:
00175         std::string methodname;
00176 
00178         std::string returnval;
00179 
00181         enum om_debug_types type;
00182     public:
00184         OmDebugCall(enum om_debug_types type_,
00185                     std::string methodname_,
00186                     std::string params)
00187                 : methodname(methodname_),
00188                   type(type_)
00189         {
00190             DEBUGLINE2(type, methodname << "(" << params << ") called");
00191         }
00192 
00194         void setreturnval(std::string returnval_) { returnval = returnval_; }
00195 
00197         ~OmDebugCall() {
00198             DEBUGLINE2(type, methodname << "() returning " << returnval);
00199         }
00200 };
00201 
00205 #define DEBUGCALL(t,r,a,b) \
00206     std::string omdebugapicall_str; \
00207     std::string omdebugapicall_method; \
00208     typedef r omdebugapicallreturn_t; \
00209     if (om_debug.want_type(OM_DEBUG_##t)) { \
00210         std::ostringstream os1; \
00211         os1 << "[" << static_cast<const void*>(this) << "] " << STRINGIZE(r) << " " << a; \
00212         omdebugapicall_method = os1.str(); \
00213         std::ostringstream os2; \
00214         os2 << b; \
00215         omdebugapicall_str = os2.str(); \
00216     } \
00217     OmDebugCall omdebugapicall(OM_DEBUG_##t, omdebugapicall_method, omdebugapicall_str);
00218 
00221 #define DEBUGCALL_STATIC(t,r,a,b) \
00222     std::string omdebugapicall_str; \
00223     std::string omdebugapicall_method; \
00224     typedef r omdebugapicallreturn_t; \
00225     if (om_debug.want_type(OM_DEBUG_##t)) { \
00226         std::ostringstream os1; \
00227         os1 << "[static   ] " << STRINGIZE(r) << " " << a; \
00228         omdebugapicall_method = os1.str(); \
00229         std::ostringstream os2; \
00230         os2 << b; \
00231         omdebugapicall_str = os2.str(); \
00232     } \
00233     OmDebugCall omdebugapicall(OM_DEBUG_##t, omdebugapicall_method, omdebugapicall_str);
00234 
00235 #define RETURN(A) do { \
00236     omdebugapicallreturn_t omdebugapicallreturn = A; \
00237     std::ostringstream os; \
00238     os << omdebugapicallreturn; \
00239     omdebugapicall.setreturnval(os.str()); \
00240     return omdebugapicallreturn; \
00241 } while (0)
00242 
00243 #define DEBUGMSG(a,b) DEBUGMSG2(OM_DEBUG_##a, b)
00244 #define DEBUGLINE(a,b) DEBUGLINE2(OM_DEBUG_##a, b)
00245 
00246 using std::endl;
00247 
00248 #elif defined(XAPIAN_DEBUG_PROFILE)
00249 
00250 #define DEBUGMSG(a,b) (void)0
00251 #define DEBUGLINE(a,b) (void)0
00252 #define RETURN(A) return A
00253 
00254 #include <cstdio>  // For fprintf().
00255 #include <cstdlib> // For abort().
00256 #include <sys/time.h>
00257 
00258 #include <list>
00259 #include <string>
00260 
00261 namespace Xapian {
00262 namespace Internal {
00263 
00264 class Timer {
00265     private:
00266         std::string call;
00267 
00268         // time routine entered (to subtract from parent)
00269         struct timeval entry;
00270 
00271         // time routine started executing
00272         struct timeval start;
00273 
00274         // dead time (time spent paused in subroutines)
00275         struct timeval dead;
00276 
00277         // kids time (time spent running in subroutines)
00278         struct timeval kids;
00279 
00280         // time pause() called
00281         static struct timeval paused;
00282 
00283         // pointer to start time so resume can start the clock
00284         static struct timeval * pstart;
00285 
00286         static std::list<Timer *> stack;
00287 
00288         static int depth;
00289 
00290     public:
00291         Timer(const std::string &call_) : call(call_) {
00292             stack.push_back(this);
00293             depth++;
00294             entry = paused;
00295             pstart = &start;
00296             timerclear(&dead);
00297             timerclear(&kids);
00298         }
00299 
00300         ~Timer() {
00301             gettimeofday(&paused, NULL);
00302             {
00303                 if (stack.empty()) std::abort();
00304                 stack.pop_back();
00305                 depth--;
00306 
00307                 // running time is paused - start - dead
00308                 int runu = paused.tv_usec - start.tv_usec - dead.tv_usec;
00309                 int runs = paused.tv_sec - start.tv_sec - dead.tv_sec;
00310                 runs += runu / 1000000;
00311                 runu %= 1000000;
00312                 if (runu < 0) {
00313                     runu += 1000000;
00314                     runs--;
00315                 }
00316 
00317                 if (!stack.empty()) {
00318                     struct timeval * k = &(stack.back()->kids);
00319                     k->tv_sec += runs;
00320                     k->tv_usec += runu;
00321                 }
00322 
00323                 // subtract time spent in kids
00324                 int myu = runu - kids.tv_usec;
00325                 int mys = runs - kids.tv_sec;
00326                 mys += myu / 1000000;
00327                 myu %= 1000000;
00328                 if (myu < 0) {
00329                     myu += 1000000;
00330                     mys--;
00331                 }
00332                 std::fprintf(stderr, "% 5d.%06d % 5d.%06d %-*s%s\n",
00333                              runs, runu, mys, myu, depth, "", call.c_str());
00334             }
00335 
00336             // subtract entry from start (dead time 1)
00337             int usec = start.tv_usec - entry.tv_usec;
00338             int sec = start.tv_sec - entry.tv_sec;
00339             sec += usec / 1000000;
00340             usec %= 1000000;
00341             if (usec < 0) {
00342                 usec += 1000000;
00343                 sec--;
00344             }
00345 
00346             // dead time for subroutines
00347             usec += dead.tv_usec;
00348             sec += dead.tv_sec;
00349 
00350             // subtract paused (dead time 2 part a)
00351             usec -= paused.tv_usec;
00352             sec -= paused.tv_sec;
00353 
00354             pstart = NULL;
00355             struct timeval * d = NULL;
00356             if (!stack.empty()) {
00357                 d = &(stack.back()->dead);
00358                 d->tv_sec += sec;
00359                 d->tv_usec += usec;
00360             }
00361             gettimeofday(&paused, NULL);
00362             if (d) {
00363                 d->tv_sec += paused.tv_sec;
00364                 d->tv_usec += paused.tv_usec;
00365             }
00366         }
00367 
00368         static void pause() {
00369             gettimeofday(&paused, NULL);
00370         }
00371 
00372         static void resume() {
00373             if (pstart == NULL) std::abort();
00374             gettimeofday(pstart, NULL);
00375         }
00376 };
00377 
00378 }
00379 }
00380 
00384 #define DEBUGCALL(t,r,a,b) \
00385     Xapian::Internal::Timer::pause(); \
00386     Xapian::Internal::Timer om_time_call(a); \
00387     Xapian::Internal::Timer::resume();
00388 
00389 #define DEBUGCALL_STATIC(t,r,a,b) \
00390     Xapian::Internal::Timer::pause(); \
00391     Xapian::Internal::Timer om_time_call(a); \
00392     Xapian::Internal::Timer::resume();
00393 
00394 #else
00395 
00396 #define DEBUGMSG(a,b) (void)0
00397 #define DEBUGLINE(a,b) (void)0
00398 #define RETURN(A) return A
00399 
00400 #define DEBUGCALL(r,t,a,b) (void)0
00401 #define DEBUGCALL_STATIC(r,t,a,b) (void)0
00402 #endif /* XAPIAN_DEBUG_VERBOSE */
00403 
00404 #define DEBUGAPICALL(r,a,b) DEBUGCALL(APICALL,r,a,b)
00405 #define DEBUGAPICALL_STATIC(r,a,b) DEBUGCALL_STATIC(APICALL,r,a,b)
00406 #define DebugMsg(a) DEBUGMSG(UNKNOWN, a)
00407 
00408 #endif /* OM_HGUARD_OMDEBUG_H */

Documentation for Xapian (version 1.0.10).
Generated on 24 Dec 2008 by Doxygen 1.5.2.