Overhead of try-catch blocks? 
Author Message
 Overhead of try-catch blocks?

Does anyone have numbers on the overhead (number of machine instructions,
 execution time increase...) added by including a try-catch block in your
 code?  We're using the MS VC++ 6 compiler, but any info is better than
 nothing.

 thanks,

 Colin



Mon, 16 Dec 2002 03:00:00 GMT  
 Overhead of try-catch blocks?
Quote:
> Does anyone have numbers on the overhead (number of machine instructions,
>  execution time increase...) added by including a try-catch block in your
>  code?  We're using the MS VC++ 6 compiler, but any info is better than
>  nothing.

AFAIK there is no overhead for try-catch with VC on Windows NT. Only throw
and stack unwinding technique (it may be turned off if you are not
interested with the final result) will take a bit of resources.

But why do not have a look at the code by yourself?
Just compile the program below with cl -Ox -GX, run your favorite de{*filter*}
and see.
#include <iostream>
int
main()
{
 _asm int 3
 try {
  std::cout << "asdf"; // To have a look at try. Look at the code between
int 3 and pushing parameters for << operator.
  throw 1; // To be dead sure the exceptions would take place
  // There is no use to put a code here to examine the catch. VC will get
rid of it.
 }
 catch (...) {}

Quote:
}

With regards,
Michael Kochetkov.

P.S. What is wrong with microsoft.public.vc.language? Why post here, to
comp.lang.c++?



Tue, 17 Dec 2002 03:00:00 GMT  
 Overhead of try-catch blocks?
Thank you for your response.  I posted to both newsgroups because I wasn't
exclusively interested in the Microsoft compiler implementation.  I don't
quite understand why you need to declare the int using the _asm inline
assembly keyword?

I see the following after the "throw 1;".  Unfortunately, I don't know
enough x86 asm to understand exactly what's happening here.

004014BB   mov         dword ptr [ebp-14h],1
004014C2   push        offset __TI1H (00431100)
004014C7   lea         eax,[ebp-14h]
004014CA   push        eax

(side question re: basic assembly lang: why do we sometimes mov values
relative to the base pointer ebp, and sometimes push values onto the stack?
for example above, we first put 1 at [ebp-14h] then we load it into eax and
push in onto the stack. why not put it directly into the register and push
it?)

I see the value "1" being pushed onto the stack (not clear what all is
happening here...what's "offset _TI1H(...)"??)

_significant_ overhead in here, with the stack frame unwinding and all.

Then for the catch we have:
18:     catch (...) {}
004014D0   mov         eax,offset __tryend$_main$1 (004014d6)
004014D5   ret
19:
20:     return 0;
004014D6   mov         dword ptr [ebp-4],0FFFFFFFFh
004014DD   xor         eax,eax
21:   }

Is this telling the __CxxThrowException function where to return to the
catch block?  Why does it point to (004014d6), and why xor eax with itself?
(sorry for all the novice asm questions...).

So it looks to me like there are just 2 or 3 instructions added for the
try-catch block, and the vast majority of the overhead comes from the actual
throwing of the exception, which in theory shouldn't happen frequently.
Does this correspond with your reading?

The reason I ask in the first place is, we are revising (optimizing) our
company error-handling standard, and trying to determine if extensive use of
try-catch blocks should be discouraged (due to code-bloat causing
performance degradation).  Based on this info, it does not appear to be the
case.  Thoughts?

Thank you for your time!

Colin Reinhardt


Quote:
> > Does anyone have numbers on the overhead (number of machine
instructions,
> >  execution time increase...) added by including a try-catch block in
your
> >  code?  We're using the MS VC++ 6 compiler, but any info is better than
> >  nothing.
> AFAIK there is no overhead for try-catch with VC on Windows NT. Only throw
> and stack unwinding technique (it may be turned off if you are not
> interested with the final result) will take a bit of resources.

> But why do not have a look at the code by yourself?
> Just compile the program below with cl -Ox -GX, run your favorite de{*filter*}
> and see.
> #include <iostream>
> int
> main()
> {
>  _asm int 3
>  try {
>   std::cout << "asdf"; // To have a look at try. Look at the code between
> int 3 and pushing parameters for << operator.
>   throw 1; // To be dead sure the exceptions would take place
>   // There is no use to put a code here to examine the catch. VC will get
> rid of it.
>  }
>  catch (...) {}
> }

> With regards,
> Michael Kochetkov.

> P.S. What is wrong with microsoft.public.vc.language? Why post here, to
> comp.lang.c++?



