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