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