Tue, 17 Dec 2002 03:00:00 GMT  
 Overhead of try-catch blocks?


Quote:
> Thank you for your response.  I posted to both newsgroups because I wasn't
> exclusively interested in the Microsoft compiler implementation.  I don't
> quite understand why you need to declare the int using the _asm inline
> assembly keyword?

It is because I am lazy. Believe me, it is much easier to set a break-point
and make a de{*filter*} stop there then to disassemple (or produce disassembled
code) and look for the proper place then. Wow, I read your question again
and begin to understand it. But I will not wipe the beginning of my replay.
It may be useful.

It is not a declaration. It is the assembler instruction which means the
third interrupt (de{*filter*} interrupt). When you run the program I have
written under a de{*filter*} it would get stopped at the point of 'int 3'
instruction and you can see what you want easlily.

Quote:

> I see the following after the "throw 1;".  Unfortunately, I don't know
> enough x86 asm to understand exactly what's happening here.

> 004014BB   mov         dword ptr [ebp-14h],1
> 004014C2   push        offset __TI1H (00431100)
> 004014C7   lea         eax,[ebp-14h]
> 004014CA   push        eax

Awfull optimization. lea eax,[ebp-14h] and push  eax should be separated for
concurrent excecution. Do you have SP4 installed? In this place it is not
critical but I have serious claim to VC SP3 for it's optimization features.
You might wish to have a look at my thread "I am stuck with VC optimization
..." or something like this at the microsoft.public.vc.language. SP4 makes
the things better.

The code above is the overheads for throw. You do not expect throws in the
normal program execution, do you? So this code will not excecute. Just a
conditional jump over it in the real life.
There should be some stack unwinding preparation code at the main entrance
too.

Quote:

> (side question re: basic assembly lang: why do we sometimes mov values
> relative to the base pointer ebp, and sometimes push values onto the
stack?
> for example above, we first put 1 at [ebp-14h] then we load it into eax
and
> push in onto the stack. why not put it directly into the register and push
> it?)

> I see the value "1" being pushed onto the stack (not clear what all is
> happening here...what's "offset _TI1H(...)"??)

> _significant_ overhead in here, with the stack frame unwinding and all.

> Then for the catch we have:
> 18:     catch (...) {}
> 004014D0   mov         eax,offset __tryend$_main$1 (004014d6)
> 004014D5   ret
> 19:
> 20:     return 0;
> 004014D6   mov         dword ptr [ebp-4],0FFFFFFFFh
> 004014DD   xor         eax,eax
> 21:   }

> Is this telling the __CxxThrowException function where to return to the
> catch block?  Why does it point to (004014d6), and why xor eax with
itself?
> (sorry for all the novice asm questions...).

It will do some Microsoft things, I suppose.

Quote:

> So it looks to me like there are just 2 or 3 instructions added for the

And the stack unwinding semantics code at the beginning of each function
which declaration misses throw().

Quote:
> try-catch block, and the vast majority of the overhead comes from the
actual
> throwing of the exception, which in theory shouldn't happen frequently.
> Does this correspond with your reading?

Yes, it does.

Quote:

> The reason I ask in the first place is, we are revising (optimizing) our
> company error-handling standard, and trying to determine if extensive use
of
> try-catch blocks should be discouraged (due to code-bloat causing

Try-catch blocks and stack unwinding semantics being enabled. It is
important, please, see below.

Quote:
> performance degradation).  Based on this info, it does not appear to be
the
> case.  Thoughts?

IMO exceptions are Ok on NT with MS VC.

The only wish (I mean advice) do not forget to point throw() in those
functions' declarations that do not throw. It should eliminate the stack
unwinding semantics code at the beginning of such functions.

With regards,
Michael Kochetkov.



Tue, 17 Dec 2002 03:00:00 GMT  
 Overhead of try-catch blocks?

Quote:

> exclusively interested in the Microsoft compiler implementation.  I don't
> quite understand why you need to declare the int using the _asm inline
> assembly keyword?

It's just a trick to make the de{*filter*} kick in right there.  It could
have just as easily been a call to ::DebugBreak(); instead of inlined
assembly.

Quote:
> I see the following after the "throw 1;".  Unfortunately, I don't know
> enough x86 asm to understand exactly what's happening here.

Me neither. :)

Quote:
> catch block?  Why does it point to (004014d6), and why xor eax with
> itself?  (sorry for all the novice asm questions...).

I think that long ago it was discovered that for some reason xor'ing a
register with itself produced the value zero faster than using a
literal value zero.  But I'm not really sure about that.

