Re: try...catch slooowness?

2010-12-22 Thread Steven Schveighoffer

On Wed, 22 Dec 2010 15:21:52 -0500, Rob  wrote:


Steven Schveighoffer wrote:

On Tue, 21 Dec 2010 17:16:57 -0500, Rob  wrote:


Walter Bright wrote:

Michel Fortin wrote:

Exceptions are slow, that's a fact of life. The idea is that an
exception should be exceptional, so the case to optimize for is the
case where you don't have any exception: a try...catch that doesn't
throw. Other ways to implement exceptions exists which are faster
at throwing (setjmp for instance), but they're also slower at
entering and exiting a try..catch block when no exception occur.


[...]


Exceptions are recommended to avoid cluttering your normal code
flow with error handling code. Clearly, in the code above
exceptions are part of the normal code flow. That's not what
exception are made for.


Right on all counts. Exceptions are for *exceptional* cases, i.e.
unexpected errors, not normal control flow.


Exceptions (actual ones and not just a reference to any particular
error handling mechanism) are EXPECTED errors. That follows directly
from the goal of keeping programs running by handling of errors that
were thought about at design time. Show me an unexpected error and
I'll show you a bug.


No they aren't.  They are anticipated,


That is how the term "expected" is used in the literature. Read up. No
need to play semantical/literal games. It's the concept that is relevant.
The point is that saying that exceptions are unexpected is incorrect by
just about any paper, article or book on error handling, save for those
that get that wrong also (A. Andrescu's early book gets it wrong also, as
I recall, FWIW).


Sorry, I guess I dummer than you.

-Steve


Re: try...catch slooowness?

2010-12-22 Thread Rob
Steven Schveighoffer wrote:
> On Tue, 21 Dec 2010 17:25:09 -0500, Rob  wrote:
>
>> Steven Schveighoffer wrote:
>>
>>> An exception is a recoverable error,
>>
>> Not necessarily. At some point, all the handling options could have
>> been tried but all failed in which case there is nothing left to do
>> except for letting something higher up (like the operating system)
>> deal with the situation. In such a case, recovery did not occur if
>> you consider recovery to mean that the program keeps running
>> normally.
>
> In D, unrecoverable errors derive from Error, recoverable ones derive
> from Exception.
>
> By 'recovery' I mean that the program can either continue to run or
> decide proactively to do something different (like print an error and
> exit).

That, decidedly, from common terminology usage industry-wide, is 
considered "unrecoverable". "Unrecoverable" doesn't mean crash and burn. 
Anything less than the program staying running is indicates something 
unrecoverable happened.




Re: try...catch slooowness?

2010-12-22 Thread Rob
Steven Schveighoffer wrote:
> On Tue, 21 Dec 2010 17:16:57 -0500, Rob  wrote:
>
>> Walter Bright wrote:
>>> Michel Fortin wrote:
 Exceptions are slow, that's a fact of life. The idea is that an
 exception should be exceptional, so the case to optimize for is the
 case where you don't have any exception: a try...catch that doesn't
 throw. Other ways to implement exceptions exists which are faster
 at throwing (setjmp for instance), but they're also slower at
 entering and exiting a try..catch block when no exception occur.
>>>
>>> [...]
>>>
 Exceptions are recommended to avoid cluttering your normal code
 flow with error handling code. Clearly, in the code above
 exceptions are part of the normal code flow. That's not what
 exception are made for.
>>>
>>> Right on all counts. Exceptions are for *exceptional* cases, i.e.
>>> unexpected errors, not normal control flow.
>>
>> Exceptions (actual ones and not just a reference to any particular
>> error handling mechanism) are EXPECTED errors. That follows directly
>> from the goal of keeping programs running by handling of errors that
>> were thought about at design time. Show me an unexpected error and
>> I'll show you a bug.
>
> No they aren't.  They are anticipated,

That is how the term "expected" is used in the literature. Read up. No 
need to play semantical/literal games. It's the concept that is relevant. 
The point is that saying that exceptions are unexpected is incorrect by 
just about any paper, article or book on error handling, save for those 
that get that wrong also (A. Andrescu's early book gets it wrong also, as 
I recall, FWIW).




Re: try...catch slooowness?

2010-12-22 Thread Steven Schveighoffer

On Tue, 21 Dec 2010 17:25:09 -0500, Rob  wrote:


Steven Schveighoffer wrote:


An exception is a recoverable error,


Not necessarily. At some point, all the handling options could have been
tried but all failed in which case there is nothing left to do except for
letting something higher up (like the operating system) deal with the
situation. In such a case, recovery did not occur if you consider
recovery to mean that the program keeps running normally.


