Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Real life cost of using exceptions for control flow?

0 views
Skip to first unread message

Miyra

unread,
Jun 10, 2004, 6:29:03 PM6/10/04
to
Hi. I'm working with an app that uses exceptions for control flow.
These are code blocks where exceptions are thrown/caught regularly. A
couple hundred exceptions occur per hour and they're caught close to
the point of origination. I'm trying to decide whether to refactor...

What is the cost of throwing an exception in the CLR - relative to,
say, a conditional statement? Are we taking talking 1+ orders of
magnitude? Is there significant churn in the CLR? Are my timers and
threads going to suffer drift or unnecessary swaps each time an
exception get fired?

Thanks for anyone's input. I've spent time snooping the news groups
and csharp.net, but haven't run into a great answer yet (besides
"don't use exceptions for control flow" arguments :-)

-Miyra

ps: Developing with MS Visual C# NET.

ps: Here are some links I found
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndotnet/html/dotnetperftips.asp
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndotnet/html/highperfmanagedapps.asp
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag/html/scalenetchapt15.asp

no potted meat@hotmail.com David Browne

unread,
Jun 10, 2004, 6:56:12 PM6/10/04
to

"Miyra" <miy...@yahoo.com> wrote in message
news:a07d6578.04061...@posting.google.com...

> Hi. I'm working with an app that uses exceptions for control flow.
> These are code blocks where exceptions are thrown/caught regularly. A
> couple hundred exceptions occur per hour and they're caught close to
> the point of origination. I'm trying to decide whether to refactor...
>
A couple hundred exceptions per hour is not on an order of magnatude where
you should be concerned for performance reasons.

David


David Levine

unread,
Jun 10, 2004, 8:02:29 PM6/10/04
to

"Miyra" <miy...@yahoo.com> wrote in message
news:a07d6578.04061...@posting.google.com...
> Hi. I'm working with an app that uses exceptions for control flow.
> These are code blocks where exceptions are thrown/caught regularly. A
> couple hundred exceptions occur per hour and they're caught close to
> the point of origination. I'm trying to decide whether to refactor...
>
> What is the cost of throwing an exception in the CLR - relative to,
> say, a conditional statement? Are we taking talking 1+ orders of
> magnitude? Is there significant churn in the CLR? Are my timers and
> threads going to suffer drift or unnecessary swaps each time an
> exception get fired?
>
> Thanks for anyone's input. I've spent time snooping the news groups
> and csharp.net, but haven't run into a great answer yet (besides
> "don't use exceptions for control flow" arguments :-)
>

As with most other issues in software, what you should or should not do
depends on your circumstances. The general rule of not using exceptions for
flow control is sound advice for 99.9999% of the apps, and the best approach
to take is to follow that rule unless you can prove you need to break it. In
other words, you should always follow the rule...unless you shouldn't.

That being said, here is the general sequence of events on a standard
Windows OS (NT/XP) when an exception is thrown...

1. Transition to kernel mode and build a trap frame (similar to what happens
when a hardware interrupt occurs) and create an exception record and hand it
to the exception dispatcher.
2. Notify the Win32 subsystem through its exception LPC port.
3. Determine if a debugger is attached. If so it sends a first chance
exception to the debugger via the LPC port (actually sent via the session
manager which dispatches it to the appropriate debugger process).
4. If no debugger is present or if it was not handled the dispatcher
switches to user mode and locates a frame-based exception handler. This is
pure Win32 SEH, not the .NET mechanism, but the process is similar. It walks
the stack searching for a registered exception handler.
5. If no handler is found or none of the handlers disposed of the exception
the dispatcher swiches back to kernel mode and calls the debugger again.
This is the 2nd chance notification.
6. If still not handled the win32 subsystem unhandled exception handler gets
invoked (Dr. Watson pops up).
7. If still not handled by the environment subsystem it is handled by the
kernel's default handler, which will terminate the application.

Built into step 4 is all or most of the .NET runtime's handling of the
exception. It is modeled after the Win32 implementation of Structured
Exception Handling (SEH) but in a plaform neutral way (at least, that's the
promise). Locating an exception handler on the faulted stack may also
involve one or more transitions between managed and unmanaged code. SEH uses
a two pass mechanism for locating a handler and then executing finally
blocks between the faulting instruction and the catch block that will handle
the exception.

In pure .NET terms, when an exception is thrown and control given to the
.net runtime, it searches the callstack looking for a handler. This is the
first pass, and exception filters, both type and user (C# does not have user
filters but VB does) run during this first pass. When a handler is found it
records the catch handler location, then goes back to the beginning of the
stack and begins the 2nd pass to unwind the stack. All finally blocks
between the faulting instruction and the catch handler run to completion;
the finally blocks associated activation records are removed from the stack
so that if a nested exception occurs the finally block will only run once.
This ensures that the stack is in a reasonable state before the catch
handler runs.

Once the 2nd pass has completed the catch handler runs. At this point if
another exception is thrown the process repeats.


As you can see this is many orders of magnitude more complicated then
executing an if-then-else statement. Also, because throwing an exception
involves a roundtrip through the kernel and the Win32 subsytem, it is
inherently non-local and therefore is extremely non-performant - you are
almost guaranteed cache misses, etc. And since code in a finally block is
potentially unbounded there is no guarantee when, if ever, the code in the
catch block will get to run. Several hundred/hour does not sound like much,
but perhaps it is an indication of some other problem, perhaps in design or
implementation, that needs to be addressed.

There are other, more high-level reasons for not throwing exceptions for
flow control. For one, depending on the component, you might want to log the
exception at the point where it initially occurs, and then once again if it
is going to escape the boundaries of the module - recording 100s/hour will
fill any log file pretty quickly. For another, it is more maintainable to
keep error handling code separate from flow-control code. There are lots of
other reasons, but this message is already too long.

If it were me, I would refactor.

cheers,
Dave

Jimi

unread,
Jun 10, 2004, 11:21:06 PM6/10/04
to
> Miyrawrote:


Posted Via Usenet.com Premium Usenet Newsgroup Services
----------------------------------------------------------
** SPEED ** RETENTION ** COMPLETION ** ANONYMITY **
----------------------------------------------------------
http://www.usenet.com

Jimi

unread,
Jun 10, 2004, 11:21:07 PM6/10/04
to
In addition to the performance cost of using exceptions for control
flow, this is just bad coding (sorry, I don't know a nicer way of
saying it).

To base your mainstream logic around "oops - that was bad, let's do
this then, oops - that's not good, try this, oops.... etc" is sloppy.
Exceptions should always be reserved for either (1) cases where you
really didn't expect something (and then you basically just gather
the call stack for error log information) or (2) cases where there's
just no other way of testing without trying it and catching an
exception. In my own work I've found that (2) is quite unusual (but
occasionally necessary).

Randy A. Ynchausti

unread,
Jun 11, 2004, 4:01:07 AM6/11/04
to
Miyra,

> Hi. I'm working with an app that uses exceptions for control flow.
> These are code blocks where exceptions are thrown/caught regularly. A
> couple hundred exceptions occur per hour and they're caught close to
> the point of origination. I'm trying to decide whether to refactor...

The only answer that will yield you proof positive is to use a profiler and
see if the exception code, as written in your application, is really a
performance bottleneck. If so, refactor it. If not, get over it and move
on.

Regards,

Randy


0 new messages