C++ Exceptions Cause Performance Hit?

G

George Neuner

Another point to keep in mind (although it probably isn't
relevant to embedded systems) is that exceptions make it very
easy for the compiler to isolate the clean-up code which is
called in the error case. This can, in turn, result if smaller
functions, increasing the probability of the function fitting
entirely in the cache.

That's just as relevant in embedded code as anywhere else. Reducing
the size of the object code is frequently paramount. And in any case,
reducing the complexity of the source is always desirable.

IMO, that's why it's such a pity that the C++ exception mechanism
doesn't work very well for real time coding - which is a sizable
percentage of all embedded coding.

George
 
J

James Kanze

Julián Albo said:
> George Neuner wrote:
> If I expect that some result occurs frequently as part of the normal usage,
> I don't consider it exceptional, and then I do not use a exception
for it.

I'm not sure that George expressed himself clearly here.
Networking and hardware control application failures are (or
should be) "exceptional", in the sense that most of the time,
they don't occur. On the other hand, in embedded systems, it is
routinely expected to be able to handle and recover from them,
no matter how rarely they occur. Often in a specified finite
interval of time.
 
A

arketype

Short answer: Don't use exceptions in real-time systems.
There may be lot's of maybe's involved but overall, every experienced
realtime programmer I have spoken to says don't use them. At the very
least, even if your compiler optimizes exceptions to the max, you will
hurt the portability of your app.

Just a clarification to one of the below posters comments. Virtual
functions are usually ok in RT systems, they should have a bounded
execution time, unless the V-Table has trillions and trillions of
entries. :)

JJJ


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
R

RH

No, it doesn't have an additional exit. The "error return value" case
will have an 'if( value==bad ) break;' statement. That is the same
exit from the loop.

Sorry if I was imprecise - the loop will have an additional 'loop
exit', not a program exit. There is no explicit control flow after a
function call to check for a possibly thrown exception out of this
function. If there was, you were right, the break would just be a jump
to the loop end, not an additional exit.

But this is not how it is done.

Instead, the runtime will find the landing pad during stack unrolling
with help of language specific data stored somewhere aside in the
binary. This is usually how those no-overhead implementations are done.


Therefore, during CFG construction, the compiler will add an edge from
each possibly throwing function call to a landing pad.

In practice - in particular for the loop optimizer - this _is_ a big
problem, because many loop opts cannot deal with multiple loop-exits.
All high performance compilers I know off (Intel, Open64, HP-UX) have
difficulties with that.

A viable inter procedural optimization is to determine which functions
can actually throw and then to remove corresponding unreachable landing
pads...


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
J

James Kanze

George said:
On 15 Jul 2005 10:49:14 -0400, (e-mail address removed) wrote:
That's just as relevant in embedded code as anywhere else.

Yes and no.
Reducing the size of the object code is frequently paramount.

Agreed. My only point was that on an embedded processor,
reducing the size isn't as likely to affect speed. If, as is
often the case, memory is limited, then reducing the size will
reduce memory use.
And in any case, reducing the complexity of the source is
always desirable.

Again, yes and no. In very critical systems, where you have to
literally prove the code correct, under all possible input,
adding additional flow paths which don't show up in the source
is probably not a good idea. And in fact, in such systems, I
would ban exceptions.

Luckily, most systems (including most embedded systems) aren't
quite that critical, and we accept that exiting because of an
exception will not meet all of the functions post-conditions,
but only a small set of global invariants, which are (fairly)
easily checked, provided correct programming techniques are
used.

--
James Kanze mailto: (e-mail address removed)
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 pl. Pierre Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
?

=?ISO-8859-15?Q?Juli=E1n?= Albo

James said:
I'm not sure that George expressed himself clearly here.
Networking and hardware control application failures are (or
should be) "exceptional", in the sense that most of the time,
they don't occur.

Then use the sense of "exceptional" that most adequately fits to the
application.
On the other hand, in embedded systems, it is routinely expected to
be able to handle and recover from them, no matter how rarely they
Occur. Often in a specified finite interval of time.

I don't consider important if the situation fits on some preconception of
what is exceptional and what not. Each concrete case may have his own
rules. Then don't use expections for situations that in this case are
inadequate, but that's not a reason to completely ban exceptions.
 
