Wednesday, April 30, 2008

c/c++: switch vs. array of functions

As I promised I made some tests to compare switch statement and a map to functions. As I expected a map to functions works faster. Furthermore it doesn't depend on the amount of 'switch' conditions. I made a synthetic test:

unsigned long func(unsigned long acc)
{
    return acc*acc;
}

#define SWITCH

typedef unsigned long (*fd)(unsigned long);

int main(int argc, char **argv)
{
    unsigned long i, acc = 0;

    #ifndef SWITCH
        fd f[15] = {func,func,func,func,func,func,func,func,func,func,func,func,func,func,func};
    #endif

    for (i=0;i<1000000000;++i)
    {   
        #ifdef SWITCH
            switch (i%15)
            {
                case 0:
                    acc = func(acc + i); break;
                case 1:
                    acc = func(acc + i); break;
                case 2:
                    acc = func(acc + i); break;
                case 3:
                    acc = func(acc + i); break;
                case 4:
                    acc = func(acc + i); break;
                case 5:
                    acc = func(acc + i); break;
                case 6:
                    acc = func(acc + i); break;
                case 7:
                    acc = func(acc + i); break;
                case 8:
                    acc = func(acc + i); break;
                case 9:
                    acc = func(acc + i); break;
                case 10: 
                    acc = func(acc + i); break;
                case 11: 
                    acc = func(acc + i); break;
                case 12: 
                    acc = func(acc + i); break;
                case 13: 
                    acc = func(acc + i); break;
                case 14:
                    acc = func(acc + i); break;
            }
        #else
            acc = f[i%15](acc + i);
        #endif
    }

    return 0;
}
Times w/o switch:
$for i in 1 2 3; do time ./a.out; done

real 0m11.114s
user 0m10.973s
sys 0m0.010s

real 0m10.968s
user 0m10.966s
sys 0m0.007s

real 0m10.904s
user 0m10.899s
sys 0m0.003s
and w/ switch
$for i in 1 2 3; do time ./a.out; done

real 0m12.378s
user 0m12.399s
sys 0m0.000s

real 0m12.410s
user 0m12.413s
sys 0m0.013s

real 0m12.417s
user 0m12.423s
sys 0m0.010s
A map to functions wins ~1 sec. That's not that much but if you are building a state machine with a lot of states it's better to use mapping rather than switch.

No comments: