On Thu, 12 Nov 2009 11:14:56 -0500, Steven Schveighoffer <schvei...@yahoo.com> wrote:

On Thu, 12 Nov 2009 10:29:17 -0500, Andrei Alexandrescu <seewebsiteforem...@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;
    }
}


[ste...@steveslaptop testd]$ time ./testme interface

real    1m18.152s
user    1m16.638s
sys     0m0.015s
[ste...@steveslaptop testd]$ time ./testme virtual

real    1m11.146s
user    1m10.497s
sys     0m0.014s
[ste...@steveslaptop testd]$ time ./testme struct

real    1m5.828s
user    1m5.249s
sys     0m0.011s
[ste...@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

Reply via email to