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
191 lineBuffer.resize( lineBuffer.capacity() );
192 unsigned size = vsnprintf( &lineBuffer[idx], lineBuffer.size() - idx, fmt, args1 );
193 ++size;
194
195 if( size > ( lineBuffer.size() - idx ) )
196 {
197 lineBuffer.resize( idx + size );
198 size = vsnprintf( &lineBuffer[idx], lineBuffer.size() - idx, fmt, args2 );
199 ++size;
200 }
201 #else
202
203
204
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;
210
211 if( size > exp_size )
212 {
213
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;
218 }
219 #endif
220
221
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
236 *buffer = ' ';
237 char* b1 = buffer + 1;
238
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
244
245 if( e1 - b1 == e2 - b2 )
246 {
247
248 char* p = b2;
249 while( *p && *p == *b1 )
250 {
251 ++p;
252 ++b1;
253 }
254
255 if( p > b2 && *p )
256 {
257
258 while( *p )
259 {
260 *b2 = *p;
261 ++b2;
262 ++p;
263 }
264 e2 = b2;
265 }
266 }
267
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];
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];
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 }