Am Sat, 08 Feb 2014 14:01:12 -0800
schrieb Walter Bright <[email protected]>:
> On 2/7/2014 8:40 AM, Dmitry Olshansky wrote:
> > Meh. If exceptions are such a liability we'd better make them (much) faster.
>
> They can be made faster by slowing down non-exception code.
>
> This has been debated at length in the C++ community, and the generally
> accepted
> answer is that non-exception code performance is preferred and exception
> performance is thrown under the bus in order to achieve it.
>
> I think it's quite a reasonable conclusion.
Am Sat, 08 Feb 2014 21:31:53 -0800
schrieb Walter Bright <[email protected]>:
> On 2/8/2014 9:00 PM, Marco Leise wrote:
> > The reasons for slow exceptions in D could be the generation
> > of stack trace strings or the garbage collector instead of
> > inherent trade offs to keep the successful code path fast.
>
> Sigh, once again,
>
> 1. It is not the collector
>
> 2. I've implemented it both ways, I know what I'm talking about. You can see
> the
> fast exception way in the Win32 code generation, and the slow way in the
> Linux
> code generation.
Ok, I'm on Linux which should be inherently slower at
throwing exceptions as you say. So I've written a little test
and it shows two things:
1. You are right, about the collector. It is not the
bottleneck.
2. It doesn't have anything to do with trading speed for the
successful code path either.
I called two functions recursively until a nesting depth of
1000. The first version allocates a new exception, the second
one reuses an existing exception. At the call site I caught
the exception. I did this 10_000 times in a loop.
[The code is attached.]
Even at this nesting depth the second version still
outperformed the first one by a factor of ~200(!) and all
the CPU time (>98%) was is spent somewhere in libc.
Using static exceptions (or similarly in C++: throwing
literal strings) is VERY fast in D already and I see no reason
to improve that at the moment.
So I repeat my point:
The reasons for slow exceptions in D could be the generation
of stack trace strings or anything else other than some
inherent trade offs to keep the successful code path fast.
--
Marco
import core.time;
import std.stdio;
enum iter = 10_000;
enum maxDepth = 1000;
int main(string[] args)
{
int sum;
string text = args.length >= 2 ? args[1] : "Hello World";
{
auto t1 = TickDuration.currSystemTick;
foreach (i; 0 .. iter)
{
try
{
newException(text);
}
catch (Exception e)
{
sum += e.line;
}
}
auto t2 = TickDuration.currSystemTick;
writefln("New exception needs %s µs per iteration", (t2-t1).nsecs / 1_000 / iter);
}
{
auto t1 = TickDuration.currSystemTick;
foreach (i; 0 .. iter)
{
try
{
staticException(text);
}
catch (Exception e)
{
sum += e.line;
}
}
auto t2 = TickDuration.currSystemTick;
writefln("Static exception needs %s µs per iteration", (t2-t1).nsecs / 1_000 / iter);
}
return sum;
}
void newException(string text, size_t depth = 1)
{
if (depth < maxDepth)
newException(text, depth + 1);
else
throw new Exception(text);
}
Exception se;
void staticException(string text, size_t depth = 1)
{
if (depth < maxDepth)
staticException(text, depth + 1);
else
throw se ? se : (se = new Exception(text));
}