Loading [MathJax]/extensions/tex2jax.js
Mesh Oriented datABase  (version 5.5.1)
An array-based unstructured mesh library
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
DebugOutput.cpp
Go to the documentation of this file.
1 #include "DebugOutput.hpp" 2 #include "moab/MOABConfig.h" 3 #include "moab/Range.hpp" 4 #include "moab/CN.hpp" 5 #include "Internals.hpp" 6  7 #include <iostream> 8 #include <cstring> 9 #include <algorithm> 10 #include <cassert> 11  12 namespace moab 13 { 14  15 DebugOutputStream::~DebugOutputStream() {} 16  17 class FILEDebugStream : public DebugOutputStream 18 { 19  private: 20  FILE* filePtr; 21  22  public: 23  FILEDebugStream( FILE* filep ) : filePtr( filep ) {} 24  void println( int rank, const char* pfx, const char* str ); 25  void println( const char* pfx, const char* str ); 26 }; 27 void FILEDebugStream::println( int rank, const char* pfx, const char* str ) 28 { 29  fprintf( filePtr, "%3d %s%s\n", rank, pfx, str ); 30  fflush( filePtr ); 31 } 32 void FILEDebugStream::println( const char* pfx, const char* str ) 33 { 34  fputs( pfx, filePtr ); 35  fputs( str, filePtr ); 36  fputc( '\n', filePtr ); 37  fflush( filePtr ); 38 } 39  40 class CxxDebugStream : public DebugOutputStream 41 { 42  private: 43  std::ostream& outStr; 44  45  public: 46  CxxDebugStream( std::ostream& str ) : outStr( str ) {} 47  void println( int rank, const char* pfx, const char* str ); 48  void println( const char* pfx, const char* str ); 49 }; 50 void CxxDebugStream::println( int rank, const char* pfx, const char* str ) 51 { 52  outStr.width( 3 ); 53  outStr << rank << " " << pfx << str << std::endl; 54  outStr.flush(); 55 } 56 void CxxDebugStream::println( const char* pfx, const char* str ) 57 { 58  outStr << pfx << str << std::endl; 59  outStr.flush(); 60 } 61  62 DebugOutput::DebugOutput( DebugOutputStream* impl, unsigned verbosity ) 63  : outputImpl( impl ), mpiRank( -1 ), verbosityLimit( verbosity ) 64 { 65  impl->referenceCount++; 66  assert( impl->referenceCount > 1 ); 67 } 68 DebugOutput::DebugOutput( DebugOutputStream* impl, int rank, unsigned verbosity ) 69  : outputImpl( impl ), mpiRank( rank ), verbosityLimit( verbosity ) 70 { 71  impl->referenceCount++; 72  assert( impl->referenceCount > 1 ); 73 } 74 DebugOutput::DebugOutput( FILE* impl, unsigned verbosity ) 75  : outputImpl( new FILEDebugStream( impl ) ), mpiRank( -1 ), verbosityLimit( verbosity ) 76 { 77 } 78 DebugOutput::DebugOutput( FILE* impl, int rank, unsigned verbosity ) 79  : outputImpl( new FILEDebugStream( impl ) ), mpiRank( rank ), verbosityLimit( verbosity ) 80 { 81 } 82 DebugOutput::DebugOutput( std::ostream& str, unsigned verbosity ) 83  : outputImpl( new CxxDebugStream( str ) ), mpiRank( -1 ), verbosityLimit( verbosity ) 84 { 85 } 86 DebugOutput::DebugOutput( std::ostream& str, int rank, unsigned verbosity ) 87  : outputImpl( new CxxDebugStream( str ) ), mpiRank( rank ), verbosityLimit( verbosity ) 88 { 89 } 90 DebugOutput::DebugOutput( const char* pfx, DebugOutputStream* impl, unsigned verbosity ) 91  : linePfx( pfx ), outputImpl( impl ), mpiRank( -1 ), verbosityLimit( verbosity ) 92 { 93  impl->referenceCount++; 94  assert( impl->referenceCount > 1 ); 95 } 96 DebugOutput::DebugOutput( const char* pfx, DebugOutputStream* impl, int rank, unsigned verbosity ) 97  : linePfx( pfx ), outputImpl( impl ), mpiRank( rank ), verbosityLimit( verbosity ) 98 { 99  impl->referenceCount++; 100  assert( impl->referenceCount > 1 ); 101 } 102 DebugOutput::DebugOutput( const char* pfx, FILE* impl, unsigned verbosity ) 103  : linePfx( pfx ), outputImpl( new FILEDebugStream( impl ) ), mpiRank( -1 ), verbosityLimit( verbosity ) 104 { 105 } 106 DebugOutput::DebugOutput( const char* pfx, FILE* impl, int rank, unsigned verbosity ) 107  : linePfx( pfx ), outputImpl( new FILEDebugStream( impl ) ), mpiRank( rank ), verbosityLimit( verbosity ) 108 { 109 } 110 DebugOutput::DebugOutput( const char* pfx, std::ostream& str, unsigned verbosity ) 111  : linePfx( pfx ), outputImpl( new CxxDebugStream( str ) ), mpiRank( -1 ), verbosityLimit( verbosity ) 112 { 113 } 114 DebugOutput::DebugOutput( const char* pfx, std::ostream& str, int rank, unsigned verbosity ) 115  : linePfx( pfx ), outputImpl( new CxxDebugStream( str ) ), mpiRank( rank ), verbosityLimit( verbosity ) 116 { 117 } 118  119 DebugOutput::DebugOutput( const DebugOutput& copy ) 120  : linePfx( copy.linePfx ), outputImpl( copy.outputImpl ), mpiRank( copy.mpiRank ), 121  verbosityLimit( copy.verbosityLimit ) 122 { 123  outputImpl->referenceCount++; 124  assert( outputImpl->referenceCount > 1 ); 125 } 126  127 DebugOutput& DebugOutput::operator=( const DebugOutput& copy ) 128 { 129  linePfx = copy.linePfx; 130  outputImpl = copy.outputImpl; 131  mpiRank = copy.mpiRank; 132  verbosityLimit = copy.verbosityLimit; 133  outputImpl->referenceCount++; 134  assert( outputImpl->referenceCount > 1 ); 135  return *this; 136 } 137  138 DebugOutput::~DebugOutput() 139 { 140  if( !lineBuffer.empty() ) 141  { 142  lineBuffer.push_back( '\n' ); 143  process_line_buffer(); 144  } 145  if( outputImpl ) 146  { 147  assert( outputImpl->referenceCount > 0 ); 148  if( !--outputImpl->referenceCount ) delete outputImpl; 149  outputImpl = 0; 150  } 151 } 152  153 void DebugOutput::use_world_rank() 154 { 155  mpiRank = 0; 156 #ifdef MOAB_HAVE_MPI 157  int flag = 0; 158  if( MPI_SUCCESS == MPI_Initialized( &flag ) && flag ) MPI_Comm_rank( MPI_COMM_WORLD, &mpiRank ); 159 #endif 160 } 161  162 void DebugOutput::print_real( const char* buffer ) 163 { 164  lineBuffer.insert( lineBuffer.end(), buffer, buffer + strlen( buffer ) ); 165  process_line_buffer(); 166 } 167  168 void DebugOutput::tprint_real( const char* buffer ) 169 { 170  tprint(); 171  print_real( buffer ); 172 } 173  174 void DebugOutput::print_real( const std::string& str ) 175 { 176  lineBuffer.insert( lineBuffer.end(), str.begin(), str.end() ); 177  process_line_buffer(); 178 } 179  180 void DebugOutput::tprint_real( const std::string& str ) 181 { 182  tprint(); 183  print_real( str ); 184 } 185  186 void DebugOutput::print_real( const char* fmt, va_list args1, va_list args2 ) 187 { 188  size_t idx = lineBuffer.size(); 189 #ifdef MOAB_HAVE_VSNPRINTF 190  // try once with remaining space in buffer 191  lineBuffer.resize( lineBuffer.capacity() ); 192  unsigned size = vsnprintf( &lineBuffer[idx], lineBuffer.size() - idx, fmt, args1 ); 193  ++size; // trailing null 194  // if necessary, increase buffer size and retry 195  if( size > ( lineBuffer.size() - idx ) ) 196  { 197  lineBuffer.resize( idx + size ); 198  size = vsnprintf( &lineBuffer[idx], lineBuffer.size() - idx, fmt, args2 ); 199  ++size; // trailing null 200  } 201 #else 202  // Guess how much space might be required. 203  // If every character is a format code then there are len/3 format codes. 204  // Guess a random large value of num_chars characters per formatted argument. 205  const unsigned num_chars = 180; 206  unsigned exp_size = ( num_chars / 3 ) * strlen( fmt ); 207  lineBuffer.resize( idx + exp_size ); 208  unsigned size = vsnprintf( &lineBuffer[idx], exp_size, fmt, args1 ); 209  ++size; // trailing null 210  // check if we overflowed the buffer 211  if( size > exp_size ) 212  { 213  // crap! 214  fprintf( stderr, "ERROR: Buffer overflow at %s:%d\n", __FILE__, __LINE__ ); 215  lineBuffer.resize( idx + exp_size ); 216  size = vsnprintf( &lineBuffer[idx], exp_size, fmt, args2 ); 217  ++size; // trailing null 218  } 219 #endif 220  221  // less one because we don't want the trailing '\0' 222  lineBuffer.resize( idx + size - 1 ); 223  process_line_buffer(); 224 } 225  226 void DebugOutput::tprint_real( const char* fmt, va_list args1, va_list args2 ) 227 { 228  tprint(); 229  print_real( fmt, args1, args2 ); 230 } 231  232 static void print_range( char* buffer, int len, unsigned long begin, unsigned long end ) 233 { 234  assert( end > begin ); 235  // begin with a space 236  *buffer = ' '; 237  char* b1 = buffer + 1; 238  // print begin-end, but keep track of where each peice is written 239  char* e1 = b1 + snprintf( b1, len, "%lu", begin ); 240  *e1 = '-'; 241  char* b2 = e1 + 1; 242  char* e2 = b2 + snprintf( b2, len, "%lu", end ); 243  // if the printed strings for both numbers don't contain the same 244  // number of digits, don't do anything more 245  if( e1 - b1 == e2 - b2 ) 246  { 247  // see how many leading digits the two numbers have in common 248  char* p = b2; 249  while( *p && *p == *b1 ) 250  { 251  ++p; 252  ++b1; 253  } 254  // remove common shared leading digits from second number 255  if( p > b2 && *p ) 256  { 257  // shift second value down so that common leading digits are not repeated 258  while( *p ) 259  { 260  *b2 = *p; 261  ++b2; 262  ++p; 263  } 264  e2 = b2; 265  } 266  } 267  // add trailing comma 268  *e2 = ','; 269  ++e2; 270  *e2 = '\0'; 271 } 272  273 void DebugOutput::list_range_real( const char* pfx, const Range& range ) 274 { 275  if( pfx ) 276  { 277  lineBuffer.insert( lineBuffer.end(), pfx, pfx + strlen( pfx ) ); 278  lineBuffer.push_back( ' ' ); 279  } 280  281  if( range.empty() ) 282  { 283  print_real( "<empty>\n" ); 284  return; 285  } 286  287  char numbuf[48]; // unsigned 64 bit integer can't have more than 20 decimal digits 288  Range::const_pair_iterator i; 289  EntityType type = MBMAXTYPE; 290  for( i = range.const_pair_begin(); i != range.const_pair_end(); ++i ) 291  { 292  if( TYPE_FROM_HANDLE( i->first ) != type ) 293  { 294  type = TYPE_FROM_HANDLE( i->first ); 295  const char* name = CN::EntityTypeName( type ); 296  lineBuffer.insert( lineBuffer.end(), name, name + strlen( name ) ); 297  } 298  if( i->first == i->second ) 299  snprintf( numbuf, 48, " %lu,", (unsigned long)( ID_FROM_HANDLE( i->first ) ) ); 300  else 301  print_range( numbuf, 48, ID_FROM_HANDLE( i->first ), ID_FROM_HANDLE( i->second ) ); 302  lineBuffer.insert( lineBuffer.end(), numbuf, numbuf + strlen( numbuf ) ); 303  } 304  305  lineBuffer.push_back( '\n' ); 306  process_line_buffer(); 307 } 308  309 void DebugOutput::list_ints_real( const char* pfx, const Range& range ) 310 { 311  if( range.empty() ) 312  { 313  print_real( "<empty>\n" ); 314  return; 315  } 316  317  if( pfx ) 318  { 319  lineBuffer.insert( lineBuffer.end(), pfx, pfx + strlen( pfx ) ); 320  lineBuffer.push_back( ' ' ); 321  } 322  323  char numbuf[48]; // unsigned 64 bit integer can't have more than 20 decimal digits 324  Range::const_pair_iterator i; 325  for( i = range.const_pair_begin(); i != range.const_pair_end(); ++i ) 326  { 327  if( i->first == i->second ) 328  snprintf( numbuf, 48, " %lu,", (unsigned long)( i->first ) ); 329  else 330  print_range( numbuf, 48, (unsigned long)( i->first ), (unsigned long)( i->second ) ); 331  lineBuffer.insert( lineBuffer.end(), numbuf, numbuf + strlen( numbuf ) ); 332  } 333  334  lineBuffer.push_back( '\n' ); 335  process_line_buffer(); 336 } 337  338 void DebugOutput::process_line_buffer() 339 { 340  size_t last_idx = 0; 341  std::vector< char >::iterator i; 342  for( i = std::find( lineBuffer.begin(), lineBuffer.end(), '\n' ); i != lineBuffer.end(); 343  i = std::find( i, lineBuffer.end(), '\n' ) ) 344  { 345  *i = '\0'; 346  if( have_rank() ) 347  outputImpl->println( get_rank(), linePfx.c_str(), &lineBuffer[last_idx] ); 348  else 349  outputImpl->println( linePfx.c_str(), &lineBuffer[last_idx] ); 350  ++i; 351  last_idx = i - lineBuffer.begin(); 352  } 353  354  if( last_idx ) 355  { 356  i = std::copy( lineBuffer.begin() + last_idx, lineBuffer.end(), lineBuffer.begin() ); 357  lineBuffer.erase( i, lineBuffer.end() ); 358  } 359 } 360  361 void DebugOutput::tprint() 362 { 363  size_t s = lineBuffer.size(); 364  lineBuffer.resize( s + 64 ); 365  size_t ss = snprintf( &lineBuffer[s], 64, "(%.2f s) ", cpuTi.time_since_birth() ); 366  lineBuffer.resize( s + ss ); 367 } 368  369 } // namespace moab