As I factored more class commonalities into interfaces I began to wonder about their runtime cost. A study of gtype.c and gtype.h revealed that glib appears to be doing quite a bit of work to find an interface method so I decided to benchmark them.

Beginning with a type instance glib must lookup the class, then binary search an array of interface entries for the id of the wanted interface. Once it finds a match it can finally dispatch via the vtable that is part of the interface belonging to that entry. This is much more work than a virtual call but it can be well worth the trouble. I should add that glib isn't a stupid implementation. It must do all this work because of design compromises. For comparison, the C++ version of an interface bloats each instance with a vtable pointer in exchange for fast method lookup. Calling a C++ interface method shouldn't be noticeably slower than any other virtual function since that's exactly what it is. There is some fixup arithmetic for multiple bases classes but arithmetic is pretty cheap. In contrast, an instance of a GType with interfaces does not own any interface vtables. Those belong to the class, the concrete type.

Assume only the interface type of an instance is known at compile time and the concrete type is unknown. Different concrete types are free to implement any number of interfaces and therefore an interface entry may have different offsets within each class. Given an interface id and an unknown instance, the only way to find the interface entry that corresponds to both that instance and the interface id is to search the interface entries in the instance's class for the id. If the id is found, bingo, the entry's interface's vtable is used for dispatch. In the classic space/time trade we spend time to buy space.

Here's a quick interface benchmark written in Vala.


using GLib;

// Our interface
public interface Foo : Object
{
    public abstract int ifrob ();
}

// And a factory method so clients never touch
// the concrete type.
public Foo makeFoo ()
{
    return new FooC ();
}

// Finally a concrete type.
public class FooC : Object, Foo
{
    // Foo interface method
    public int ifrob () {
        return 1;
    }

    // virtual method
    public virtual int vfrob () {
        return 1;
    }

    // regular method
    public int frob () {
        return 1;
    }
}

// Number of method calls
const long n = 10000000;

void main ()
{
    // Interface var
    var fi = makeFoo ();

    // Concrete type
    var fc = fi as FooC;

    var timer = new Timer ();

    print ("GLib Dispatch Mechanisms\n");
    print ("%ld iterations\nTimes in seconds\n\n", n);

    timer.start ();
    for (long i = 0; i < n; ++i) {
        fc.frob ();
    }
    print ("direct:    %f\n", timer.elapsed ());

    timer.start ();
    for (long i = 0; i < n; ++i) {
        fc.vfrob ();
    }
    print ("virtual:   %f\n", timer.elapsed ());

    timer.start ();
    for (long i = 0; i < n; ++i) {
        fi.ifrob ();
    }
    print ("interface: %f\n", timer.elapsed ());

}
Here's the output, compiled with --Xcc='-O3'. GLib is compiled with '-O2'.
GLib Dispatch Mechanisms
10000000 iterations
Times in seconds

direct:    0.000001
virtual:   0.060368
interface: 0.450858

See how -O3 inlines the direct call and then removes the useless loop. You gotta love C compilers, gcc 4.4.1 in this case. Direct calls take about 0.075 seconds with optimizations off. But look at the virtual vs. the interface call. It's over seven times slower. I added some dummy interfaces to FooC in different orders but there was virtually no effect compared to the hit for using an interface in the first place. The disassembler revealed a call to fixed offsets of eax in both virtual and interface cases so the only thing getting optimized out by the compiler is vala boilerplate. The real work is still there. '-O2' yielded interface calls approximately six times more costly than their virtual cousins.

In summary, expect interface calls to be six or seven times slower than a regular virtual one. Interfaces are still sort of new in GLib. Lets hope they get faster because I really like using them.


Your Response