In D, unrecoverable errors derive from Error, recoverable ones derive from  
Exception.


By 'recovery' I mean that the program can either continue to run or decide  
proactively to do something different (like print an error and exit).  But  
control is still in the programmer's hands.



Exception handling is
great when it exists at a much higher level, because you can
essentially do all error handling in one spot, and simply write code
without worrying about error codes.


That sounds like the common misconception that leads to weak designs.


So you tell me, what is a good design with exceptions?  Because it seems  
like doing:


try fn()
catch(Exception) {...}

is pretty ugly and cumbersome (and clearly has performance issues), when  
it could be:


if(fn() != 0)
  ...

To me, if you are surrounding a single low-level call with an exception  
handler, your design has issues.


-Steve


Re: try...catch slooowness?

2010-12-22 Thread Steven Schveighoffer

On Tue, 21 Dec 2010 17:16:57 -0500, Rob  wrote:


Walter Bright wrote:

Michel Fortin wrote:

Exceptions are slow, that's a fact of life. The idea is that an
exception should be exceptional, so the case to optimize for is the
case where you don't have any exception: a try...catch that doesn't
throw. Other ways to implement exceptions exists which are faster at
throwing (setjmp for instance), but they're also slower at entering
and exiting a try..catch block when no exception occur.


[...]


Exceptions are recommended to avoid cluttering your normal code flow
with error handling code. Clearly, in the code above exceptions are
part of the normal code flow. That's not what exception are made for.


Right on all counts. Exceptions are for *exceptional* cases, i.e.
unexpected errors, not normal control flow.


Exceptions (actual ones and not just a reference to any particular error
handling mechanism) are EXPECTED errors. That follows directly from the
goal of keeping programs running by handling of errors that were thought
about at design time. Show me an unexpected error and I'll show you a
bug.


