1 #ifndef moab_DEBUG_OUTPUT_HPP
2 #define moab_DEBUG_OUTPUT_HPP
3 
4 #include <stdarg.h>
5 #include <stdio.h>
6 #include <vector>
7 #include <iosfwd>
8 #include <string>
9 
10 #include "moab/Compiler.hpp"
11 #include "moab/CpuTimer.hpp"
12 
13 namespace moab {
14 
15 class Range;
16 class DebugOutputStream;
17 
18 /**\brief Utility class for printing debug output
19  *
20  * This class implements line-oriented output.  That is, it buffers
21  * output data until a newline is encountered, at which point it
22  * sends the output to the output stream followed by an explicit
23  * flush, and optionally prefixed with the MPI rank.
24  *
25  * This class also implements a verbosity filter for all output.
26  * The class instance has a verbosity limit.  Each request
27  * for output has an associated verbosity level.  If the verbosity
28  * level for the output is is less greater than the limit then
29  * the output is discarded.  By convetion a verbosity limit
30  * of zero should indicate no output. Therefore all requests
31  * for output should have an associated verbosity level greater
32  * than or equal to one.
33  *
34  * \Note Any output not terminated with an newline character or
35  *       followed by later output containing a newline character
36  *       will not be flushed until the destructor is invoked.
37  * \Note C++-style IO (i.e. std::ostream) is not supported because
38  *       it is necessarily inefficient for debug-type output.  All
39  *       formatting (e.g. converting arguments to strings, etc.) must
40  *       be done even when output is disabled.
41  */
42 class DebugOutput {
43 
44 public:
45 
46   /**
47    *\param str       Output stream to which to flush output
48    *\param verbosity Verbosity limit.
49    */
50   DebugOutput( DebugOutputStream* str, unsigned verbosity = 0 );
51   /**
52    *\param str       Output stream to which to flush output
53    *\param rank      MPI rank with which to prefix output.
54    *\param verbosity Verbosity limit.
55   */
56   DebugOutput( DebugOutputStream* str, int rank, unsigned verbosity = 0 );
57   /**
58    *\param str     Output stream to which to flush output
59    *\param enabled Enable output: if not true, all output operations to nothing.
60    */
61   DebugOutput( FILE* str, unsigned verbosity = 0 );
62   /**
63    *\param str       Output stream to which to flush output
64    *\param rank      MPI rank with which to prefix output.
65    *\param verbosity Verbosity limit.
66    */
67   DebugOutput( FILE* str, int rank, unsigned verbosity = 0 );
68   /**
69    *\param str       Output stream to which to flush output
70    *\param verbosity Verbosity limit.
71    */
72   DebugOutput( std::ostream& str, unsigned verbosity = 0 );
73   /**
74    *\param str       Output stream to which to flush output
75    *\param rank      MPI rank with which to prefix output.
76    *\param verbosity Verbosity limit.
77    */
78   DebugOutput( std::ostream& str, int rank, unsigned verbosity = 0 );
79 
80   /**
81    *\param pfx       Prefix for output
82    *\param str       Output stream to which to flush output
83    *\param verbosity Verbosity limit.
84    */
85   DebugOutput( const char* pfx, DebugOutputStream* str, unsigned verbosity = 0 );
86   /**
87    *\param pfx       Prefix for output
88    *\param str       Output stream to which to flush output
89    *\param rank      MPI rank with which to prefix output.
90    *\param verbosity Verbosity limit.
91   */
92   DebugOutput( const char* pfx, DebugOutputStream* str, int rank, unsigned verbosity = 0 );
93   /**
94    *\param pfx       Prefix for output
95    *\param str     Output stream to which to flush output
96    *\param enabled Enable output: if not true, all output operations to nothing.
97    */
98   DebugOutput( const char* pfx, FILE* str, unsigned verbosity = 0 );
99   /**
100    *\param pfx       Prefix for output
101    *\param str       Output stream to which to flush output
102    *\param rank      MPI rank with which to prefix output.
103    *\param verbosity Verbosity limit.
104    */
105   DebugOutput( const char* pfx, FILE* str, int rank, unsigned verbosity = 0 );
106   /**
107    *\param pfx       Prefix for output
108    *\param str       Output stream to which to flush output
109    *\param verbosity Verbosity limit.
110    */
111   DebugOutput( const char* pfx, std::ostream& str, unsigned verbosity = 0 );
112   /**
113    *\param pfx       Prefix for output
114    *\param str       Output stream to which to flush output
115    *\param rank      MPI rank with which to prefix output.
116    *\param verbosity Verbosity limit.
117    */
118   DebugOutput( const char* pfx, std::ostream& str, int rank, unsigned verbosity = 0 );
119 
120   DebugOutput( const DebugOutput& copy );
121   DebugOutput& operator=( const DebugOutput& copy );
122 
123   /**
124    * Destructor flushes any remaining output that wasn't followed
125    * by a newline character.
126    */
127   ~DebugOutput();
128 
129   //!\brief Check if MPI rank has been set.
have_rank() const130   bool have_rank() const    { return mpiRank >= 0; }
131   //!\brief Get MPI rank.
get_rank() const132   int get_rank() const      { return mpiRank; }
133   //!\brief Set MPI rank.
set_rank(int rank)134   void set_rank( int rank ) { mpiRank  = rank; }
135   //!\brief Set MPI rank to the rank of this proccess in MPI_COMM_WORLD,
136   //!       or zero if MOAB is build w/out MPI.
137   void use_world_rank();
138 
139   //!\brief Only print debug output from N processes
limit_output_to_first_N_procs(int N)140   void limit_output_to_first_N_procs( int N )
141     { if (mpiRank >= N) verbosityLimit = 0; }
142 
143   //!\brief Get verbosity limit
get_verbosity() const144   unsigned get_verbosity() const      { return verbosityLimit; }
145   //!\brief Set verbosity limit
set_verbosity(unsigned val)146   void set_verbosity( unsigned val )   { verbosityLimit = val; }
147 
148   //!\brief Get line prefix
get_prefix() const149   const std::string& get_prefix() const  { return linePfx; }
150   //!\brief Set line prefix
set_prefix(const std::string & str)151   void set_prefix(const std::string& str) { linePfx = str; }
152 
153   //!\brief Output the specified string iff output is enabled.
print(int verbosity,const char * str)154   void print( int verbosity, const char* str )
155     { if (check(verbosity)) print_real(str); }
156 
157   //!\brief Output the specified string iff output is enabled.
print(int verbosity,const std::string & str)158   void print( int verbosity, const std::string& str )
159     { if (check(verbosity)) print_real(str); }
160 
161   //!\brief Output the specified printf-formatted output iff output is enabled
162   inline void printf( int verbosity, const char* fmt, ... ) MB_PRINTF(2);
163 
164   //!\brief Output the specified string iff output is enabled.
165   //!
166   //! Include current CPU time (as returned by clock()) in output.
tprint(int verbosity,const char * str)167   void tprint( int verbosity, const char* str )
168     { if (check(verbosity)) tprint_real(str); }
169 
170   //!\brief Output the specified string iff output is enabled.
171   //!
172   //! Include current CPU time (as returned by clock()) in output.
tprint(int verbosity,const std::string & str)173   void tprint( int verbosity, const std::string& str )
174     { if (check(verbosity)) tprint_real(str); }
175 
176   //!\brief Output the specified printf-formatted output iff output is enabled
177   //!
178   //! Include current CPU time (as returned by clock()) in output.
179   inline void tprintf( int verbosity, const char* fmt, ... ) MB_PRINTF(2);
180 
181 
182   //!\brief Print the contents of a moab::Range
183   //!\param pfx String to print after default class prefix and before range contents
print(int verbosity,const char * pfx,const Range & range)184   void print( int verbosity, const char* pfx, const Range& range )
185     { if (check(verbosity)) list_range_real( pfx, range ); }
186   //!\brief Print the contents of a moab::Range
print(int verbosity,const Range & range)187   void print( int verbosity, const Range& range )
188     { if (check(verbosity)) list_range_real( 0, range ); }
189 
190   //!\brief Print the contents of a moab::Range as numerical values only
191   //!\param pfx String to print after default class prefix and before range contents
print_ints(int verbosity,const char * pfx,const Range & range)192   void print_ints( int verbosity, const char* pfx, const Range& range )
193     { if (check(verbosity)) list_ints_real( pfx, range ); }
194   //!\brief Print the contents of a moab::Range as numerical values only
print_ints(int verbosity,const Range & range)195   void print_ints( int verbosity, const Range& range )
196     { if (check(verbosity)) list_ints_real( 0, range ); }
197 
198 private:
199 
200   std::string linePfx;
201   DebugOutputStream *outputImpl;
202   int mpiRank;
203   unsigned verbosityLimit;
204   CpuTimer cpuTi;
205 
206   void tprint();
207 
208   void list_range_real( const char* pfx, const Range& range );
209   void list_ints_real( const char* pfx, const Range& range );
210   void print_real( const char* buffer );
211   void print_real( const std::string& str );
212   void tprint_real( const char* buffer );
213   void tprint_real( const std::string& str );
214 
215   // Function must be passed to copies of the same va_list because
216   // a) it might have to call vs(n)printf twice, b) vs(n)printf modifies
217   // the va_list such that it cannot be reused, and c) va_copy is not
218   // (yet) portable (c99, no c++ standard).
219   void print_real( const char* buffer, va_list args1, va_list args2 );
220   void tprint_real( const char* buffer, va_list args1, va_list args2 );
221   void process_line_buffer();
222 
223   std::vector<char> lineBuffer;
224 
check(unsigned verbosity)225   inline bool check(unsigned verbosity)
226     { return verbosity <= verbosityLimit; }
227 };
228 
229 
230 class DebugOutputStream {
231 protected:
232   friend class DebugOutput;
233   int referenceCount;
234 public:
DebugOutputStream()235   DebugOutputStream() : referenceCount(1) {}
236   virtual ~DebugOutputStream();
237   virtual void println( const char* pfx, const char* str ) = 0;
238   virtual void println( int rank, const char* pfx, const char* str ) = 0;
239 };
240 
printf(int verbosity,const char * fmt,...)241 void DebugOutput::printf( int verbosity, const char* fmt, ... )
242 {
243   if (check(verbosity)) {
244     va_list args1, args2;
245     va_start(args1, fmt);
246     va_start(args2, fmt);
247     print_real(fmt, args1, args2);
248     va_end(args2);
249     va_end(args1);
250   }
251 }
252 
tprintf(int verbosity,const char * fmt,...)253 void DebugOutput::tprintf( int verbosity, const char* fmt, ... )
254 {
255   if (check(verbosity)) {
256     va_list args1, args2;
257     va_start(args1, fmt);
258     va_start(args2, fmt);
259     tprint_real(fmt, args1, args2);
260     va_end(args2);
261     va_end(args1);
262   }
263 }
264 
265 } // namespace moab
266 
267 #endif
268