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