#Function pointer vs vtable lookup

15 messages · Page 1 of 1 (latest)

silk owl
#

Is it better to use a function pointer then it is to use polymorphism when trying to do eg

boundary.calculate();

Where boundary should call either the function boundary1() or boundary2() depending on a variable which is set within the constructor of the boundary class

Im wondering about this as polymorphism with derived classes seems the cleanest however this function is called in tight loops and im HEARING polymorphic function calls are reaally bad for HPC

polar nebula
umbral geode
#
template<std::size_t N>
struct BoundaryTag {
  static constexpr std::size_t value = N;
};

template<typename BoundaryDerived, typename BoundaryTag>
class BoundaryBase {
public:
  void interface() { static_cast<Boundary*>(this)->impl(); }
};

class Boundary : public BoundaryBase<Boundary, BoundaryTag<...>> {
public:
  void impl();
  // ....
};
#

obviously this doesnt work if you cant set your boundary constructor at compiletime

#

or, even better, just specialize for the different configs

#
template<std::size_t N>
class Boundary;

template<>
class Boundary<2> {};

template<>
class Boundary<2> {};
#

if you dont have compiletime info, then whatever revshell said

silk owl
#

Thx for the information both of you, sadly i don’t know which type of boundary condition to call at compile time and therefore i must go with the function pointers

light mortar
#

You'll also need to think about branch preditability. Are you changing the case in which the different function implementations are called randomly? It's best to test, because if the implementation keeps failing branch preditability, then a vtable would be more performative with the extra cycles and indirection compared to the wasted cycles from branch preditability failure.

Calling a direct function pointer is good, a direct call is better. Depending on what you're doing you could separate them based on the type before using for the direct call. Could do it runtime instead of compile time with the use of CRTP and etc.

You could directly store the function pointer and check the function pointer instead of what determines the function pointer to be called to avoid requiring branch preditability. You could also look to optimize that by abusing terinary expressions to hopefully get the compilier to optimize that as a cmov instruction rather than cmp, mov, etc separately.

So, what im saying is, it really depends on how dynamic the behavior is.
Boundary type is known at compile time -> Crtp/templates/sfinae/etc -> everything will get inlined normally or less dispatch cost.
Boundary type changes rarely -> can store function pointer / lambda -> Simplier than vtable, no base class indirection, no need to load vtable.
Boundary type changes frequeintly and less unpredictabily -> Vtable or pointer like above, but its more based on if the branch preditability fails or not.
(side note: if you know the most common outcome, you can also look in to using [[likely]] and [[unlikely]] compiler flags)
And if you just need the pure runtime flexibility, virtual functions and the vtable would just be better in the long time generally. You get cleaner code, and indirect branches are handled well nowadays.

The best thing is to create a benchmark of your implementation and the different ways to implement it.

silk owl
# light mortar You'll also need to think about branch preditability. Are you changing the case ...

wow thanks for the very detailed explanation, i'll have to dive a bit deeper into that when i have the time as this is still very new territory for me.

My current situation is mostly that a runtime parameter defines which branches are chosen, and for the rest of the programs's runtime this is the only one which will ever be used no change, for boundaries however its a bit more nuanced, ill give a light sketch:

i might have 1 million elements, each of these elements neighours other elements and or a boundary, i need to retrieve the data of the neighbouring elements for each element (this is obviously done in parallel), then the idea is mostly that for e.g. a million elements, maybe a couple ten thousand elements have a physical boundary, i currently indentify these by specifying a NEGATIVE neighbour element index, followed by an if statement, saying IF the neighbour index < 0, retrieve boundary condition, from where the polymorphism starts, as the exact boundary function which should be called is dependent on 1. the input parameters, and 2. the specific boundary (ie there are multiple boundaries in a single simulation which are defined per element at run time), right now i first access a single boundarycondition() function which corresponds to the runtime defined values, then in this function i just have a switch which maps the negative index value to a specific return value/calculation.... it sounds shitty, it is shitty, i dont expect you to have a direct answer to this i just thought id maybe explain what i do in words so i might get an idea myself but so far no luck 🙂

primal willow
#

that's just

#

a 2 way graph?

#

vector <int> a[n]
for (int i = 1;i<=n;i++){
int g1,g2;
cin>>g1>>g2;
a[g1].push_back(g2);
a[g2].push_back(g1);
}