]> https://gitweb.dealii.org/ - dealii.git/commitdiff
defer backtrace lookup in dealii::Exception for performance reasons
authorTimo Heister <timo.heister@gmail.com>
Tue, 19 Nov 2013 22:27:40 +0000 (22:27 +0000)
committerTimo Heister <timo.heister@gmail.com>
Tue, 19 Nov 2013 22:27:40 +0000 (22:27 +0000)
git-svn-id: https://svn.dealii.org/trunk@31720 0785d39b-7218-0410-832d-ea1e28bc413d

deal.II/doc/news/changes.h
deal.II/include/deal.II/base/exceptions.h
deal.II/source/base/exceptions.cc

index 80b7a85a8f5106fa44983d8536c31c31d21f5e9f..9dbadb924bbe29ca31daa921d94b3477492d4e4a 100644 (file)
@@ -211,6 +211,13 @@ inconvenience this causes.
 <h3>Specific improvements</h3>
 
 <ol>
+  <li> Changed: when a dealii::Exception is thrown, defer the symbol lookup of the
+  stack trace to when it is needed. This improves performance if what() is never
+  called.
+  <br>
+  (Timo Heister, 2013/11/17)
+  </li>
+
   <li> Fixed: GridGenerator::parallelogram was not instantiated properly
   on intel compilers.
   <br>
index fceafdd46c6e13c7887355712dfe585d51034661..0f5f4c393d45dac39ebc63d1d35421659f02d3d9 100644 (file)
@@ -72,6 +72,12 @@ public:
                    const char *cond,
                    const char *exc_name);
 
+
+  /**
+   * Override the standard function that returns the description of the error.
+   */
+  virtual const char* what() const throw();
+
   /**
    * Get exception name.
    */
@@ -124,7 +130,7 @@ protected:
    * A backtrace to the position where the problem happened, if the
    * system supports this.
    */
-  char **stacktrace;
+  mutable char **stacktrace;
 
   /**
    * The number of stacktrace frames that are stored in the previous
@@ -132,13 +138,20 @@ protected:
    */
   int n_stacktrace_frames;
 
+#ifdef HAVE_GLIBC_STACKTRACE
+  /**
+   * array of pointers that contains the raw stack trace
+   */
+  void *raw_stacktrace[25];
+#endif
+
 private:
   /**
    * Internal function that generates the c_string that gets printed by
    * exception::what(). Called by the ExceptionBase constructor and
    * set_fields.
    */
-  void generate_message();
+  void generate_message() const;
 };
 
 
index b71a75d98a670b7fe76b97e7a038a9bac3626455..590f1ce1f68cd441dffd63d73359064640eaf0f3 100644 (file)
@@ -115,23 +115,40 @@ void ExceptionBase::set_fields (const char *f,
   exc  = e;
 
   // If the system supports this, get a stacktrace how we got here:
-
   if (stacktrace != 0)
     {
       free (stacktrace);
       stacktrace = 0;
     }
 
+  // Note that we defer the symbol lookup done by backtrace_symbols()
+  // to when we need it (see what() below). This is for performance
+  // reasons, as this requires loading libraries and can take in the
+  // order of seconds on some machines.
 #ifdef HAVE_GLIBC_STACKTRACE
-  void *array[25];
-  n_stacktrace_frames = backtrace(array, 25);
-  stacktrace = backtrace_symbols(array, n_stacktrace_frames);
+  n_stacktrace_frames = backtrace(raw_stacktrace, 25);
 #endif
 
-  // And finally populate the underlying std::runtime_error:
-  generate_message();
+  // set the message to the empty string so that what() will compute
+  // a new error message with the new information.
+  std::runtime_error * base = static_cast<std::runtime_error *>(this);
+  *base = std::runtime_error("");
 }
 
+const char* ExceptionBase::what() const throw()
+{
+  // We override the what() function to be able to look up the symbols
+  // of the stack trace.
+  if (std::runtime_error::what()[0]=='\0')
+    {
+#ifdef HAVE_GLIBC_STACKTRACE
+      stacktrace = backtrace_symbols(raw_stacktrace, n_stacktrace_frames);
+#endif
+
+      generate_message();
+    }
+  return std::runtime_error::what();
+}
 
 
 const char *ExceptionBase::get_exc_name () const
@@ -262,7 +279,7 @@ void ExceptionBase::print_stack_trace (std::ostream &out) const
 
 
 
-void ExceptionBase::generate_message ()
+void ExceptionBase::generate_message () const
 {
   // build up a string with the error message...
 
@@ -289,8 +306,10 @@ void ExceptionBase::generate_message ()
   converter << "--------------------------------------------------------"
             << std::endl;
 
-  // ... and set up std::runtime_error with it:
-  static_cast<std::runtime_error &>(*this) = std::runtime_error(converter.str());
+  // ... and set up std::runtime_error with it. We need to do a const
+  // cast so we can change the what message even though our method is const.
+  const std::runtime_error * base = static_cast<const std::runtime_error *>(this);
+  const_cast<std::runtime_error &>(*base) = std::runtime_error(converter.str());
 }
 
 

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.

Douglas Adams


Typeset in Trocchi and Trocchi Bold Sans Serif.