Quote:
> So it looks to me like there are just 2 or 3 instructions added for
> the try-catch block, and the vast majority of the overhead comes
> from the actual throwing of the exception, which in theory shouldn't
> happen frequently.  Does this correspond with your reading?

It varies from compiler to compiler.  I believe that is correct for
VC++, but I don't know.  Some are significantly less efficient than
VC++, at the expense of being more correct.

Quote:
> The reason I ask in the first place is, we are revising (optimizing)
> our company error-handling standard, and trying to determine if
> extensive use of try-catch blocks should be discouraged (due to
> code-bloat causing performance degradation).  Based on this info, it
> does not appear to be the case.  Thoughts?

Writing exception safe code is no easy job, and it does affect design
decisions.  Also, I'd consider an extensive use of try-catch blocks as
overkill for most situations.  If you're thinking about using
exceptions heavily, you should invest some time in getting comfortable
with using the "Resource Acquisition is Initialization" pattern.
These local objects can do cleanup in their destructor, and remove the
need (and a lot of the overhead) for try-catch blocks.

Obviously, an exception has to eventually be caught, but for
intermediate calls in the callstack unwinding, if they don't do
anything but cleanup their local work, RAII can be a much better
solution.

I'd *highly* recommend you read Herb Sutter's "Exceptional C++" for
good exception-handling and exception-safety techniques.  If you're
establishing policy, make sure the decisions are made understanding
all the ramifications of it, before it is put into place.

--
Chris



Tue, 17 Dec 2002 03:00:00 GMT  
 Overhead of try-catch blocks?
Thanks again for even more good info.  Regarding your comment about "don't
forget to point throw()...", do you mean to use explicit exception
specifications? (eg.  HRESULT myFuncWhichDoesntThrow( int, char* )
throw(); )
The compiler will then be smart enough to leave the extra instructions out,
huh?  Good point.  Thanks!

Colin


Quote:



> > Thank you for your response.  I posted to both newsgroups because I
wasn't
> > exclusively interested in the Microsoft compiler implementation.  I
don't
> > quite understand why you need to declare the int using the _asm inline
> > assembly keyword?
> It is because I am lazy. Believe me, it is much easier to set a
break-point
> and make a de{*filter*} stop there then to disassemple (or produce
disassembled
> code) and look for the proper place then. Wow, I read your question again
> and begin to understand it. But I will not wipe the beginning of my
replay.
> It may be useful.

> It is not a declaration. It is the assembler instruction which means the
> third interrupt (de{*filter*} interrupt). When you run the program I have
> written under a de{*filter*} it would get stopped at the point of 'int 3'
> instruction and you can see what you want easlily.

> > I see the following after the "throw 1;".  Unfortunately, I don't know
> > enough x86 asm to understand exactly what's happening here.

> > 004014BB   mov         dword ptr [ebp-14h],1
> > 004014C2   push        offset __TI1H (00431100)
> > 004014C7   lea         eax,[ebp-14h]
> > 004014CA   push        eax
> Awfull optimization. lea eax,[ebp-14h] and push  eax should be separated
for
> concurrent excecution. Do you have SP4 installed? In this place it is not
> critical but I have serious claim to VC SP3 for it's optimization
features.
> You might wish to have a look at my thread "I am stuck with VC
optimization
> ..." or something like this at the microsoft.public.vc.language. SP4 makes
> the things better.


> The code above is the overheads for throw. You do not expect throws in the
> normal program execution, do you? So this code will not excecute. Just a
> conditional jump over it in the real life.
> There should be some stack unwinding preparation code at the main entrance
> too.

> > (side question re: basic assembly lang: why do we sometimes mov values
> > relative to the base pointer ebp, and sometimes push values onto the
> stack?
> > for example above, we first put 1 at [ebp-14h] then we load it into eax
> and
> > push in onto the stack. why not put it directly into the register and
push
> > it?)

> > I see the value "1" being pushed onto the stack (not clear what all is
> > happening here...what's "offset _TI1H(...)"??)

> > _significant_ overhead in here, with the stack frame unwinding and all.

> > Then for the catch we have:
> > 18:     catch (...) {}
> > 004014D0   mov         eax,offset __tryend$_main$1 (004014d6)
> > 004014D5   ret
> > 19:
> > 20:     return 0;
> > 004014D6   mov         dword ptr [ebp-4],0FFFFFFFFh
> > 004014DD   xor         eax,eax
> > 21:   }