No they aren't.  They are anticipated, but not expected.  For instance, an  
I/O error is not *expected*, but it is anticipated as possible if say the  
config file is not readable, but it's not expected to happen for a normal  
operation.  In this case, the exception most likely kills the program  
(can't do much without a config), but the program handles the error  
gracefully and prints a readable message rather than just "Broken Pipe" or  
something like that.


-Steve


Re: try...catch slooowness?

2010-12-21 Thread Rob
Steven Schveighoffer wrote:

> An exception is a recoverable error,

Not necessarily. At some point, all the handling options could have been 
tried but all failed in which case there is nothing left to do except for 
letting something higher up (like the operating system) deal with the 
situation. In such a case, recovery did not occur if you consider 
recovery to mean that the program keeps running normally.

> Exception handling is
> great when it exists at a much higher level, because you can
> essentially do all error handling in one spot, and simply write code
> without worrying about error codes.

That sounds like the common misconception that leads to weak designs.





Re: try...catch slooowness?

2010-12-21 Thread Rob
Walter Bright wrote:
> Michel Fortin wrote:
>> Exceptions are slow, that's a fact of life. The idea is that an
>> exception should be exceptional, so the case to optimize for is the
>> case where you don't have any exception: a try...catch that doesn't
>> throw. Other ways to implement exceptions exists which are faster at
>> throwing (setjmp for instance), but they're also slower at entering
>> and exiting a try..catch block when no exception occur.
>
> [...]
>
>> Exceptions are recommended to avoid cluttering your normal code flow
>> with error handling code. Clearly, in the code above exceptions are
>> part of the normal code flow. That's not what exception are made for.
>
> Right on all counts. Exceptions are for *exceptional* cases, i.e.
> unexpected errors, not normal control flow.

Exceptions (actual ones and not just a reference to any particular error 
handling mechanism) are EXPECTED errors. That follows directly from the 
goal of keeping programs running by handling of errors that were thought 
about at design time. Show me an unexpected error and I'll show you a 
bug.

>
> The implementation is designed so that the speed normal execution is
> strongly favored over speed of exception handling. 




Re: try...catch slooowness?

2010-12-20 Thread Walter Bright

Michel Fortin wrote:
Exceptions are slow, that's a fact of life. The idea is that an 
exception should be exceptional, so the case to optimize for is the case 
where you don't have any exception: a try...catch that doesn't throw. 
Other ways to implement exceptions exists which are faster at throwing 
(setjmp for instance), but they're also slower at entering and exiting a 
try..catch block when no exception occur.


[...]

Exceptions are recommended to avoid cluttering your normal code flow 
with error handling code. Clearly, in the code above exceptions are part 
of the normal code flow. That's not what exception are made for.


Right on all counts. Exceptions are for *exceptional* cases, i.e. unexpected 
errors, not normal control flow.


The implementation is designed so that the speed normal execution is strongly 
favored over speed of exception handling.


Re: try...catch slooowness?

2010-12-20 Thread spir
On Mon, 20 Dec 2010 12:29:29 -0500
"Steven Schveighoffer"  wrote:

> This example is misleading.  First, catching an exception should be a rare  
> occurrence (literally, an exception to the rule).  You are testing the  
> case where catching an exception vastly outweighs the cases where an  
> exception is not thrown.  What I'm saying is, catching an exception is  
> very slow, but *trying* to catch an exception is not.

Right, understood, thank you.

Denis
-- -- -- -- -- -- --
vit esse estrany ☣

spir.wikidot.com



Re: try...catch slooowness?

2010-12-20 Thread Steven Schveighoffer

On Sun, 19 Dec 2010 07:33:29 -0500, spir  wrote:


Hello,


I had not initially noticed that the 'in' operator (for AAs) returns a  
pointer to the looked up element. So that, to avoid double lookup in  
cases where lookups may fail, I naively used try...catch. In cases of  
very numerous lookups, my code suddenly became blitz fast. So that I  
wondered about exception handling efficiency. Below a test case (on my  
computer, both loops run in about the same average time):


void main () {
byte[uint] table = [3:1, 33:1, 333:1];
byte b;
byte* p;
Time t0;
uint N1 = 246, N2 = 999;
   // try...catch
t0 = time();
foreach (n ; 0..N1) {
try b = table[n];
catch (RangeError e) {}
}
writefln("try...catch version time: %sms", time() - t0);
   // pointer
t0 = time();
foreach (n ; 0..N2) {
p = (n in table);
if (p) b = table[n];
}
writefln("pointer version time: %sms", time() - t0);
   writefln("pointer version is about %s times faster",N2/N1);
}
==>
try...catch version time: 387ms
pointer version time: 388ms
pointer version is about 40650 times faster

Note that both versions perform a single lookup trial; the difference  
thus only lies in pointer deref vs try...catch handling, i guess. What  
do you think?


This example is misleading.  First, catching an exception should be a rare  
occurrence (literally, an exception to the rule).  You are testing the  
case where catching an exception vastly outweighs the cases where an  
exception is not thrown.  What I'm saying is, catching an exception is  
very slow, but *trying* to catch an exception is not.


Second, exception handling is not meant to be used in the way you used  
it.  You don't use it as an extra return value.  I'd expect a more  
reasonable use of catching an exception in AAs as this:


try
{
  foreach(n ; 0..N1)
  {
 b = table[n];
  }
}
catch(RangeError e)
{
   writeln("Caught exception! ", e);
}

An exception is a recoverable error, but it usually means something is  
wrong, not 'business as usual'.  This doesn't mean it's impossible to  
design poor interfaces that use exceptions for everything, but it  
shouldn't be that way.  An exception should always be a rare occurrence,  
when something happens that you don't expect.  A huge clue that you are  
using exceptions poorly or that the interface is not meant to be used that  
way is if your exception handling is being done at the innermost level of  
your program.  Exception handling is great when it exists at a much higher  
level, because you can essentially do all error handling in one spot, and  
simply write code without worrying about error codes.


This is why the 'in' operator exists for AAs.

General rules of thumb for AAs:

1. if you expect that a value is always going to be present when you ask  
for it, use exception handling at a high level.
2. if you *don't* expect that, and want to check the existence of an  
element, use 'in'


Now, after saying all that, improving how exception handling works can  
only be good.  So comparing exception handling performance in D to  
exception handling in other languages can give a better idea of how well  
D's exception handling performs.


-Steve


Re: try...catch slooowness?

2010-12-19 Thread Michel Fortin

On 2010-12-19 08:17:07 -0500, spir  said:


On Sun, 19 Dec 2010 07:46:09 -0500
bearophile  wrote:


spir:


try...catch version time: 387ms
pointer version time: 388ms
pointer version is about 40650 times faster


Those numbers look wrong :-)


I thought so. But in the real app a loop that lasted ~ 10s suddenly became
instantaneous (human perception ;-)
Try it. Sorry, but I'm not inventing the numbers.


What looks wrong is that the output seem to say that 388ms was 40650 
times faster than 387ms. Obviously, by looking at the code one can 
understand that you adjusted the number of iteration to get the same 
time for both versions, and from that number of iteration you can claim 
the pointer version is about X times faster. But the output alone is 
misleading. Add the iteration count to the output and it'll be easier 
to read.


