1

I am using a high performance/parallel graph library written in C in a C++ project. It provides a struct stinger (the graph data structure) and operations like

int stinger_insert_edge_pair (struct stinger *G,
                          int64_t type, int64_t from, int64_t to,
                          double weight, int64_t timestamp) { .... }

Most of the time, however, I do not want to specify timestamps or weights or types. Default parameters would be nice. Also, an OOP-like interface would be nice: G->insertEdge(u, v) instead of insert_edge_pair(G, u, v, ...).

So I was thinking of creating an adapter class looking like

class Graph {

protected:

    stinger* stingerG;

public:

    /** default parameters ***/

    double defaultEdgeWeight = 1.0;


    /** methods **/

    Graph(stinger* stingerG);

     virtual void insertEdge(node u, node v, double weight=defaultEdgeWeight);

   };

The method insertEdge(...) simply calls stinger_insert_edge_pair(this->stingerG, ...) with the appropriate parameters.

However, performance is a crucial aspect here. What is the performance penalty associated with using such an adapter class? Should I expect degraded performance compared to using the "naked" library?

clstaudt
  • 21,436
  • 45
  • 156
  • 239
  • Very hard to tell without profiling. Other than that the general aspects of good coding still remains. – DumbCoder Nov 28 '12 at 12:14
  • "Other than that the general aspects of good coding still remains. " Is using such an adapter good coding in your opinion? – clstaudt Nov 28 '12 at 12:15
  • 1
    Why adapt with virtual functions? Do you want to provide different kinds of adapters? A simple adapter that forwards calls to the c api in inlined methods should have nearly zeor overhead. – hansmaad Nov 28 '12 at 12:19
  • Using a specific design pattern for a specific scenario is a design issue, can you substantiate the reason why you are using a specific pattern and not another ? Performance issues are to be asked latter. – DumbCoder Nov 28 '12 at 12:21
  • I thought that such a class would provide the more concise and more OOP interface which I wanted and would allow me to provide default parameters (call it "adapter pattern" or not). – clstaudt Nov 28 '12 at 12:28

3 Answers3

1

A virtual function usually can't be inlined, so there is the same amount of overhead from a function call (pushing parameters on the stack, possible disruption to the pipeline and cache, etc). In practice, a routine function call is very fast--on the order of clock cycles. The only way to know for sure whether this is appropriate is to test on your own application.

chrisaycock
  • 36,470
  • 14
  • 88
  • 125
  • So you would recommend making methods non-virtual when performance is desired? This would enable inlining, but non-virtual function calls do not have a significant overhead if I understand you correctly. – clstaudt Nov 28 '12 at 12:19
  • @cls Yes, don't use virtual functions unless *forced* to do so. There's almost always a compile-time work-around. – chrisaycock Nov 28 '12 at 12:20
  • Even virtual functions can be inlined *if* the compiler can statically (i.e., at compile time) determine the type for which the function will be invoked. Note I'm not saying this is common or expected, only that it is possible. – Jerry Coffin Nov 28 '12 at 14:19
1

If you use trivial inline methods, compiler should inline them at point of calling, so there won't be any performance penalty. However note, that you shouldn't use virtual functions for this.

hate-engine
  • 2,300
  • 18
  • 26
  • Could you define "trivial inline methods"? – clstaudt Nov 28 '12 at 12:22
  • The problem is that at least gcc **may not** really inline function even if it marked as `inline`. See: http://stackoverflow.com/questions/934529/c-inline-functions-using-gcc-why-the-call Also, there is an `always_inline` for gcc, but that's non-standard feature. – hate-engine Nov 28 '12 at 12:31
1

If your insertEgde just forwards the call to stinger_insert_edge_pair there would (most probably) be no difference in code generated between the plain call to stinger_insert_edge_pair and g->insertEdge (provided you remove the virtual specifier). Comparing the assembly code that is generated through the plain call and adapter call would give a fair input on the overhead your adapter is bring in.

Does insertEdge have to be virtual? Are you planning to have subclasses of Graph? But again, cost of virtual function call is almost negligible compared to real cost the function execution itself.

nanda
  • 804
  • 4
  • 8
  • In this case, performance is more important than extensibility, so `insertEdge` does not have to be virtual. – clstaudt Nov 28 '12 at 12:25
  • If you are too skeptical I suggest you remove it. But I would rather remove it because I know I would never derive and override and not state performance as the reason. – nanda Nov 28 '12 at 12:37