F

Francis Glassborow

Short answer: Don't use exceptions in real-time systems.
I can understand such a guideline and in small real-time systems it
makes excellent sense (as does using C for such systems) , but as
systems get larger I think an alternative mid-term objective would be
desirable, have compilers that specifically optimise for real-time.

At the moment, most C++ implementors are aiming at minimizing the
program footprint in memory and maximizing the execution speed for
programs that have not raised an exception. The whole cost of exceptions
is then paid when an exception is actually raised. For most
desk-top/work-station/number-crunching supper-computers that is the most
appropriate strategy for most applications. If I am writing a weather
forecasting program I want it to work as fast as possible so that it
turns out forecasts in time to be useful (note that there is a sense in
which this is real-time). If something untoward happens that results in
an exception being raised I loose that run of the program (as I would if
there were a power cut).

However there is a whole class of programs that must produce results in
a bounded time, loading all the cost of exceptions on the point where
one is raised almost certainly exceeds the maximum allowed time. In such
cases error handling costs need to be distributed over the whole
program. The traditional error return mechanism does that, but makes the
process of producing and maintaining high quality code significantly
harder.

As long as exceptions are banned from such code the implementers have no
motive for producing implementations that 'optimise' exception handling
by distributing its costs across the normal code and execution paths. I
am not a compiler writer (and it is 20 years since I last wrote anything
of that kind) but it seems to me that writing such a compiler should be
possible and there might be a real market for it as long as there was
more than one such implementation.


--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
G

George Neuner

What are the problems?

The basic issue is that, from the programmer's perspective, an
exception throw is an atomic event which has a duration that can only
be indirectly controlled.

The duration of any particular throw is serially deterministic - it
depends only on the difference in call depth and the number of frame
local objects that have non-trivial destructors. These are both fixed
for any particular throw/catch pairing (assuming no recursion).
However the only way to control the duration is by manipulating those
parameters - call depth and number of non-trivial objects. This can
lead to a lot of refactoring to duplicate functions or move objects
higher into the call chain and then pass them around. It can be
particularly troublesome if the functions involved are shared heavily.

The atomicity of the throw is the more serious issue. Many real time
systems perform multiple tasks but do not use preemptive scheduling.
Many systems are designed as cooperative taskers, co-routines, or as
some kind of state machine. A lengthy throw which occurs at the wrong
moment could result in a failure by delaying execution of a more
important operation.

Before someone objects that the return from a function with many local
objects to destruct may be equally lengthy, and that the programmer
similarly has no control over it ... Yes. But the point is that
exceptions may involve multiple call frames which increases the
likelihood that more objects will be involved. In the normal return
scenario the programmer would regain control in each frame and could
decide what to do next - in the exception scenario the programmer is
locked out until all the intervening frames are destructed.

Additionally, function calls and returns are natural scheduling points
which the RT programmer is used to considering, whereas exceptions are
more easily overlooked as scheduling points because their timing
effects depend on how many call frames they traverse.



There is also the [diminishing] danger that programmers moving from C
to C++ may mentally equate exceptions with longjmp, which is normally
a constant time operation regardless of call depth.

Also certain types of programs depend on the ability to hop around at
will. When used purely for upward continuations, longjmp and
exceptions are functionally equivalent modulo destructor calls. But
setjmp/longjmp can also be used for general continuations. Exceptions
can't, and C++ doesn't provide any object safe construct or standard
library function that can.
[Yes ... I know that objects and longjmp can be safely mixed if you
are very careful.]


-
Exception atomicity is not an issue for a preemptive tasking system
and it may eventually cease to be an issue going forward when
functionality demands increase to the point where preemptive threading
is the only viable solution. However, I expect to continue to see
systems designed without it for a while yet because certified RTOSes
and tasking kernels remain expensive and most managers are
[rightfully] wary of liability arising from a home built solution.

And, of course, exceptions can be tamed through coding practices.
However, the effect of tightly controlling them results either in
programs which are written unnaturally (using TLS perhaps) or in
restricting them to protecting, at most, a single level of function
call so that their effect is no more than a normal function return.

