Topic: Do exceptions have to be slow?


Author: Francis Glassborow <francis.glassborow@ntlworld.com>
Date: Tue, 15 May 2001 17:29:44 GMT
Raw View
In article <3B0117AD.75AD99DA@thep.lu.se>, Leif L=F6nnblad
<Leif.Lonnblad@thep.lu.se> writes
>Hi all,
>
>I'm currently writing a fairly large piece of C++ software where I
>use exceptions a lot. Not only for errors and rare events, but as a not
>uncommon way of exiting functions. This has turned out to be extremely
>slow.

Yes, and because of the way that exceptions are generally implemented to
make them as near cost free as possible if they are not actually thrown,
that will always be the case. Your programmers have abused the use of
throw and so are paying the price:(

>
>I realize that this is a 'quality of implementation' issue so it is a
>bit off-topic, but I thought comp.std.c++ could be a good forum for
>reaching many compiler developers.

It isn't really a quality of implementation issue except in so far as
there are alternative strategies that would make your software run
better but would damage all the software from those who have used
exceptions in the way they were designed.

>
>I also know that exceptions were not intended to be used as a normal
>way of exiting functions. But it so happens that for the algorithms
>I'm implementing - Monte Carlo integration and generation of
>complicated distributions with intricate cuts - the exception
>mechanism provides an extremely elegant solution. But (almost
>forbiddingly) slow.

So you can have elegant and slow or 'correct' and fast. I very much
doubt that exceptions are actually an elegant solution to your problem.

>
>I have appended a piece of code below (not from my project), comparing
>normal function returns (with checking of the return value), with
>throwing an exception. On my Linux box running gcc-2.95.2, the latter
>is more than a hundred times slower (sic!). It also turns out that
>supplying throw declarations to the functions makes it another factor
>five slower.

I think you meant throw specifications and most experts believe those
are poorly designed and are a pain in the proverbials.  So what do you
conclude is the right way to write your code in C++?

>
>The obvious question is whether exceptions have to be this slow, or if
>it is just that the gcc developers never tried to optimize them. (I've
>tried a couple of other compilers with only slightly better result.)

They have to be that slow or they have to cost everyone. The
overwhelming majority of us prefer that we only pay when something bad
has happened.

>
>Is it too optimistic to hope that compiler writers in general will try
>to optimize their exception handling anytime soon? Would it be better
>for me to redesign my algorithms without exceptions?

Definitely redesign. Optimisers currently focus on ways to minimise the
RAM footprint and execution speed of an executable that contains
exceptions that are not actually thrown because nothing untoward
happens.

>
>
>
>Leif L=F6nnblad
>
>Department of Theoretical Physics,
>Lund University
>
>

Francis Glassborow      ACCU
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: Matthew Austern <austern@research.att.com>
Date: Tue, 15 May 2001 17:30:21 GMT
Raw View
Leif L=F6nnblad <Leif.Lonnblad@thep.lu.se> writes:

> I have appended a piece of code below (not from my project), comparing
> normal function returns (with checking of the return value), with
> throwing an exception. On my Linux box running gcc-2.95.2, the latter
> is more than a hundred times slower (sic!). It also turns out that
> supplying throw declarations to the functions makes it another factor
> five slower.
>=20
> The obvious question is whether exceptions have to be this slow, or if
> it is just that the gcc developers never tried to optimize them. (I've
> tried a couple of other compilers with only slightly better result.)

I'm not sure if comp.std.c++ is the right place for this discussion,
since nothing in the C++ standard dictates exception speed.  (I
understand that some standards are different, that the Ada standard,
for example, explicitly gives guidance about performance tradeoffs
when implementing exceptions.)  But two general points.

First, the standard does mandate some pretty complicated behavior for
exception processing: stack unwinding and RTTI.  It's unlikely that
this can ever be as fast as normal function return.

Second, most implementors have worked very hard to optimize
exceptions---but they've been optimizing something other than what
you've been measuring.  They've been optimizing the case of normal
control flow.  The goal has been that exceptions should have zero
overhead unless an exception is actually thrown.  That goal hasn't
been achieved, and probably isn't achievable, but some implementations
come impressively close.  This is an explicit tradeoff, since the
usual techniques for increasing the speed of the no-exception case
(moving unwind information out of the way, etc.) will make throwing an
exception slower.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: remove.haberg@matematik.su.se (Hans Aberg)
Date: Tue, 15 May 2001 19:44:15 GMT
Raw View
In article <NQzW4HBLFTA7EwFQ@ntlworld.com>, Francis Glassborow
<francisG@robinton.demon.co.uk> wrote:
>>I also know that exceptions were not intended to be used as a normal
>>way of exiting functions. But it so happens that for the algorithms
>>I'm implementing - Monte Carlo integration and generation of
>>complicated distributions with intricate cuts - the exception
>>mechanism provides an extremely elegant solution. But (almost
>>forbiddingly) slow.
>
>So you can have elegant and slow or 'correct' and fast. I very much
>doubt that exceptions are actually an elegant solution to your problem.

Exceptions can be used to implement the dynamic equivalent of constructs
such as "return", "break", and "continue", by having a sequence with an
evaluator, letting those constructs throwing an exception and the sequence
object catching them. I was a long time ago suggested the denotational
semantics explanation of why this might work so, but I have forgotten
about it.

So it certainly looks as though exceptions can be used as a toll of normal
programming.

I am a bit curios why the throw-catch procedure is so slow: After all, it
should kill off the same objects as when making a series of "return"'s
using "if" clauses". So the overhead must have something to do with how
those objects that should be killed off are registered and killed off.

  Hans Aberg      * Anti-spam: remove "remove." from email address.
                  * Email: Hans Aberg <remove.haberg@member.ams.org>
                  * Home Page: <http://www.matematik.su.se/~haberg/>
                  * AMS member listing: <http://www.ams.org/cml/>

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: "Carl Daniel" <carl@pixami.com>
Date: Tue, 15 May 2001 21:24:18 GMT
Raw View
"Leif L   nnblad" <Leif.Lonnblad@thep.lu.se> wrote in message
news:3B0117AD.75AD99DA@thep.lu.se...

[snip]

> The obvious question is whether exceptions have to be this slow, or if
> it is just that the gcc developers never tried to optimize them. (I've
> tried a couple of other compilers with only slightly better result.)

I just did a simple test with MSVC6:

#include "PxContextTimer.h"    // my own whizzo-matic timing class
#include <windows.h>

void nothrow()
{
  TIME_CONTEXT("No-throw");
}

void throw2()
{
  throw 1;
}

void throw1()
{
  TIME_CONTEXT("Throw");

  try
  {
    throw2();
  }
  catch(...)
  {
  }
}

void main()
{
  TIME_CONTEXT_ROOT("Main",0);

  nothrow();
  throw1();
  Sleep(50);  // make sure the timing log has been dumped before we exit
}

With all optimizations disabled, these are the times I got on a 650Mhz
Pentium III (I did these with optimizations off to ensure that the compiler
wasn't too clever on me.  Since the exception overhead is largely due to the
execution time of library code which is already compiled, optimization is
likely to have little effect on the real overhead of throwing exceptions).

5/15/01 2:04:25 PM
  42495.62   s  41310.84   s  Main
    1.68   s  1.68   s  No-throw
    1183.11   s  1183.11   s  Throw

So - about 2us for a normal call/return, about 1ms for a call/throw.  Is
that slow?  I suppose that depends on what your functions do.  Adding
computation to the functions, the time differential holds at about 1ms
penalty for exiting via throw.  Here are the times counting to 1,000,000 in
each function:

5/15/01 2:17:09 PM
  72846.97   s  48170.93   s  Main
    11868.27   s  11868.27   s  No-throw
    12807.77   s  12807.77   s  Throw

Whether exceptions are slow is completely dependent on the functions you're
throwing from - in the long run, it's all relative.  If the functions you're
throwing from do I/O at all, the cost of exit via throw is likely to be much
much less than the variability in I/O time that the functions will incur
regardless of exceptions.

-cd



---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: Francis Glassborow <francis.glassborow@ntlworld.com>
Date: Tue, 15 May 2001 22:58:51 GMT
Raw View
In article <remove.haberg-1505012143300001@du131-226.ppp.su-
anst.tninet.se>, Hans Aberg <remove.haberg@matematik.su.se> writes
>I am a bit curios why the throw-catch procedure is so slow: After all, it
>should kill off the same objects as when making a series of "return"'s
>using "if" clauses". So the overhead must have something to do with how
>those objects that should be killed off are registered and killed off.

Basically you cannot have close to zero overhead for exceptions in the
normal flow of a program and little cost when abnormal flow (and
exception is thrown) occurs. Most of us prefer very low overheads when
are program is behaving (no throws happen). If programmers do not
understand this, they abuse the C++ exception mechanism.

In effect, unless special methods are used (which, thank god, most
implementors provide) every call to a function which might throw (does
not have an empty throw spec) has to be treated as a conditional return
and that really bloats your code a smashes performance. And if you think
the empty throw spec helps, you would be mistaken because traps still
have to be placed so that a runtime violation can be detected.


Francis Glassborow      ACCU
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: Francis Glassborow <francis.glassborow@ntlworld.com>
Date: Tue, 15 May 2001 22:58:58 GMT
Raw View
In article <9ds6nu$5m3@dispatch.concentric.net>, Carl Daniel
<carl@pixami.com> writes
>Whether exceptions are slow is completely dependent on the functions you're
>throwing from - in the long run, it's all relative.

In part, but the cost is also dependant on the complexity of the code.
To really test you need to have a large executable with exceptions in
use. Now benchmark a small region using conditional returns v
exceptions. Now you will see the impact of exception handling (however
note that this will depend on how aggressively the compiler optimises
normal flow (no exceptions thrown) for both RAM footprint and execution
speed. It is perfectly possible to write an exception implementation
that works as well as conditional returns by using a naive exception
mechanism.


Francis Glassborow      ACCU
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: "Al Grant" <tnarga@arm.REVERSE-NAME.com>
Date: Tue, 15 May 2001 23:32:40 GMT
Raw View
"Leif L   nnblad" <Leif.Lonnblad@thep.lu.se> wrote in message
news:3B0117AD.75AD99DA@thep.lu.se...
>The obvious question is whether exceptions have to be this slow, or if
>it is just that the gcc developers never tried to optimize them. (I've
>tried a couple of other compilers with only slightly better result.)

>Is it too optimistic to hope that compiler writers in general will try
>to optimize their exception handling anytime soon? Would it be better
>for me to redesign my algorithms without exceptions?

Stroustrup says "The primary aim of the exception
handling mechanism... is error handling and the support
of fault tolerance".

Therefore an optimised exception handling mechanism
is one that minimises the effect of the mechanism on
the non-exceptional code path.  It may only be able
to do this by making the exception handling mechanism
so complex that taking an exception is a relatively
expensive event.  But that is not a problem given
what exceptions are designed for in C++.



---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: Leif =?iso-8859-1?Q?L=F6nnblad?= <Leif.Lonnblad@thep.lu.se>
Date: Tue, 15 May 2001 12:12:45 GMT
Raw View
Hi all,

I'm currently writing a fairly large piece of C++ software where I
use exceptions a lot. Not only for errors and rare events, but as a not
uncommon way of exiting functions. This has turned out to be extremely
slow.

I realize that this is a 'quality of implementation' issue so it is a
bit off-topic, but I thought comp.std.c++ could be a good forum for
reaching many compiler developers.

I also know that exceptions were not intended to be used as a normal
way of exiting functions. But it so happens that for the algorithms
I'm implementing - Monte Carlo integration and generation of
complicated distributions with intricate cuts - the exception
mechanism provides an extremely elegant solution. But (almost
forbiddingly) slow.

I have appended a piece of code below (not from my project), comparing
normal function returns (with checking of the return value), with
throwing an exception. On my Linux box running gcc-2.95.2, the latter
is more than a hundred times slower (sic!). It also turns out that
supplying throw declarations to the functions makes it another factor
five slower.

The obvious question is whether exceptions have to be this slow, or if
it is just that the gcc developers never tried to optimize them. (I've
tried a couple of other compilers with only slightly better result.)

Is it too optimistic to hope that compiler writers in general will try
to optimize their exception handling anytime soon? Would it be better
for me to redesign my algorithms without exceptions?



Leif L=F6nnblad

Department of Theoretical Physics,
Lund University




// throwtest.cc
#include <iostream>
#include <ctime>
#include <cmath>

double elapsed() {
  static long last =3D 0;
  long el =3D std::clock() - last;
  last +=3D el;
  return double(el)*0.000001;
}

double testfn(long i) {
  if ( i%2 =3D=3D 0 ) return 0.0;
  return i;
}

double testfn2(long i) {
  double x =3D testfn(i);
  if ( x =3D=3D 0.0 ) return -1.0;
  return std::log(x);
}

double throwfn(long i) {
  if ( i%2 =3D=3D 0 ) throw int();
  return i;
}

double throwfn2(long i) {
  return std::log(throwfn(i));
}

double declarethrowfn(long i) throw(int) {
  if ( i%2 =3D=3D 0 ) throw int();
  return i;
}

double declarethrowfn2(long i) throw(int) {
  return std::log(declarethrowfn(i));
}

int main() {

  long N =3D 100000000;
  long n =3D 1000000;

  elapsed();
  double sum =3D 0.0;
  for ( long i =3D 0; i < n; ++ i ) {
    try { sum +=3D 1.0/throwfn(i); }
    catch (int) {}
  }
  std::cout << "Undeclared exception " << elapsed()/double(n) <<
std::endl;

  sum =3D 0.0;
  for ( long i =3D 0; i < n; ++ i ) {
    try { sum +=3D 1.0/declarethrowfn(i); }
    catch (int) {}
  }
  std::cout << "Declared exception   " << elapsed()/double(n) <<
std::endl;

  sum =3D 0.0;
  for ( long i =3D 0; i < N; ++ i ) {
    double x =3D testfn(i);
    if ( x !=3D 0.0 ) sum +=3D 1.0/x;
  }
  std::cout << "Check return value   " << elapsed()/double(N) <<
std::endl;

  N /=3D 10;
  n /=3D 10;

  sum =3D 0.0;
  for ( long i =3D 0; i < n; ++ i ) {
    try { sum +=3D 1.0/std::exp(throwfn2(i)); }
    catch (int) {}
  }
  std::cout << "Undeclared exception 2 " << elapsed()/double(n) <<
std::endl;

  sum =3D 0.0;
  for ( long i =3D 0; i < n; ++ i ) {
    try { sum +=3D 1.0/std::exp(declarethrowfn2(i)); }
    catch (int) {}
  }
  std::cout << "Declared exception 2   " << elapsed()/double(n) <<
std::endl;

  sum =3D 0.0;
  for ( long i =3D 0; i < N; ++ i ) {
    double x =3D testfn2(i);
    if ( x > -1.0 ) sum +=3D 1.0/std::exp(x);
  }
  std::cout << "Check return value 2   " << elapsed()/double(N) <<
std::endl;


  return 0;
}

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]