MOAB: Mesh Oriented datABase
(version 5.4.1)
|
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