Ultimately it does come down to the programmer knowing his tools. My
own concern, exemplified by this thread, is that a lot of people are
doing things they probably shouldn't be, in unfamiliar contexts and
with tools they don't fully understand.

George
 
W

Wu Yongwei

David said:
Whether or not they are misinformed may depend on your compiler, and
it certainly depends on your definition of "big". Some relevant
information is at:

http://tinyurl.com/8rljh

Cannot connect to this URL. Maybe you should paste the original URL as
well next time. TinyURL is cool but its chance of failing is bigger
than the normal URL (this time there seems to be problems with its DNS
servers).

Best regards,

Yongwei


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
A

arketype

Very true indeed, but we are stuck with the chicken/egg conundrum.

I especially see exceptions as being useful in underflow/overflow
errors, which are common to some realtime apps. I currently use
exceptions in a realtime sound streaming library. It is basically
'soft' realtime, because it is used for 'prelistening' and another more
predictable (and less capable) library is used for actual rendering
during performance. However I have marvelled at how robust (if a little
slow) my error handling has become, especially in overflow conditions.
I use an exception class to carry the overflowed object to a catch
handler where I can usually figure out a way to reschedule sending it,
or at the very worst, can release any resources it used.

One way to use exceptions flexibly in time constrained code is by
creating a macro or template function to 'raise an error' ala:

template<typename T> raiseError(typename
boost::call_traits<T>::const_reference err) { throw err; }

and then if you want to handle, say, common errors without the overhead
of exceptions:

template<> raiseError<QueueOverflow> (QueueOverflow const& err) {
blockFreeNotify(err); }

Although I am a big fan of exceptions, they really have cleaned up my
code, I still stick to my (I mean my mentors) prior advice, don't use
it in (hard) realtime systems. I guess trying them in 'soft' realtime
is OK if, like me, you enjoy living on the edge.

JJJ


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
M

Markus.Elfring

Exception performance depends on the compilers implementation of exceptions.
In the best case code that uses exceptions is faster in the "normal" (i.e.
no exception thrown) code path, but throwing an exceptions causes
overhead.

In most systems this is what you want. In real-time systems this additional
overhead can break your "reaction-time" guarantee

How do you measure the timing to check for the desired bounds and
limits?
Do you count instructions and processor cyles in the generated
(assembler) code?

Regards,
Markus.
 
D

David Abrahams

Wu Yongwei said:
Cannot connect to this URL. Maybe you should paste the original URL as
well next time. TinyURL is cool but its chance of failing is bigger
than the normal URL (this time there seems to be problems with its DNS
servers).

http://groups-beta.google.com/group..._frm/thread/80083ac31a1188da/d49f0ef8fe76c60f

--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
G

Gene Bushuyev

....
Before someone objects that the return from a function with many local
objects to destruct may be equally lengthy, and that the programmer
similarly has no control over it ... Yes. But the point is that
exceptions may involve multiple call frames which increases the
likelihood that more objects will be involved. In the normal return
scenario the programmer would regain control in each frame and could
decide what to do next - in the exception scenario the programmer is
locked out until all the intervening frames are destructed.

I don't see any diffeence. Programmer has the same degree of control. He can
catch exception at any place appropriately structuring his try/catch blocks,
same as he can do it with the error codes. How are the errors codes any
better? They would require roughly the same amount of processor time, except
the programmer has to clean up and propagate the error codes manually.
Additionally, function calls and returns are natural scheduling points
which the RT programmer is used to considering, whereas exceptions are
more easily overlooked as scheduling points because their timing
effects depend on how many call frames they traverse.

Same is with error codes, you need to consired how many stack frames you
need to go until the place where the error can be resolved.
Also certain types of programs depend on the ability to hop around at
will. When used purely for upward continuations, longjmp and
exceptions are functionally equivalent modulo destructor calls. But
setjmp/longjmp can also be used for general continuations. Exceptions
can't, and C++ doesn't provide any object safe construct or standard
library function that can.
[Yes ... I know that objects and longjmp can be safely mixed if you
are very careful.]

Co-routines (fibers, setjmp/longjmp) which usually run in an infinte loop
must never leak errors outside, because there is no recovery mechanism in
this stack hopping scheme other than program reset. It doesn't matter
whether exceptions, or error codes are used.

- gene


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
A

Allan W

