Semantics of toString
Steven Schveighoffer
schveiguy at yahoo.com
Thu Nov 12 09:20:41 PST 2009
On Thu, 12 Nov 2009 11:14:56 -0500, Steven Schveighoffer
<schveiguy at yahoo.com> wrote:
> On Thu, 12 Nov 2009 10:29:17 -0500, Andrei Alexandrescu
> <SeeWebsiteForEmail at erdani.org> wrote:
>
>> I think the cost of calling through the delegate is roughly the same as
>> a virtual call.
>
> Not exactly. I think you are right that struct member calls are faster
> than delegates, but only slightly. The difference being that a struct
> member call does not need to load the function address from the stack,
> it can hard-code the address directly.
>
> However, virtual calls have to be lower performing because you are doing
> two indirections, one to the class vtable, then one to the function
> address itself. Plus those two locations are most likely located on the
> heap, not the stack, and so may not be in the cache.
Some rudamentary attempts at benchmarking:
testme.d:
struct S
{
void foo(int x){}
}
interface I
{
void foo(int x);
}
class C : I
{
void foo(int x){}
}
const loopcount = 10_000_000_000L;
void doVirtual()
{
C c = new C;
for(auto x = loopcount; x > 0; x--)
c.foo(x);
}
void doInterface()
{
I i = new C;
for(auto x = loopcount; x > 0; x--)
i.foo(x);
}
void doDelegate()
{
auto d = new C;
auto dg = &d.foo;
for(auto x = loopcount; x > 0; x--)
dg(x);
}
void doStruct()
{
S s;
for(auto x = loopcount; x > 0; x--)
s.foo(x);
}
void main(char[][] args)
{
switch(args[1])
{
case "virtual":
doVirtual();
break;
case "interface":
doInterface();
break;
case "struct":
doStruct();
break;
case "delegate":
doDelegate();
break;
}
}
[steves at steveslaptop testd]$ time ./testme interface
real 1m18.152s
user 1m16.638s
sys 0m0.015s
[steves at steveslaptop testd]$ time ./testme virtual
real 1m11.146s
user 1m10.497s
sys 0m0.014s
[steves at steveslaptop testd]$ time ./testme struct
real 1m5.828s
user 1m5.249s
sys 0m0.011s
[steves at steveslaptop testd]$ time ./testme delegate
real 1m10.464s
user 1m9.856s
sys 0m0.010s
According to this, delegates are slightly faster than virtual calls, but
not by much. By far a direct call is faster, but I was surprised at how
little overhead virtual calls add in relation to the loop counter. I had
to use 10 billion loops or else the difference was undetectable.
I used dmd 1.046 -release -O (the -release is needed to get rid of the
class method checking the invariant every call).
The relative assembly for calling a virtual method is:
mov ECX,[EBX]
mov EAX,EBX
push dword ptr -8[EBP]
call dword ptr 014h[ECX]
and the assembly for calling a delegate is:
push dword ptr -8[EBP]
mov EAX,-010h[EBP]
call EBX
-Steve
More information about the Digitalmars-d
mailing list