moab
DebugOutput.cpp
Go to the documentation of this file.
00001 #include "DebugOutput.hpp"
00002 #include "moab/Range.hpp"
00003 #include "moab/CN.hpp"
00004 #include "Internals.hpp"
00005 #include <iostream>
00006 #include <string.h>
00007 #include <algorithm>
00008 #include <assert.h>
00009 
00010 #ifdef USE_MPI
00011 #  include "moab_mpi.h"
00012 #else
00013 #  include "time.h"
00014 #endif
00015 
00016 namespace moab {
00017 
00018 DebugOutputStream::~DebugOutputStream() {}
00019 
00020 class FILEDebugStream : public DebugOutputStream
00021 {
00022 private:
00023   FILE* filePtr;
00024 public:
00025   FILEDebugStream( FILE* filep ) : filePtr(filep) {}
00026   void println( int rank, const char* pfx, const char* str );
00027   void println( const char* pfx, const char* str );
00028 };
00029 void FILEDebugStream::println( int rank, const char* pfx, const char* str )
00030   { fprintf(filePtr, "%3d  %s%s\n", rank, pfx, str); fflush(filePtr); }
00031 void FILEDebugStream::println( const char* pfx, const char* str )
00032   { 
00033     fputs( pfx, filePtr ); 
00034     fputs( str, filePtr ); 
00035     fputc( '\n', filePtr ); 
00036     fflush(filePtr); 
00037   }
00038 
00039 
00040 class CxxDebugStream : public DebugOutputStream
00041 {
00042 private:
00043   std::ostream& outStr;
00044 public:
00045   CxxDebugStream( std::ostream& str ) : outStr(str) {}
00046   void println( int rank, const char* pfx, const char* str );
00047   void println( const char* pfx, const char* str );
00048 };
00049 void CxxDebugStream::println( int rank, const char* pfx, const char* str )
00050   { 
00051     outStr.width(3);
00052     outStr << rank << "  "  << pfx << str << std::endl; 
00053     outStr.flush(); 
00054   }
00055 void CxxDebugStream::println( const char* pfx, const char* str )
00056   { outStr << pfx << str << std::endl; outStr.flush(); }
00057 
00058 #ifdef USE_MPI
00059   #define CURTIME (MPI_Wtime())
00060 #else
00061   #define CURTIME (clock()/(double)CLOCKS_PER_SEC)
00062 #endif
00063 
00064 
00065 DebugOutput::DebugOutput( DebugOutputStream* impl, unsigned verbosity )
00066   : outputImpl(impl), mpiRank(-1), verbosityLimit(verbosity), initTime(CURTIME)
00067     { impl->referenceCount++; assert(impl->referenceCount > 1); }
00068 DebugOutput::DebugOutput( DebugOutputStream* impl, int rank, unsigned verbosity )
00069   : outputImpl(impl), mpiRank(rank), verbosityLimit(verbosity), initTime(CURTIME)
00070     { impl->referenceCount++; assert(impl->referenceCount > 1); }
00071 DebugOutput::DebugOutput( FILE* impl, unsigned verbosity )
00072   : outputImpl(new FILEDebugStream(impl)),
00073     mpiRank(-1), verbosityLimit(verbosity), initTime(CURTIME) {}
00074 DebugOutput::DebugOutput( FILE* impl, int rank, unsigned verbosity )
00075   : outputImpl(new FILEDebugStream(impl)),
00076     mpiRank(rank), verbosityLimit(verbosity), initTime(CURTIME) {}
00077 DebugOutput::DebugOutput( std::ostream& str, unsigned verbosity )
00078   : outputImpl(new CxxDebugStream(str)),
00079     mpiRank(-1), verbosityLimit(verbosity), initTime(CURTIME) {}
00080 DebugOutput::DebugOutput( std::ostream& str, int rank, unsigned verbosity )
00081   : outputImpl(new CxxDebugStream(str)),
00082     mpiRank(rank), verbosityLimit(verbosity), initTime(CURTIME) {}
00083 DebugOutput::DebugOutput( const char* pfx, DebugOutputStream* impl, unsigned verbosity )
00084   : linePfx(pfx), outputImpl(impl), mpiRank(-1), verbosityLimit(verbosity) , initTime(CURTIME)
00085   { impl->referenceCount++; assert(impl->referenceCount > 1); }
00086 DebugOutput::DebugOutput( const char* pfx, DebugOutputStream* impl, int rank, unsigned verbosity )
00087   : linePfx(pfx), outputImpl(impl), mpiRank(rank), verbosityLimit(verbosity), initTime(CURTIME)
00088   { impl->referenceCount++; assert(impl->referenceCount > 1); }
00089 DebugOutput::DebugOutput( const char* pfx, FILE* impl, unsigned verbosity )
00090   : linePfx(pfx), outputImpl(new FILEDebugStream(impl)),
00091     mpiRank(-1), verbosityLimit(verbosity), initTime(CURTIME) {}
00092 DebugOutput::DebugOutput( const char* pfx, FILE* impl, int rank, unsigned verbosity )
00093   : linePfx(pfx), outputImpl(new FILEDebugStream(impl)),
00094     mpiRank(rank), verbosityLimit(verbosity), initTime(CURTIME) {}
00095 DebugOutput::DebugOutput( const char* pfx, std::ostream& str, unsigned verbosity )
00096   : linePfx(pfx), outputImpl(new CxxDebugStream(str)),
00097     mpiRank(-1), verbosityLimit(verbosity), initTime(CURTIME) {}
00098 DebugOutput::DebugOutput( const char* pfx, std::ostream& str, int rank, unsigned verbosity )
00099   : linePfx(pfx), outputImpl(new CxxDebugStream(str)),
00100     mpiRank(rank), verbosityLimit(verbosity), initTime(CURTIME) {}
00101 
00102 DebugOutput::DebugOutput( const DebugOutput& copy )
00103   : linePfx(copy.linePfx), 
00104     outputImpl(copy.outputImpl),
00105     mpiRank(copy.mpiRank),
00106     verbosityLimit(copy.verbosityLimit)
00107 {
00108   outputImpl->referenceCount++; 
00109   assert(outputImpl->referenceCount > 1); 
00110 }
00111 
00112 DebugOutput& DebugOutput::operator=( const DebugOutput& copy )
00113 {
00114   linePfx = copy.linePfx;
00115   outputImpl = copy.outputImpl;
00116   mpiRank = copy.mpiRank;
00117   verbosityLimit = copy.verbosityLimit;
00118   outputImpl->referenceCount++; 
00119   assert(outputImpl->referenceCount > 1); 
00120   return *this;
00121 }
00122 
00123 DebugOutput::~DebugOutput()
00124 { 
00125   if (!lineBuffer.empty()) {
00126     lineBuffer.push_back('\n');
00127     process_line_buffer();
00128   }
00129   if (outputImpl) {
00130     assert(outputImpl->referenceCount > 0);
00131     if (!--outputImpl->referenceCount)
00132       delete outputImpl;
00133     outputImpl = 0;
00134   }
00135 }
00136   
00137 void DebugOutput::use_world_rank() 
00138 {
00139   mpiRank = 0;
00140 #ifdef USE_MPI
00141   MPI_Comm_rank( MPI_COMM_WORLD, &mpiRank );
00142 #endif
00143 }   
00144 
00145 void DebugOutput::print_real( const char* buffer )
00146 {
00147   lineBuffer.insert( lineBuffer.end(), buffer, buffer + strlen(buffer) );
00148   process_line_buffer();
00149 }
00150 
00151 void DebugOutput::tprint_real( const char* buffer )
00152 {
00153   tprint();
00154   print_real( buffer );
00155 }
00156   
00157 void DebugOutput::print_real( const std::string& str )
00158 {
00159   lineBuffer.insert( lineBuffer.end(), str.begin(), str.end() );
00160   process_line_buffer();
00161 }
00162   
00163 void DebugOutput::tprint_real( const std::string& str )
00164 {
00165   tprint();
00166   print_real( str );
00167 }
00168 
00169 void DebugOutput::print_real( const char* fmt, va_list args1, va_list args2 )
00170 {
00171   size_t idx = lineBuffer.size();
00172 #ifdef HAVE_VSNPRINTF
00173     // try once with remaining space in buffer
00174   lineBuffer.resize( lineBuffer.capacity() );
00175   unsigned size = vsnprintf( &lineBuffer[idx], lineBuffer.size() - idx, fmt, args1 );
00176   ++size; // trailing null
00177     // if necessary, increase buffer size and retry
00178   if (size > (lineBuffer.size() - idx)) {
00179     lineBuffer.resize( idx + size );
00180     size = vsnprintf( &lineBuffer[idx], lineBuffer.size() - idx, fmt, args2 );
00181     ++size; // trailing null
00182   }
00183 #else
00184     // Guess how much space might be required.
00185     // If every character is a format code then there are len/3 format codes.
00186     // Guess a random large value of 81 characters per formatted argument.
00187   unsigned exp_size = 27*strlen(fmt);
00188   lineBuffer.resize( idx + exp_size );
00189   unsigned size = vsprintf( &lineBuffer[idx], fmt, args1 );
00190   ++size; // trailing null
00191     // check if we overflowed the buffer
00192   if (size > exp_size) {
00193     // crap!
00194     fprintf(stderr,"ERROR: Buffer overflow at %s:%d\n", __FILE__, __LINE__);
00195     lineBuffer.resize( idx + exp_size );
00196     size = vsprintf( &lineBuffer[idx], fmt, args2 );
00197     ++size; // trailing null
00198   }
00199 #endif
00200 
00201     // less one because we don't want the trailing '\0'
00202   lineBuffer.resize(idx+size-1);
00203   process_line_buffer();
00204 }
00205 
00206 void DebugOutput::tprint_real( const char* fmt, va_list args1, va_list args2 )
00207 {
00208   tprint();
00209   print_real( fmt, args1, args2 );
00210 }
00211 
00212 static void print_range( char* buffer, unsigned long begin, unsigned long end )
00213 {
00214   assert(end > begin);
00215     // begin with a space
00216   *buffer = ' ';
00217   char *b1 = buffer + 1;
00218     // print begin-end, but keep track of where each peice is written
00219   char* e1 = b1 + sprintf(b1,"%lu",begin);
00220   *e1 = '-';
00221   char* b2 = e1+1;
00222   char* e2 = b2 + sprintf(b2,"%lu",end);
00223     // if the printed strings for both numbers don't contain the same
00224     // number of digits, don't do anything more
00225   if (e1-b1 == e2-b2) {
00226      // see how many leading digits the two numbers have in common
00227     char* p = b2;
00228     while (*p && *p == *b1)
00229       { ++p; ++b1; }
00230       // remove common shared leading digits from second number
00231     if (p > b2 && *p) {
00232        // shift second value down so that common leading digits are not repeated
00233       while(*p) {
00234         *b2 = *p;
00235         ++b2;
00236         ++p;
00237       } 
00238       e2 = b2;
00239     }
00240   }
00241     // add trailing comma
00242   *e2 = ',';
00243   ++e2;
00244   *e2 = '\0';
00245 }
00246 
00247 void DebugOutput::list_range_real( const char* pfx, const Range& range )
00248 {
00249   if (pfx) {
00250     lineBuffer.insert( lineBuffer.end(), pfx, pfx+strlen(pfx) );
00251     lineBuffer.push_back(' ');
00252   }
00253 
00254   if (range.empty()) {
00255     print_real("<empty>\n");
00256     return;
00257   }
00258 
00259   char numbuf[48]; // unsigned 64 bit integer can't have more than 20 decimal digits
00260   Range::const_pair_iterator i;
00261   EntityType type = MBMAXTYPE;
00262   for (i = range.const_pair_begin(); i != range.const_pair_end(); ++i) {
00263     if (TYPE_FROM_HANDLE(i->first) != type) {
00264       type = TYPE_FROM_HANDLE(i->first);
00265       const char* name = CN::EntityTypeName(type);
00266       lineBuffer.insert( lineBuffer.end(), name, name+strlen(name) );
00267     }
00268     if (i->first == i->second) 
00269       sprintf(numbuf, " %lu,", (unsigned long)(ID_FROM_HANDLE(i->first)));
00270     else
00271       print_range(numbuf, ID_FROM_HANDLE(i->first), ID_FROM_HANDLE(i->second) );
00272     lineBuffer.insert( lineBuffer.end(), numbuf, numbuf+strlen(numbuf) );
00273   }
00274 
00275   lineBuffer.push_back('\n');
00276   process_line_buffer();
00277 }
00278  
00279 void DebugOutput::list_ints_real( const char* pfx, const Range& range )
00280 {
00281   if (range.empty()) {
00282     print_real("<empty>\n");
00283     return;
00284   }
00285 
00286   if (pfx) {
00287     lineBuffer.insert( lineBuffer.end(), pfx, pfx+strlen(pfx) );
00288     lineBuffer.push_back(' ');
00289   }
00290 
00291   char numbuf[48]; // unsigned 64 bit integer can't have more than 20 decimal digits
00292   Range::const_pair_iterator i;
00293   for (i = range.const_pair_begin(); i != range.const_pair_end(); ++i) {
00294     if (i->first == i->second) 
00295       sprintf(numbuf, " %lu,", (unsigned long)(i->first));
00296     else
00297       print_range(numbuf, (unsigned long)(i->first), (unsigned long)(i->second));
00298     lineBuffer.insert( lineBuffer.end(), numbuf, numbuf+strlen(numbuf) );
00299   }
00300 
00301   lineBuffer.push_back('\n');
00302   process_line_buffer();
00303 }
00304    
00305 void DebugOutput::process_line_buffer()
00306 {
00307   size_t last_idx = 0;
00308   std::vector<char>::iterator i;
00309   for (i = std::find(lineBuffer.begin(), lineBuffer.end(), '\n');
00310        i != lineBuffer.end();  i = std::find(i, lineBuffer.end(), '\n')) {
00311     *i = '\0';
00312     if (have_rank()) 
00313       outputImpl->println( get_rank(), linePfx.c_str(), &lineBuffer[last_idx] );
00314     else
00315       outputImpl->println( linePfx.c_str(), &lineBuffer[last_idx] );
00316     ++i;
00317     last_idx = i - lineBuffer.begin();
00318   }
00319   
00320   if (last_idx) {
00321     i = std::copy( lineBuffer.begin()+last_idx, lineBuffer.end(), lineBuffer.begin() );
00322     lineBuffer.erase( i, lineBuffer.end() );
00323   }
00324 }
00325 
00326 void DebugOutput::tprint()
00327 {
00328   size_t s = lineBuffer.size();
00329   lineBuffer.resize( s + 64 );
00330   size_t ss = sprintf(&lineBuffer[s],"(%.2f s) ", CURTIME-initTime );
00331   lineBuffer.resize( s + ss );
00332 }
00333 
00334 } // namespace moab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines