Mesh Oriented datABase  (version 5.5.1)
An array-based unstructured mesh library
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 
16 
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 
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 
120  : linePfx( copy.linePfx ), outputImpl( copy.outputImpl ), mpiRank( copy.mpiRank ),
121  verbosityLimit( copy.verbosityLimit )
122 {
124  assert( outputImpl->referenceCount > 1 );
125 }
126 
128 {
129  linePfx = copy.linePfx;
130  outputImpl = copy.outputImpl;
131  mpiRank = copy.mpiRank;
134  assert( outputImpl->referenceCount > 1 );
135  return *this;
136 }
137 
139 {
140  if( !lineBuffer.empty() )
141  {
142  lineBuffer.push_back( '\n' );
144  }
145  if( outputImpl )
146  {
147  assert( outputImpl->referenceCount > 0 );
148  if( !--outputImpl->referenceCount ) delete outputImpl;
149  outputImpl = 0;
150  }
151 }
152 
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 ) );
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() );
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 );
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
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' );
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
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' );
336 }
337 
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 
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