C / C ++ faster calls from an array of functions

Honey, I have a C ++ program that should be as fast as possible. In particular, there is an important part that works as follows:

There is a variable D located in [0.255], based on its value, it calls a function whose pointer is stored in an array F (with 255 elements). that is, F [D] gives a pointer to the called function. The functions are very simple, they perform several expressions and / or assignments (without loops).

How can I do it faster?

I can replicate code in functions. I don't need function call functions (I use them since this was an easier way to do). My goal is to remove inefficiencies due to function calls.

I consider using Switch / case. The code for each case is the code for the corresponding function. Is there a faster way to do this?

+3
source share
4 answers
  • Convert it to switch
  • Make sure tiny functions can be built in (how to do this depends on the compiler, but explicitly labeling them inlineand placing them in the compilation unit is a good bet).
  • Finally, you can try to optimize profiling if (it seems quite possible) the switch statement calls branches unevenly.

The goal is to avoid the overhead of functional calls and force the compiler to reorder the switch statement to reduce the number of typically encountered branches.

:, , ; . - 1,07 , 0,79 - YMMV:

template<unsigned n0,unsigned n> struct F { static inline unsigned func(unsigned val); };

template<unsigned n> struct F<0,n> { static inline unsigned func(unsigned val) { return val + n;} };
template<unsigned n> struct F<1,n> { static inline unsigned func(unsigned val) { return val - n; } };
template<unsigned n> struct F<2,n> { static inline unsigned func(unsigned val) { return val ^ n; } };
template<unsigned n> struct F<3,n> { static inline unsigned func(unsigned val) { return val * n; } };
template<unsigned n> struct F<4,n> { static inline unsigned func(unsigned val) { return (val << ( n %16)) + n*(n&0xff); } };
template<unsigned n> struct F<5,n> { static inline unsigned func(unsigned val) { return (val >> ( n %16)) + (n*(n&0xff) << 16); } };
template<unsigned n> struct F<6,n> { static inline unsigned func(unsigned val) { return val / (n|1) + val; } };
template<unsigned n> struct F<7,n> { static inline unsigned func(unsigned val) { return (val <<16) + (val>>16); } };

template<unsigned n> struct f { static inline unsigned func(unsigned val) { return F<n%8,n>::func(val); } };

typedef unsigned (*fPtr)(unsigned);

fPtr funcs[256];

template<unsigned n0,unsigned n1> inline void fAssign() { 
    if(n0==n1-1 || n0==n1) //||n0==n1 just to avoid compiler warning
        funcs[n0] = f<n0>::func;
    else {
        fAssign<n0,(n0 + n1)/2>();
        fAssign<(n0 + n1)/2,n1>();
    }
}

__forceinline unsigned funcSwitch(unsigned char type,unsigned val);//huge function elided

__declspec(noinline) unsigned doloop(unsigned val,unsigned start,unsigned end) {
    for(unsigned x=start;x<end;++x)
        val = funcs[x*37&0xff](val);
    return val;
}

__declspec(noinline) unsigned doloop2(unsigned val,unsigned start,unsigned end) {
    for(unsigned x=start;x<end;++x)
        val = funcSwitch(x*37&0xff,val);
    return val;
}

, , , doloop, doloop2 funcs[?], , . , , MSC 10, ( ) , , . PGO ; , , , , , / PGO.

+3

/ , , , . , .

+3

, . (, , , int ).

, :

typedef void (*myProc_t)();

myProc_t functionArray[255] = { ... };

void CallSomepin(unsigned char D)
{
    functionArray[D]();
}

, , , , , .

EDIT: This means that the best way to avoid the inefficiency of an indirect call is to simply not do it. Look at your code and see if there are places where you can replace a call based on an indirect search with a direct call.

+2
source

There is a variable D located in [0.255], depending on its value, it calls a function whose pointer is stored in an array F (with 255 elements)

Warning. This will result in a buffer overflow if D is 255.

+1
source

Source: https://habr.com/ru/post/1781101/


All Articles