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