June 29, 2005
On Wed, 29 Jun 2005 08:20:51 -0700, Brad Beveridge <brad@somewhere.net> wrote:
> Regan Heath wrote:
>
>> In other words approx 7s for exception handling and 16 milliseconds for  return codes (likely this equals the time required to call the functions  in both cases). Exception handling is then approximately 437 times slower.  A single exception took approx 7/1000 of a milliseccond.
>>  Regan
>
>  From those numbers, assuming that the functions you call do nothing - if you expect to get errors only 1 in 437 runs then it is the same to check for error as it is to throw an exception.

I see where you're heading :)

> Regan, would you mind running those tests again & _NOT_ throwing any exceptions?  I'd like to confirm that code that can throw exceptions (but doesn't) is faster in the usual case than checking error codes.

It seems having exceptions there, but not throwing is slightly slower. But still faster than you'll ever notice.

C:\Library\D\src\temp>extime
1000000 error codes returned in (0.015)
1000000 exceptions thrown and caught in (0.032)
1000000 exceptions thrown and caught in (0.062)
1000000 exceptions thrown and caught in (0.078)
1000000 exceptions thrown and caught in (0.094)

C:\Library\D\src\temp>extime
1000000 error codes returned in (0.015)
1000000 exceptions thrown and caught in (0.063)
1000000 exceptions thrown and caught in (0.062)
1000000 exceptions thrown and caught in (0.079)
1000000 exceptions thrown and caught in (0.078)

C:\Library\D\src\temp>extime
1000000 error codes returned in (0.016)
1000000 exceptions thrown and caught in (0.062)
1000000 exceptions thrown and caught in (0.047)  <- that's odd?
1000000 exceptions thrown and caught in (0.078)
1000000 exceptions thrown and caught in (0.094)

> I'm from a C background though & checking error code still feels more natural to me :)

Same here. I've been doing a little java recently and things like:

RandomAccessFile f = null;

try {
  ..open/use f here..
} catch (IOException ex) {
  ..handle error..
} finally {
  try { if (f != null) f.close();
  } catch (IOException ex) {}
}

just seem weird/wrong to me. Maybe I'm just coding this wrong? (advice appreciated)

Regan
June 29, 2005
The modified code:

int throws(int i)
{
	if (false) throw new Exception(toString(i));
	return i;
}

int intermediate(int i)
{
	return throws(i);
}

int intermediate2(int i)
{
	return intermediate(i);
}

int intermediate3(int i)
{
	return intermediate2(i);
}

everything else the same.

Regan

On Thu, 30 Jun 2005 10:22:06 +1200, Regan Heath <regan@netwin.co.nz> wrote:
> On Wed, 29 Jun 2005 08:20:51 -0700, Brad Beveridge <brad@somewhere.net> wrote:
>> Regan Heath wrote:
>>
>>> In other words approx 7s for exception handling and 16 milliseconds for  return codes (likely this equals the time required to call the functions  in both cases). Exception handling is then approximately 437 times slower.  A single exception took approx 7/1000 of a milliseccond.
>>>  Regan
>>
>>  From those numbers, assuming that the functions you call do nothing - if you expect to get errors only 1 in 437 runs then it is the same to check for error as it is to throw an exception.
>
> I see where you're heading :)
>
>> Regan, would you mind running those tests again & _NOT_ throwing any exceptions?  I'd like to confirm that code that can throw exceptions (but doesn't) is faster in the usual case than checking error codes.
>
> It seems having exceptions there, but not throwing is slightly slower. But still faster than you'll ever notice.
>
> C:\Library\D\src\temp>extime
> 1000000 error codes returned in (0.015)
> 1000000 exceptions thrown and caught in (0.032)
> 1000000 exceptions thrown and caught in (0.062)
> 1000000 exceptions thrown and caught in (0.078)
> 1000000 exceptions thrown and caught in (0.094)
>
> C:\Library\D\src\temp>extime
> 1000000 error codes returned in (0.015)
> 1000000 exceptions thrown and caught in (0.063)
> 1000000 exceptions thrown and caught in (0.062)
> 1000000 exceptions thrown and caught in (0.079)
> 1000000 exceptions thrown and caught in (0.078)
>
> C:\Library\D\src\temp>extime
> 1000000 error codes returned in (0.016)
> 1000000 exceptions thrown and caught in (0.062)
> 1000000 exceptions thrown and caught in (0.047)  <- that's odd?
> 1000000 exceptions thrown and caught in (0.078)
> 1000000 exceptions thrown and caught in (0.094)
>
>> I'm from a C background though & checking error code still feels more natural to me :)
>
> Same here. I've been doing a little java recently and things like:
>
> RandomAccessFile f = null;
>
> try {
>    ..open/use f here..
> } catch (IOException ex) {
>    ..handle error..
> } finally {
>    try { if (f != null) f.close();
>    } catch (IOException ex) {}
> }
>
> just seem weird/wrong to me. Maybe I'm just coding this wrong? (advice appreciated)
>
> Regan