Exceptions are slow, that's a fact of life. The idea is that an 
exception should be exceptional, so the case to optimize for is the 
case where you don't have any exception: a try...catch that doesn't 
throw. Other ways to implement exceptions exists which are faster at 
throwing (setjmp for instance), but they're also slower at entering and 
exiting a try..catch block when no exception occur.




What do you think?


Compared to Oracle Java VM the DMD exceptions are very slow. Performance
tuning of DMD is left for later, when the main features are all present.


And what if the numbers are correct? Exception handling is explicitely reco
mmanded in some docs --as opposed to C-like "manual" hacks.


Exceptions are recommended to avoid cluttering your normal code flow 
with error handling code. Clearly, in the code above exceptions are 
part of the normal code flow. That's not what exception are made for.


That said, I'd encourage you to profile this test case to see where the 
time is being spent. You might find one or two places that can be 
improved in the part of the runtime dedicated to exceptions.



--
Michel Fortin
michel.for...@michelf.com
http://michelf.com/



Re: try...catch slooowness?

2010-12-19 Thread Lutger Blijdestijn
spir wrote:

> Hello,
> 
> 
> I had not initially noticed that the 'in' operator (for AAs) returns a
> pointer to the looked up element. So that, to avoid double lookup in cases
> where lookups may fail, I naively used try...catch. In cases of very
> numerous lookups, my code suddenly became blitz fast. So that I wondered
> about exception handling efficiency. Below a test case (on my computer,
> both loops run in about the same average time):
> 

Catching exceptions is known to be a bit costly. Generally, in C family 
languages with exceptions (such as D), it is considered bad practice to use 
exceptions for regular control flow. The cost is therefore acceptable 
because it is not suffered on the normal, happy code path. 

That the performance cost is so huge is likely not only the inherent 
overhead of exceptions, but probably also some extra cache misses or 
something like that.[needs analysis]



Re: try...catch slooowness?

2010-12-19 Thread spir
On Sun, 19 Dec 2010 07:46:09 -0500
bearophile  wrote:

> spir:
> 
> > try...catch version time: 387ms
> > pointer version time: 388ms
> > pointer version is about 40650 times faster
> 
> Those numbers look wrong :-)

I thought so. But in the real app a loop that lasted ~ 10s suddenly became 
instantaneous (human perception ;-)
Try it. Sorry, but I'm not inventing the numbers.

> > What do you think?
> 
> Compared to Oracle Java VM the DMD exceptions are very slow. Performance 
> tuning of DMD is left for later, when the main features are all present.

And what if the numbers are correct? Exception handling is explicitely 
recommanded in some docs --as opposed to C-like "manual" hacks.


Denis
-- -- -- -- -- -- --
vit esse estrany ☣

spir.wikidot.com



Re: try...catch slooowness?

2010-12-19 Thread spir
On Sun, 19 Dec 2010 07:47:11 -0500
Michel Fortin  wrote:

> On 2010-12-19 07:33:29 -0500, spir  said:
> 
> > // pointer
> > t0 = time();
> > foreach (n ; 0..N2) {
> > p = (n in table);
> > if (p) b = table[n];
> > }
> 
> But why the double lookup? Just dereference the pointer:
> 
>   foreach (n ; 0..N2) {
>   p = (n in table);
>   if (p) b = *p;
>   }

Oops, sorry, code copy error. But this does not change the test result times 
(because nearly no key exists in the table).

denis
-- -- -- -- -- -- --
vit esse estrany ☣

spir.wikidot.com



Re: try...catch slooowness?

2010-12-19 Thread Michel Fortin

On 2010-12-19 07:33:29 -0500, spir  said:


// pointer
t0 = time();
foreach (n ; 0..N2) {
p = (n in table);
if (p) b = table[n];
}


But why the double lookup? Just dereference the pointer:

foreach (n ; 0..N2) {
p = (n in table);
if (p) b = *p;
}


--
Michel Fortin
michel.for...@michelf.com
http://michelf.com/



Re: try...catch slooowness?

2010-12-19 Thread bearophile
spir:

> try...catch version time: 387ms
> pointer version time: 388ms
> pointer version is about 40650 times faster

Those numbers look wrong :-)


> What do you think?

Compared to Oracle Java VM the DMD exceptions are very slow. Performance tuning 
of DMD is left for later, when the main features are all present.

Bye,
bearophile