c++ - Non-virtual interface? (Need a very performant low level abstraction) -


i'm trying micro-optimize code @ low level point in application architecture. here concrete scenario:

  • i have parser class parses graph file (nodes, edges, adjacency entries etc.)
  • the file format versioned, there exist parsers each version implemented separate classes (parserv1, parserv2, ...).
  • the parsers provide same functionality upper layer in application. thus, implement same "interface".
  • in c++, i'd implement such interface abstract class functions being pure virtual.
  • as virtual functions need memory lookup , can't bound statically @ compile time , -- more important -- not allow inlining of small methods in parser classes, using classical sub-classing idiom wouldn't lead best performance can achieve.

[before describing possible solutions, want explain why i'm doing micro-optimization here (you may skip paragraph): parser class has lot of small methods, "small" means don't much. of them read 1 or 2 bytes or 1 bit cached bit stream. should possible implement them in very efficient way, function call, when inlined, needs handful of machine commands. methods called in application, since node attributes in big graph (the world-wide road network), might happen 1 million times per user request, , such request should fast possible.]

which way go here? can see following methods solve problem:

  1. write interface pure virtual methods , subclass it. performance suffer.
  2. do not write such interface. each parser defines same methods on own. in upper layer (which uses parser) has pointers (as members) each version subclass. in beginning, instantiate specific parser should used. use switch block , cast parser instance explicit subclass whenever accessing function. performance better? (if/switch block vs. virtual table lookup).
  3. mix 2 solutions 1. + 2.: write interface pure virtual methods seldom used methods, performance isn't highly critical. if critical, don't provide virtual method use second method.
  4. improving 2.: provide non-virtual methods in abstract class; keep version number member variable in abstract class (kind of own runtime type information) , implement if/switch blocks , casts in these methods; call methods in subclass. provide both inlining , static binding.

are there better ways solve problem? there idiom this?

to clarify, have lot of functions version-independent (at least until now), , fitting in super class. use standard sub-classing design functions, while questions covers solution version-dependent functions optimised. (some of them aren't called , can of course use virtual methods in these cases.) besides this, don't idea make parser class decide methods need performant , don't. (although possible so.)

first, of couse, should profile code figure-out how vcalls performance-killing in particular case (besides of potentially weaker optimizations).

putting optimization subject aside, i'm sure won't significant performance gain replacing virtual function call (or call function pointer variable, same) switch calls compile-time-known functions in different cases.

if really want significant improvement - promising variants imho:

  1. try redesign interface enable more complex functions. instance, if have function reads single vertex - modify read (up to) n vertexes @ once. , on.

  2. you may make whole parsing code (that uses parser) template class/function, use template parameter instantiate needed parser. here you'll need neither interface nor virtual functions. @ beginning (where identify version) - put switch, every recognized version call function appropriate template parameter.

the latter superior performance point of view, otoh increases code size

edit:

here's example of (2):

template <class parser> void myapplication::handlesomerequest(parser& p) {     int n = p.getvertexcount();     (ivertex = 0; ivertex < n; ivertex++)     {         // ...             p.getvertexedges(ivertex, /* ... */);             // ...         } }  void myapplication::handlesomerequest(/* .. */) {     int iversion = /* ... */;     switch (iversion)     {     case 1:         {             parserv1 p(/* ... */);             handlesomerequest(p);         }         break;      case 2:         {             parserv2 p(/* ... */);             handlesomerequest(p);         }         break;      // ...     } } 

the classes parserv1, parserv2 , etc. not have virtual functions. don't inherit interface. implement functions, such getvertexcount.


Comments

Popular posts from this blog

c# - SVN Error : "svnadmin: E205000: Too many arguments" -

c# - Copy ObservableCollection to another ObservableCollection -

All overlapping substrings matching a java regex -