June 30, 2005
Are you sure you're not measuring the performance of new Exception(toString(i))
here ? Especially toString(i) ? I don't think your benchmark is very fair,
because in one case you are purely stack based, and in the other you are
allocating tons of objects on the heap.

Regards,
Nicolas

In article <opss4jgrgc23k2f5@nrage.netwin.co.nz>, Regan Heath says...
>
>Ok, so I figured why not try and time the exception handling. Here is what I came up with:
>
>import std.stdio;
>import std.string;
>import std.c.time;
>extern(C)
>{
>	struct timeb
>	{
>		time_t time;
>		ushort millitm;
>		short timezone, dstflag;
>	}
>
>	void _ftime(timeb *);
>	alias _ftime ftime;
>}
>
>double diff(timeb* start, timeb* finish)
>{
>	double d;
>
>	d =  finish.time-start.time;
>	d += (cast(double)(finish.millitm-start.millitm))/1000.0;
>	return d;
>}
>
>const int ITERATIONS = 1000000;
>
>void throws(int i)
>{
>	throw new Exception(toString(i));
>}
>
>void intermediate(int i)
>{
>	throws(i);
>}
>
>void intermediate2(int i)
>{
>	intermediate(i);
>}
>
>void intermediate3(int i)
>{
>	intermediate2(i);
>}
>
>int returns(int i)
>{
>	return i;
>}
>
>void main()
>{
>	timeb start;
>	timeb finish;
>	int r;
>
>	ftime(&start);
>	for(int i = 0; i < ITERATIONS; i++) {
>		try {
>			r = returns(i);
>		}
>		catch (Exception e) {
>		}
>	}
>	ftime(&finish);
>	writefln(ITERATIONS," error codes returned in
>(",diff(&start,&finish),")");
>
>	ftime(&start);
>	for(int i = 0; i < ITERATIONS; i++) {
>		try {
>			throws(i);
>		}
>		catch (Exception e) {
>		}
>	}
>	ftime(&finish);
>	writefln(ITERATIONS," exceptions thrown and caught in
>(",diff(&start,&finish),")");
>
>	ftime(&start);
>	for(int i = 0; i < ITERATIONS; i++) {
>		try {
>			intermediate(i);
>		}
>			catch (Exception e) {
>		}
>	}
>	ftime(&finish);
>	writefln(ITERATIONS," exceptions thrown and caught in
>(",diff(&start,&finish),")");
>
>	ftime(&start);
>	for(int i = 0; i < ITERATIONS; i++) {
>		try {
>			intermediate2(i);
>		}
>			catch (Exception e) {
>		}
>	}
>	ftime(&finish);
>	writefln(ITERATIONS," exceptions thrown and caught in
>(",diff(&start,&finish),")");
>
>	ftime(&start);
>	for(int i = 0; i < ITERATIONS; i++) {
>		try {
>			intermediate3(i);
>		}
>			catch (Exception e) {
>		}
>	}
>	ftime(&finish);
>	writefln(ITERATIONS," exceptions thrown and caught in
>(",diff(&start,&finish),")");
>}
>
>Giving me these results:
>
>C:\Library\D\src\temp>extime
>1000000 error codes returned in (0.016)
>1000000 exceptions thrown and caught in (7.125)
>1000000 exceptions thrown and caught in (6.969)
>1000000 exceptions thrown and caught in (6.969)
>1000000 exceptions thrown and caught in (7.109)
>
>In other words approx 7s for exception handling and 16 milliseconds for return codes (likely this equals the time required to call the functions in both cases). Exception handling is then approximately 437 times slower. A single exception took approx 7/1000 of a milliseccond.
>
>Regan
>
>On Wed, 29 Jun 2005 05:06:02 +0000 (UTC), AJG <AJG_member@pathlink.com> wrote:
>
>> Hi Jarrett (and others too, please do read on),
>>
>> Thanks for the info. I was hoping some of the things in the spec were
>> outdated,
>> and I still hope it's the case, because exceptions are too powerful to
>> relagate
>> to exceptional situations only.
>>
>> I think in a way the spec contradicts itself. First, it list all the
>> things it
>> wants to eliminate:
>> - Returning a NULL pointer.
>> - Returning a 0 value.
>> - Returning a non-zero error code.
>> - Requiring errno to be checked.
>> - Requiring that a function be called to check if the previous function
>> failed
>>
>> But then it goes on to say what you quoted, which makes it all
>> irrelevant,
>> because you are almost never going to encounter these "errors" anyway.
>>
>>> But really, the question is - why would you design an application to
>>> throw
>>> an exception for anything _other_ than absolutely exceptional
>>> circumstances?
>>> I think it's more of a design issue than anything.
>>
>> I disagree here. I think errors happen _all the time_, and they _are_
>> part of
>> the normal program flow. If we use exceptions only as recommended (a very
>> limited subset of errors, the exceptional "catastrophic" ones), we are
>> back to
>> the very "tedious error handling code" we set out to remove in the first
>> place.
>> It's back to the same ol' dirty clutter.
>>
>> Let me give you an example. Suppose I am building an application that
>> requires
>> the user to input a sequence of integers, and it does some  processing
>> with
>> them; say, from the command-line. Here it is, with no "handling" in
>> place at
>> all:
>>
>> # import std.conv;
>> # alias char[] string;
>> #
>> # int processInt(int input) {
>> #     int output;
>> #     // Processing.
>> #     return (output);
>> # }
>> #
>> # main(string[] args) {
>> #     foreach (int index, string arg; args[1 .. length]) {
>> #         int temp = toInt(arg);
>> #         int result = processInt(temp);
>> #         printf("[#%d] %d => %d\n", index, temp, result);
>> #     }
>> # }
>>
>> Now, in an ideal world, the user will enter perfectly formatter integers,
>> without a single mistake, and it  would all be dandy. But that's not
>> going to
>> happen. And you _know_ that, so you _expect_ an error of this kind. It
>> _is_ part
>> of  the regular program flow.
>>
>> Luckily for us, exceptions come into play and save this "quick-and-dirty"
>> utility. If you enter a bunch of letters as an integer, toInt will not
>> choke and
>> segfault. It will throw an exception, which prevents it from going
>> further and
>> damaging anything or producing erroneous output.
>>
>> Since we did not set up any handling (a catch), the program will exit if
>> any
>> input is badly formatted. However, we can take this a step further and
>> make the
>> utility more robust and more useful:
>>
>> # import std.conv;
>> # alias char[] string;
>> #
>> # int processInt(int input) {
>> #     int output;
>> #     // Processing.
>> #     return (output);
>> # }
>> #
>> # main(string[] args) {
>> #     foreach (int index, string arg; args[1 .. length]) {
>> #         try {
>> #             int temp = toInt(arg);
>> #             int result = processInt(temp);
>> #             printf("[#%d] %d => %d\n", index, temp, result);
>> #         catch (Exception e) {
>> #             printf("Badly formatted input [#%d]=%.*s\n", index, arg);
>> #             printf("Exception says: %.*s\n", e.toString);
>> #         }
>> #     }
>> # }
>>
>> Now, the program will catch any errors neatly, and continue normal
>> operation
>> (which is perfectly valid). Now ask yourself, how many times will a
>> human being
>> type a number incorrectly? I think we know the answer is _all the time_.
>>
>> What does this mean? We should _use_ the exception mechanism to replace
>> all
>> error handling and checking, but in order to do this, it must be
>> relatively
>> fast. Maybe not as fast as a simple return code, but not an order of
>> magnitude
>> slower either. In this example it doesn't matter much, but what if it's a
>> million inputs? or what if it's a server handling hundreds of thousands
>> of
>> requests?
>>
>> This is all just IMHO, but I think it makes sense. Look at the
>> traditional
>> alternative:
>>
>> You must manually check all inputs beforehand, before even attempting to
>> convert
>> them, to see if they are perfectly formatted. You must introduce an
>> error code
>> return and move the output to its own ref parameter, because the error
>> code
>> could be mistaken for correct output.
>>
>> I think this is futile and redundant; you would be essentially
>> re-writing the
>> toInt function yourself just so that it won't throw an exception. Must
>> one
>> re-invent the wheel?
>>
>> The point of this whole thing: Exceptions are good. They are simple to
>> use and
>> powerful. They make you code neater and reduce useless clutter.
>> Moreover, they
>> represent things that occur commonly. So, we should make use of them
>> whenever
>> possible, and D should make them fast so that we can do this without
>> incurring a
>> penalty.
>>
>> Thanks for listening,
>> --AJG.
>>
>>>
>>> "AJG" <AJG_member@pathlink.com> wrote in message news:d9s10t$1lid$1@digitaldaemon.com...
>>>> What is the cost (performance & memory-wise) of throwing and catching
>>>> an
>>>> exception in D?
>>>
>>> I refer you to the "Error handling" section of D's spec
>>> (http://www.digitalmars.com/d/index.html):
>>>
>>> "
>>> Errors are not part of the normal flow of a program. Errors are
>>> exceptional,
>>> unusual, and unexpected.
>>> D exception handling fits right in with that.
>>> Because errors are unusual, execution of error handling code is not
>>> performance critical.
>>> Exception handling stack unwinding is a relatively slow process.
>>> The normal flow of program logic is performance critical.
>>> Since the normal flow code does not have to check every function call
>>> for
>>> error returns, it can be realistically faster to use exception handling
>>> for
>>> the errors.
>>> "
>>>
>>> For one, D assumes that exceptions are very unusual circumstances.  For
>>> two,
>>> it says that "error handling code is not performance critical."
>>>
>>> Now, it won't pause your app for a few seconds when throwing an
>>> exception
>>> like in .NET, but it won't be _as fast_ as the rest of your code.
>>
>>
>


June 30, 2005
In article <da0ueg$15ls$1@digitaldaemon.com>, Nicolas Lehuen says...
>
>Are you sure you're not measuring the performance of new Exception(toString(i))
>here ? Especially toString(i) ? I don't think your benchmark is very fair,
>because in one case you are purely stack based, and in the other you are
>allocating tons of objects on the heap.

See my post on exception performance.  I modified the test so it measures both stack-based and dynamic exception allocation.  FWIW, the times were almost identical.


Sean


July 01, 2005
Walter wrote:
> "AJG" <AJG_member@pathlink.com> wrote in message
> news:d9s10t$1lid$1@digitaldaemon.com...
> 
>> What is the cost (performance & memory-wise) of throwing and catching an
>> exception in D? First, why do I ask this:
> 
> D's exception handling mechanism is the same as C++'s is, as D and C++ share
> the same back end. It'll still be an order or magnitude or more slower than,
> say, returning an error code.

But is it true that this slowdown happens only when an exception is actually thrown?  So the normal flow of logic would be faster as it doesn't have to keep checking for errors.  If no exceptions are thrown, then do try/catch/finally blocks slow the program down at all?

Stewart.

-- 
My e-mail is valid but not my primary mailbox.  Please keep replies on the 'group where everyone may benefit.
July 01, 2005
In article <d9ufp5$1jh4$1@digitaldaemon.com>, David Medlock says...
>
>Knud Sørensen wrote:
>> According to the shootout the answer is NO!
>> 
>> http://shootout.alioth.debian.org/sandbox/benchmark.php?test=except&lang=all&sort=fullcpu
>> 
>> D use 10 times as much time as the fastest language on the exception test.
>> 
>
>Compare apples to apples. D is 10 times FASTER than the intel C++ compiler, which is widely reguarded as the best optimizing C++ compiler.
>
>All the languages above it are using a different programming paradigm entirely, functional programming.  The C examples are laughable, as they are basically using int error codes and setjmp/longjmp.
>

Yep - and if you use a base class for the exceptions with a free list and overloaded new and delete, you can get code just as fast as the fastest on that list (use the following code at your own risk - I haven't fully tested it), which should make throwing exceptions repeatedly in a tight loop about as fast as it gets in any language.

And more to the OP's question, even w/o overloading new and delete, D is still the fastest by a wide margin using imperitive language try/catch EH (compare it to mono C# - D is several times faster in the list above). And this will only improve as the D GC improves, getting rid of the need for custom mem. mgmt.

On my machine, the time for 250K iterations went from 0.250 to 0.09 using the free list approach.

<code>
class ExMem
{
private:
static ExMem __emList;
ExMem __emNext;
protected:
new(uint sz)
{
void* p;
if(__emList) {
p = cast(void*)__emList;
__emList = __emList.__emNext;
}
else {
p = new void[sz];
}
return p;
}

delete(void* p)
{
if(p)
{
ExMem e = cast(ExMem)p;
e.__emNext = __emList;
__emList = e;
}
}
}

class Hi_exception : ExMem
{
public:
this(size_t _n) { n = _n; }
char[] what() { return(std.string.toString(n)); }
private:
size_t n;
}

class Lo_exception : ExMem
{
public:
this(size_t _n) { n = _n; }
char[] what() { return(std.string.toString(n)); }
private:
size_t n; char N[8];
}
..
void lo_function(size_t num)
{
try
{
blowup(num);
}
catch(Lo_exception ex)
{
++LO;
delete ex; // Back into free-list
}
}

void hi_function(size_t num)
{
try
{
lo_function(num);
}
catch(Hi_exception ex)
{
++HI;
delete ex; // Back into free-list
}
}
</code>


July 01, 2005
In article <da3kfi$19m2$1@digitaldaemon.com>, Stewart Gordon says...
>
>Walter wrote:
>> "AJG" <AJG_member@pathlink.com> wrote in message news:d9s10t$1lid$1@digitaldaemon.com...
>> 
>>> What is the cost (performance & memory-wise) of throwing and catching an exception in D? First, why do I ask this:
>> 
>> D's exception handling mechanism is the same as C++'s is, as D and C++ share the same back end. It'll still be an order or magnitude or more slower than, say, returning an error code.
>
>But is it true that this slowdown happens only when an exception is actually thrown?  So the normal flow of logic would be faster as it doesn't have to keep checking for errors.  If no exceptions are thrown, then do try/catch/finally blocks slow the program down at all?

They can, depending on the implementation.  But there is no theoretical reason why they have to.  I haven't done any testing in this regard, but I have a feeling there is negligible overhead in putting try blocks in your code.


Sean


1 2 3
Next ›   Last »