George said:
I'm surprised [a real-time system]
would be using (m)any of the advanced features of C++ in the first
place. Virtual function calls, dynamic heap allocation and exception
handling are all, at best, problematic for verifying performance of
real time code.

Why do you put virtual function calls on that list?

Do you use, or do you know someone who uses, a CPU where a "call
indirect" takes significantly longer than a "call"? (By "significantly
longer" I mean more than 2-3 clock cycles.) Because AFAIK every single
C++ implementation of virtual functions uses some variation of vtables;
the object has a pointer to the vtable, and (for instance) offset 32 in
that table has the address of the function we wish to call.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
F

Francis Glassborow

Gene Bushuyev said:
Co-routines (fibers, setjmp/longjmp) which usually run in an infinte loop
must never leak errors outside, because there is no recovery mechanism in
this stack hopping scheme other than program reset. It doesn't matter
whether exceptions, or error codes are used.

But it does in the real world because of the way that compilers
implement exceptions by trying to make their presence zero cost (or even
negative cost) if no actual exception is raised. For many applications
that is exactly what is wanted, however in time constrained systems it
can push the cost of a raised exception beyond what can be accepted.

If we had compilers that had a switch to minimise exception handling
costs when an exception was raised, my guess is that that would make
exceptions useful in hard RT code.


--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
G

George Neuner

...

I don't see any diffeence. Programmer has the same degree of control. He can
catch exception at any place appropriately structuring his try/catch blocks,
same as he can do it with the error codes. How are the errors codes any
better? They would require roughly the same amount of processor time, except
the programmer has to clean up and propagate the error codes manually.



Same is with error codes, you need to consired how many stack frames you
need to go until the place where the error can be resolved.


You've entirely missed the point.

First, the programmer does *not* have the same degree of control
unless *every* function call in the chain is separately protected by
its own try block and any exceptions are manually propagated to the
appropriate frame.

Second, an exception allows direct control transfer to *any* higher
frame. If the programmer must insert redundant try blocks and
manually propagate exceptions just to deliberately avoid the
possibility of jumping a frame, then exception returns have no
advantage over use of error codes.


George
 
D

David Rasmussen

Francis said:
But it does in the real world because of the way that compilers
implement exceptions by trying to make their presence zero cost (or even
negative cost) if no actual exception is raised.

Negative cost? Meaning that a program compiled with exceptions, in which
no exceptions are raised will actually run faster than the same program
compiled without exceptions?

/David

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
T

Thomas Kemmer

David Rasmussen said:
Negative cost? Meaning that a program compiled with exceptions, in which
no exceptions are raised will actually run faster than the same program
compiled without exceptions?

I don't know what you mean by a program "compiled" without exceptions;
either you use exceptions in your source code, or you don't. Some
compilers may provide special options which "disable" exceptions,
meaning they do not include runtime support for exceptions in your
binary, assuming you do not throw or catch any exceptions in your
code.

I guess what was meant is that a program which uses exceptions as its
error-handling strategy _may_ run faster than a program which uses
some other error-handling strategy, such as checking the return value
of every function call. If no errors are encountered, you will still
have to do all the return value checking, which is some overhead.

Kind regards,
- Thomas

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
B

Ben Hutchings

Allan W said:
George said:
I'm surprised [a real-time system]
would be using (m)any of the advanced features of C++ in the first
place. Virtual function calls, dynamic heap allocation and exception
handling are all, at best, problematic for verifying performance of
real time code.

Why do you put virtual function calls on that list?

Do you use, or do you know someone who uses, a CPU where a "call
indirect" takes significantly longer than a "call"? (By "significantly
longer" I mean more than 2-3 clock cycles.)
<snip>

Every memory read potentially takes hundreds of cycles if it misses
all caches, and an indirect branch typically requires more memory
reads than a direct branch. In addition, branch prediction for
indirect branches is generally poorer and consequently virtual
function calls are more likely to require a pipeline flush and refill.
I would be surprised if the average overhead was as little as 2-3
clock cycles on any modern processor, not to mention the worst case.

--
Ben Hutchings
Having problems with C++ templates? Your questions may be answered by
<http://womble.decadentplace.org.uk/c++/template-faq.html>.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,567
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top