Reference documentation for deal.II version 8.5.1
logstream.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 1998 - 2017 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE at
12 // the top level of the deal.II distribution.
13 //
14 // ---------------------------------------------------------------------
15 
16 #include <deal.II/base/logstream.h>
17 #include <deal.II/base/job_identifier.h>
18 #include <deal.II/base/memory_consumption.h>
19 #include <deal.II/base/thread_management.h>
20 
21 #ifdef DEAL_II_HAVE_SYS_RESOURCE_H
22 # include <sys/resource.h>
23 #endif
24 
25 #ifdef DEAL_II_HAVE_UNISTD_H
26 # include <unistd.h>
27 #endif
28 
29 #include <iostream>
30 #include <iomanip>
31 #include <fstream>
32 #include <sstream>
33 
34 
35 DEAL_II_NAMESPACE_OPEN
36 
37 namespace
38 {
39  Threads::Mutex log_lock;
40  Threads::Mutex write_lock;
41 }
42 
43 
44 // The standard log object of deal.II:
45 LogStream deallog;
46 
47 
49  :
50  std_out(&std::cerr),
51  file(0),
52  std_depth(0),
53  file_depth(10000),
54  print_utime(false),
55  diff_utime(false),
56  last_time (0.),
57  double_threshold(0.),
58  float_threshold(0.),
59  offset(0),
60  print_thread_id(false),
61  old_cerr(0),
62  at_newline(true)
63 {
64  get_prefixes().push("DEAL:");
65 
66 #if defined(DEAL_II_HAVE_UNISTD_H) && defined(DEAL_II_HAVE_TIMES)
67  reference_time_val = 1./sysconf(_SC_CLK_TCK) * times(&reference_tms);
68 #endif
69 
70 }
71 
72 
74 {
75  // if there was anything left in the stream that is current to this
76  // thread, make sure we flush it before it gets lost
77  {
78  if (get_stream().str().length() > 0)
79  {
80  // except the situation is not quite that simple. if this object is
81  // the 'deallog' object, then it is destroyed upon exit of the
82  // program. since it's defined in a shared library that depends on
83  // libstdc++.so, destruction happens before destruction of
84  // std::cout/cerr, but after all file variables defined in user
85  // programs have been destroyed. in other words, if we get here and
86  // the object being destroyed is 'deallog' and if 'deallog' is
87  // associated with a file stream, then we're in trouble: we'll try
88  // to write to a file that doesn't exist any more, and we're likely
89  // going to crash (this is tested by base/log_crash_01). rather
90  // than letting it come to this, print a message to the screen
91  // (note that we can't issue an assertion here either since Assert
92  // may want to write to 'deallog' itself, and AssertThrow will
93  // throw an exception that can't be caught)
94  if ((this == &deallog) && file)
95  std::cerr << ("You still have content that was written to 'deallog' "
96  "but not flushed to the screen or a file while the "
97  "program is being terminated. This would lead to a "
98  "segmentation fault. Make sure you flush the "
99  "content of the 'deallog' object using 'std::endl' "
100  "before the end of the program.")
101  << std::endl;
102  else
103  *this << std::endl;
104  }
105  }
106 
107  if (old_cerr)
108  std::cerr.rdbuf(old_cerr);
109 }
110 
111 
112 void
113 LogStream::test_mode(const bool on,
114  const double double_threshold_,
115  const float float_threshold_,
116  const double offset_)
117 {
118  Threads::Mutex::ScopedLock lock(log_lock);
119  if (on)
120  {
121  double_threshold = double_threshold_;
122  float_threshold = float_threshold_;
123  offset = offset_;
124  }
125  else
126  {
127  double_threshold = 0.;
128  float_threshold = 0.;
129  offset = 0.;
130  }
131 }
132 
133 
134 LogStream &
135 LogStream::operator<< (std::ostream& (*p) (std::ostream &))
136 {
137 
138  std::ostringstream &stream = get_stream();
139 
140  // Print to the internal stringstream:
141  stream << p;
142 
143 
144  // This is a bloody hack until LogStream got reimplemented as a proper
145  // child of std::streambuf (or similar).
146  //
147  // The problem is that at this point we would like to know whether an
148  // std::flush or std::endl has called us, however, there is no way to
149  // detect this in a sane manner.
150  //
151  // The obvious idea to compare function pointers,
152  // std::ostream & (* const p_flush) (std::ostream &) = &std::flush;
153  // p == p_flush ? ...,
154  // is wrong as there doesn't has to be a _single_ std::flush instance...
155  // there could be multiple of it. And in fact, LLVM's libc++ implements
156  // std::flush and std::endl in a way that every shared library and
157  // executable has its local copy... fun...
158  //
159  // - Maier, 2013
160 
161  class QueryStreambuf : public std::streambuf
162  {
163  // Implement a minimalistic stream buffer that only stores the fact
164  // whether overflow or sync was called
165  public:
166  QueryStreambuf()
167  : flushed_(false), newline_written_(false)
168  {
169  }
170  bool flushed()
171  {
172  return flushed_;
173  }
174  bool newline_written()
175  {
176  return newline_written_;
177  }
178  private:
179  int_type overflow(int_type ch)
180  {
181  newline_written_ = true;
182  return ch;
183  }
184  int sync()
185  {
186  flushed_ = true;
187  return 0;
188  }
189  bool flushed_;
190  bool newline_written_;
191  } query_streambuf;
192 
193  {
194  // and initialize an ostream with this streambuf:
195  std::ostream inject (&query_streambuf);
196  inject << p;
197  }
198 
199  if (query_streambuf.flushed())
200  {
201  Threads::Mutex::ScopedLock lock(write_lock);
202 
203  // Print the line head in case of a previous newline:
204  if (at_newline)
205  print_line_head();
206 
207  at_newline = query_streambuf.newline_written();
208 
209  if (get_prefixes().size() <= std_depth)
210  *std_out << stream.str();
211 
212  if (file && (get_prefixes().size() <= file_depth))
213  *file << stream.str() << std::flush;
214 
215  // Start a new string:
216  stream.str("");
217  }
218 
219  return *this;
220 }
221 
222 
223 void
224 LogStream::attach(std::ostream &o,
225  const bool print_job_id)
226 {
227  Threads::Mutex::ScopedLock lock(log_lock);
228  file = &o;
229  o.setf(std::ios::showpoint | std::ios::left);
230  if (print_job_id)
231  o << dealjobid();
232 }
233 
234 
236 {
237  Threads::Mutex::ScopedLock lock(log_lock);
238  file = 0;
239 }
240 
241 
243 {
244  Threads::Mutex::ScopedLock lock(log_lock);
245  if (old_cerr == 0)
246  {
247  old_cerr = std::cerr.rdbuf(file->rdbuf());
248  }
249  else
250  {
251  std::cerr.rdbuf(old_cerr);
252  old_cerr = 0;
253  }
254 }
255 
256 
257 std::ostream &
259 {
260  return *std_out;
261 }
262 
263 
264 std::ostream &
266 {
267  Assert(file,
268  ExcMessage("You can't ask for the std::ostream object for the output "
269  "file if none had been set before."));
270  return *file;
271 }
272 
273 
274 bool
276 {
277  return (file != 0);
278 }
279 
280 
281 const std::string &
283 {
284  static std::string empty_string;
285 
286  if (get_prefixes().size() > 0)
287  return get_prefixes().top();
288  else
289  return empty_string;
290 }
291 
292 
293 void
294 LogStream::push (const std::string &text)
295 {
296  std::string pre;
297  if (get_prefixes().size() > 0)
298  pre = get_prefixes().top();
299 
300  pre += text;
301  pre += std::string(":");
302  get_prefixes().push(pre);
303 }
304 
305 
307 {
308  if (get_prefixes().size() > 0)
309  get_prefixes().pop();
310 }
311 
312 
313 std::ios::fmtflags
314 LogStream::flags(const std::ios::fmtflags f)
315 {
316  return get_stream().flags (f);
317 }
318 
319 
320 std::streamsize
321 LogStream::precision (const std::streamsize prec)
322 {
323  return get_stream().precision (prec);
324 }
325 
326 
327 std::streamsize
328 LogStream::width (const std::streamsize wide)
329 {
330  return get_stream().width (wide);
331 }
332 
333 
334 unsigned int
335 LogStream::depth_console (const unsigned int n)
336 {
337  Threads::Mutex::ScopedLock lock(log_lock);
338  const unsigned int h = std_depth;
339  std_depth = n;
340  return h;
341 }
342 
343 
344 unsigned int
345 LogStream::depth_file (const unsigned int n)
346 {
347  Threads::Mutex::ScopedLock lock(log_lock);
348  const unsigned int h = file_depth;
349  file_depth = n;
350  return h;
351 }
352 
353 
354 void
356 {
357  Threads::Mutex::ScopedLock lock(log_lock);
358  double_threshold = t;
359 }
360 
361 
362 void
364 {
365  Threads::Mutex::ScopedLock lock(log_lock);
366  float_threshold = t;
367 }
368 
369 
370 bool
372 {
373  Threads::Mutex::ScopedLock lock(log_lock);
374  const bool h = print_utime;
375  print_utime = flag;
376  return h;
377 }
378 
379 
380 bool
382 {
383  Threads::Mutex::ScopedLock lock(log_lock);
384  const bool h = diff_utime;
385  diff_utime = flag;
386  return h;
387 }
388 
389 
390 bool
391 LogStream::log_thread_id (const bool flag)
392 {
393  Threads::Mutex::ScopedLock lock(log_lock);
394  const bool h = print_thread_id;
395  print_thread_id = flag;
396  return h;
397 }
398 
399 std::stack<std::string> &
401 {
402 #ifdef DEAL_II_WITH_THREADS
403  bool exists = false;
404  std::stack<std::string> &local_prefixes = prefixes.get(exists);
405 
406  // If this is a new locally stored stack, copy the "blessed" prefixes
407  // from the initial thread that created logstream.
408  if (! exists)
409  {
410  const tbb::enumerable_thread_specific<std::stack<std::string> > &impl
412 
413  // The thread that created this LogStream object should be the first
414  // in tbb's enumerable_thread_specific container.
415  const tbb::enumerable_thread_specific<std::stack<std::string> >::const_iterator first_elem
416  = impl.begin();
417 
418  if (first_elem != impl.end())
419  {
420  local_prefixes = *first_elem;
421  }
422  }
423 
424  return local_prefixes;
425 
426 #else
427  return prefixes.get();
428 #endif
429 }
430 
431 
432 void
434 {
435 #ifdef DEAL_II_HAVE_SYS_RESOURCE_H
436  rusage usage;
437  double utime = 0.;
438  if (print_utime)
439  {
440  getrusage(RUSAGE_SELF, &usage);
441  utime = usage.ru_utime.tv_sec + 1.e-6 * usage.ru_utime.tv_usec;
442  if (diff_utime)
443  {
444  double diff = utime - last_time;
445  last_time = utime;
446  utime = diff;
447  }
448  }
449 #else
450 //TODO[BG]: Do something useful here
451  double utime = 0.;
452 #endif
453 
454  const std::string &head = get_prefix();
455  const unsigned int thread = Threads::this_thread_id();
456 
457  if (get_prefixes().size() <= std_depth)
458  {
459  if (print_utime)
460  {
461  int p = std_out->width(5);
462  *std_out << utime << ':';
463  std_out->width(p);
464  }
465  if (print_thread_id)
466  *std_out << '[' << thread << ']';
467 
468  if (head.size() > 0)
469  *std_out << head << ':';
470  }
471 
472  if (file && (get_prefixes().size() <= file_depth))
473  {
474  if (print_utime)
475  {
476  int p = file->width(6);
477  *file << utime << ':';
478  file->width(p);
479  }
480  if (print_thread_id)
481  *file << '[' << thread << ']';
482 
483  if (head.size() > 0)
484  *file << head << ':';
485  }
486 }
487 
488 
489 void
491 {
492  struct tms current_tms;
493 #if defined(DEAL_II_HAVE_UNISTD_H) && defined(DEAL_II_HAVE_TIMES)
494  const clock_t tick = sysconf(_SC_CLK_TCK);
495  const double time = 1./tick * times(&current_tms);
496 #else
497  const double time = 0.;
498  const unsigned int tick = 100;
499  current_tms.tms_utime = 0;
500  current_tms.tms_stime = 0;
501  current_tms.tms_cutime = 0;
502  current_tms.tms_cstime = 0;
503 #endif
504  (*this) << "Wall: " << time - reference_time_val
505  << " User: " << 1./tick * (current_tms.tms_utime - reference_tms.tms_utime)
506  << " System: " << 1./tick * (current_tms.tms_stime - reference_tms.tms_stime)
507  << " Child-User: " << 1./tick * (current_tms.tms_cutime - reference_tms.tms_cutime)
508  << " Child-System: " << 1./tick * (current_tms.tms_cstime - reference_tms.tms_cstime)
509  << std::endl;
510 }
511 
512 
513 std::size_t
515 {
516  // TODO
517  Assert(false, ExcNotImplemented());
518 
519  std::size_t mem = sizeof(*this);
520  // to determine size of stack
521  // elements, we have to copy the
522  // stack since we can't access
523  // elements from further below
524 // std::stack<std::string> tmp = prefixes;
525 // while (tmp.empty() == false)
526 // {
527 // mem += MemoryConsumption::memory_consumption (tmp.top());
528 // tmp.pop ();
529 // }
530 
531  return mem;
532 }
533 
534 DEAL_II_NAMESPACE_CLOSE
void pop()
Definition: logstream.cc:306
float float_threshold
Definition: logstream.h:475
std::streamsize precision(const std::streamsize prec)
Definition: logstream.cc:321
void timestamp()
Definition: logstream.cc:490
bool print_utime
Definition: logstream.h:453
unsigned int this_thread_id()
std::ostream * std_out
Definition: logstream.h:427
Threads::ThreadLocalStorage< std::stack< std::string > > prefixes
Definition: logstream.h:420
const std::string & get_prefix() const
Definition: logstream.cc:282
double offset
Definition: logstream.h:494
bool print_thread_id
Definition: logstream.h:499
void threshold_double(const double t)
Definition: logstream.cc:355
unsigned int depth_file(const unsigned int n)
Definition: logstream.cc:345
STL namespace.
unsigned int std_depth
Definition: logstream.h:443
std::streamsize width(const std::streamsize wide)
Definition: logstream.cc:328
bool log_thread_id(const bool flag)
Definition: logstream.cc:391
std::ostream & get_file_stream()
Definition: logstream.cc:265
std::streambuf * old_cerr
Definition: logstream.h:516
std::ios::fmtflags flags(const std::ios::fmtflags f)
Definition: logstream.cc:314
LogStream & operator<<(const double t)
Definition: logstream.h:592
static ::ExceptionBase & ExcMessage(std::string arg1)
bool has_file() const
Definition: logstream.cc:275
~LogStream()
Definition: logstream.cc:73
double last_time
Definition: logstream.h:463
void test_mode(const bool on=true, const double double_threshold=1.e-10, const float float_threshold=1.e-7f, const double offset=1.e-7)
Definition: logstream.cc:113
#define Assert(cond, exc)
Definition: exceptions.h:313
tbb::enumerable_thread_specific< T > & get_implementation()
std::stack< std::string > & get_prefixes() const
Definition: logstream.cc:400
bool diff_utime
Definition: logstream.h:458
void log_cerr()
Definition: logstream.cc:242
void threshold_float(const float t)
Definition: logstream.cc:363
bool log_time_differences(const bool flag)
Definition: logstream.cc:381
unsigned int depth_console(const unsigned int n)
Definition: logstream.cc:335
void print_line_head()
Definition: logstream.cc:433
std::ostream * file
Definition: logstream.h:435
double double_threshold
Definition: logstream.h:469
void attach(std::ostream &o, const bool print_job_id=true)
Definition: logstream.cc:224
std::ostream & get_console()
Definition: logstream.cc:258
double reference_time_val
Definition: logstream.h:504
bool at_newline
Definition: logstream.h:521
bool log_execution_time(const bool flag)
Definition: logstream.cc:371
void push(const std::string &text)
Definition: logstream.cc:294
static ::ExceptionBase & ExcNotImplemented()
void detach()
Definition: logstream.cc:235
std::ostringstream & get_stream()
Definition: logstream.h:567
unsigned int file_depth
Definition: logstream.h:448
struct tms reference_tms
Definition: logstream.h:509
std::size_t memory_consumption() const
Definition: logstream.cc:514