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