> > Is this telling the __CxxThrowException function where to return to the
> > catch block?  Why does it point to (004014d6), and why xor eax with
> itself?
> > (sorry for all the novice asm questions...).
> It will do some Microsoft things, I suppose.

> > So it looks to me like there are just 2 or 3 instructions added for the
> And the stack unwinding semantics code at the beginning of each function
> which declaration misses throw().

> > try-catch block, and the vast majority of the overhead comes from the
> actual
> > throwing of the exception, which in theory shouldn't happen frequently.
> > Does this correspond with your reading?
> Yes, it does.

> > The reason I ask in the first place is, we are revising (optimizing) our
> > company error-handling standard, and trying to determine if extensive
use
> of
> > try-catch blocks should be discouraged (due to code-bloat causing
> Try-catch blocks and stack unwinding semantics being enabled. It is
> important, please, see below.

> > performance degradation).  Based on this info, it does not appear to be
> the
> > case.  Thoughts?
> IMO exceptions are Ok on NT with MS VC.

> The only wish (I mean advice) do not forget to point throw() in those
> functions' declarations that do not throw. It should eliminate the stack
> unwinding semantics code at the beginning of such functions.

> With regards,
> Michael Kochetkov.



Tue, 17 Dec 2002 03:00:00 GMT  
 Overhead of try-catch blocks?

Quote:

> The only wish (I mean advice) do not forget to point throw() in those
> functions' declarations that do not throw. It should eliminate the stack
> unwinding semantics code at the beginning of such functions.

I don't think it should.  The compiler is supposed to generate code
that verifies that no exception is thrown that is not in the
specification.  This test is done at runtime, not at compile time.  If
the compiler optimizes this away, it's probably not going to be able
to do this testing.

Then, a function actually *does* throw an exception that is outside
the set of its exception specifications, somthing needs to call
unexpected().

I don't believe VC++ implements exception specifications.  Not sure if
SP4 addresses this or not.  But I think that for the most part they
are completely ignored.  (Or that at least has been the case.)

--
Chris



Tue, 17 Dec 2002 03:00:00 GMT  
 Overhead of try-catch blocks?


..................................................................

Quote:

> I see the following after the "throw 1;".  Unfortunately, I don't know
> enough x86 asm to understand exactly what's happening here.

> 004014BB   mov         dword ptr [ebp-14h],1

 *(int*)(stack_base_pointer - 0x14) = 1.

Quote:
> 004014C2   push        offset __TI1H (00431100)

push( &var); // can't see what is it
address (reference)is pushed onto stack, ESP( stack pointer) is decreased by
address size (4 bytes)

Quote:
> 004014C7   lea         eax,[ebp-14h]

eax=(int)(ebp-0x14);
effective address (reference) to stack variable which holds 1 is loaded into
EAX (acumulator) register.

Quote:
> 004014CA   push        eax

push (&throw_arg);
Address (pointer value) is now pushed . ESP goes down once again.
Michael is right here, these instructions depends on each other,
so it might cause cycle or two stall, so scheduling doesn't look
good.

ESP (stack pointer) down, EIP (instruction pointer) is loaded with called
address.

Quote:

> (side question re: basic assembly lang: why do we sometimes mov values
> relative to the base pointer ebp, and sometimes push values onto the
stack?
> for example above, we first put 1 at [ebp-14h] then we load it into eax
and
> push in onto the stack. why not put it directly into the register and push
> it?)

Good question. Because reference to 1, rather then value is used, I think.
Probably there are good reasons for this.

Quote:
> Then for the catch we have:
> 18:     catch (...) {}
> 004014D0   mov         eax,offset __tryend$_main$1 (004014d6)

address (offset) is moved to eax
eax=(int)&__tryend$_main$1;

Quote:
> 004014D5   ret

ret to exception function,
which I suppose calls 4014d6. So eax probably holds
address of proc to jump.

Quote:
> 19:
> 20:     return 0;
> 004014D6   mov         dword ptr [ebp-4],0FFFFFFFFh

*(int*)(ebp-4)=0xFFFFFFFF;

top of stack frame is filled with all 1's, markup that stack is now empty?

Quote:
> 004014DD   xor         eax,eax
> 21:   }

eax^=eax;
return value in eax?

Quote:
> Is this telling the __CxxThrowException function where to return to the
> catch block?

probably.

Quote:
>  Why does it point to (004014d6), and why xor eax with itself?
> (sorry for all the novice asm questions...).

jump address and retval (probably).

Quote:

> So it looks to me like there are just 2 or 3 instructions added for the
> try-catch block, and the vast majority of the overhead comes from the
actual
> throwing of the exception, which in theory shouldn't happen frequently.
> Does this correspond with your reading?

