From c39e7f15f4b362d7b8921e3222585a2d5db558a6 Mon Sep 17 00:00:00 2001 From: Timo Heister Date: Tue, 19 Nov 2013 22:27:40 +0000 Subject: [PATCH] defer backtrace lookup in dealii::Exception for performance reasons git-svn-id: https://svn.dealii.org/trunk@31720 0785d39b-7218-0410-832d-ea1e28bc413d --- deal.II/doc/news/changes.h | 7 +++++ deal.II/include/deal.II/base/exceptions.h | 17 +++++++++-- deal.II/source/base/exceptions.cc | 37 +++++++++++++++++------ 3 files changed, 50 insertions(+), 11 deletions(-) diff --git a/deal.II/doc/news/changes.h b/deal.II/doc/news/changes.h index 80b7a85a8f..9dbadb924b 100644 --- a/deal.II/doc/news/changes.h +++ b/deal.II/doc/news/changes.h @@ -211,6 +211,13 @@ inconvenience this causes.

Specific improvements

    +
  1. 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. +
    + (Timo Heister, 2013/11/17) +
  2. +
  3. Fixed: GridGenerator::parallelogram was not instantiated properly on intel compilers.
    diff --git a/deal.II/include/deal.II/base/exceptions.h b/deal.II/include/deal.II/base/exceptions.h index fceafdd46c..0f5f4c393d 100644 --- a/deal.II/include/deal.II/base/exceptions.h +++ b/deal.II/include/deal.II/base/exceptions.h @@ -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; }; diff --git a/deal.II/source/base/exceptions.cc b/deal.II/source/base/exceptions.cc index b71a75d98a..590f1ce1f6 100644 --- a/deal.II/source/base/exceptions.cc +++ b/deal.II/source/base/exceptions.cc @@ -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(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(*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(this); + const_cast(*base) = std::runtime_error(converter.str()); } -- 2.39.5