Overhead for throwing exception is compensated by a fact that you can
eliminate lot of check statements in code and you can have better error
handling.

Quote:

> The reason I ask in the first place is, we are revising (optimizing) our
> company error-handling standard, and trying to determine if extensive use
of
> try-catch blocks should be discouraged (due to code-bloat causing
> performance degradation).  Based on this info, it does not appear to be
the
> case.  Thoughts?

Actually they are just function calls, not much. If you don't use them you
have to use something else so there is another overhead , plus more
complicated error handling, IMO.
After all, everything depends on design.

Quote:

> Thank you for your time!

> Colin Reinhardt

Greetings, Bane.

My ISP's news server is back from the dead.:)



Wed, 18 Dec 2002 03:00:00 GMT  
 Overhead of try-catch blocks?
Quote:
> Thanks again for even more good info.  Regarding your comment about "don't
> forget to point throw()...", do you mean to use explicit exception
> specifications? (eg.  HRESULT myFuncWhichDoesntThrow( int, char* )
> throw(); )
> The compiler will then be smart enough to leave the extra instructions
out,
> huh?  Good point.  Thanks!

That is very easy to check. Let us consider the code:
void
f1()
{
 throw 1;
Quote:
}

void
f() /*throw()*/
{
 try {
 f1();
 }
 catch (...) {
 }
Quote:
}

int
main()
{
 _asm int 3
 try {
  f();
 }
 catch (...) {
 }
Quote:
}

with throw() being commented. Our main header will look like this:
push   ebp
mov    ebp,esp
push   FFFFFFFF
push   004054EA
mov    eax,fs:[00000000]
push   eax
mov    fs:[00000000],esp
push   ecx
push   ebx
push   esi
push   edi
mov    [ebp-10],esp

Then let us uncomment throw() and our main function will look like this:
jmp    J206.00401020

There is a little bit difference there, is not it? This cute compiler even
do not return from main. Just type return 0; or something like this and
there would be a function call followed by xor eax,eax and ret.

With regards,
Michael Kochetkov.



Wed, 18 Dec 2002 03:00:00 GMT  
 Overhead of try-catch blocks?


Quote:

> > The only wish (I mean advice) do not forget to point throw() in those
> > functions' declarations that do not throw. It should eliminate the stack
> > unwinding semantics code at the beginning of such functions.

> I don't think it should.  The compiler is supposed to generate code

It must not do it but it will do it just to give you a pleasure. Please, see
my reply to Colin.

Quote:
> that verifies that no exception is thrown that is not in the
> specification.  This test is done at runtime, not at compile time.  If
> the compiler optimizes this away, it's probably not going to be able
> to do this testing.

> Then, a function actually *does* throw an exception that is outside
> the set of its exception specifications, somthing needs to call
> unexpected().

> I don't believe VC++ implements exception specifications.  Not sure if
> SP4 addresses this or not.  But I think that for the most part they
> are completely ignored.  (Or that at least has been the case.)

There is no need to believe it or not. The things we a talking about are
easily revealed by examples. You even do not need to read SP4 bug-fix list
on the msdn site.

With regards,
Michael Kochetkov.



Wed, 18 Dec 2002 03:00:00 GMT  
 Overhead of try-catch blocks?

Quote:


> > I don't believe VC++ implements exception specifications.  Not
> > sure if SP4 addresses this or not.  But I think that for the most
> > part they are completely ignored.  (Or that at least has been the
> > case.)
> There is no need to believe it or not. The things we a talking about
> are easily revealed by examples. You even do not need to read SP4
> bug-fix list on the msdn site.

Actually, it's a little more difficult than that.  I don't even have a
windows machine with VC++ on it, and do most of my work on Linux.

I just read this (VC++) group for threads that look to have
interesting topics.

--
Chris



Wed, 18 Dec 2002 03:00:00 GMT  
 
 [ 13 post ] 

 Relevant Pages 

1. The if ~ else block in try~catch block

2. TRY-CATCH vs. try-catch

3. try/catch VS TRY/CATCH

4. Optimizer ignores try-catch block

5. try catch block

6. does atl support try..catch block?(empty inside)

7. /Og causes intermittent omission of try..catch block

8. nested try/catch block and _set_se_translator

9. try{} catch{} block and Global Optimization

10. Error processing using try-catch blocks

11. can I nest try/catch blocks?

12. Try catch blocks - can multiple methods share a single try/catch combination?

 

 
Powered by phpBB® Forum Software