2012-11-28 39 views
1

我在C++项目中使用用C语言编写的a high performance/parallel graph library。它提供了一个结构stinger(图形数据结构)和操作类似C/C++:使用适配器模式会降低性能吗?

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

大部分时间,不过,我不希望指定时间戳或重量或类型。默认参数会很好。此外,一个类似OOP的界面会很好:G->insertEdge(u, v)而不是insert_edge_pair(G, u, v, ...)

所以我想创造一个适配器类看起来像

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); 

    }; 

的方法insertEdge(...)简单地调用stinger_insert_edge_pair(this->stingerG, ...)用适当的参数。

但是,性能是一个关键的方面。与使用这样的适配器类相关的性能损失是多少?与使用“裸体”库相比,我是否应该期望性能下降?

+0

很难分辨没有分析。除此之外,良好编码的一般方面仍然存在。 – DumbCoder

+0

“除此之外,良好编码的一般方面仍然存在。”在您看来,使用这种适配器是否合适? – clstaudt

+1

为什么要适应虚拟功能?你想提供不同种类的适配器吗?一个简单的适配器将调用转发给内联方法中的c api应该有近乎开销。 – hansmaad

回答

1

如果您的insertEgde只是将调用转发给stinger_insert_edge_pair,那么在对stinger_insert_edge_pair和g-> insertEdge(只要您移除虚拟说明符)的简单调用之间生成的代码中(很可能)没有区别。 比较通过普通调用和适配器调用生成的汇编代码将给出适配器引入的开销的公平输入。

InsertEdge必须是虚拟的吗?你打算有Graph的子类吗?但是,虚拟函数调用的代价与函数执行本身的实际代价相比几乎可以忽略不计。

+0

在这种情况下,性能比扩展性更重要,所以'insertEdge'不一定是虚拟的。 – clstaudt

+0

如果你太怀疑我建议你删除它。但我宁愿删除它,因为我知道我永远不会派生和覆盖,也不会将性能作为理由。 – nanda

1

虚函数通常不能被内联,所以从函数调用(在堆栈上推参数,可能中断流水线和高速缓存等)有相同的开销。在实践中,例行函数调用速度非常快 - 按照时钟周期的顺序。确定这是否合适的唯一方法是在您自己的应用程序上测试测试

+0

因此,当您需要性能时,您会建议制作非虚拟方法吗?这可以启用内联,但如果我理解正确,非虚函数调用不会有明显的开销。 – clstaudt

+0

@cls是的,除非强制*这样做,否则不要使用虚拟函数。几乎总是有编​​译时的解决方法。 – chrisaycock

+0

即使虚拟函数可以内联*,如果*编译器可以静态地(即,在编译时)确定函数将被调用的类型。注意我并不是说这是常见的或预期的,只是这是可能的。 –

1

如果您使用微不足道的方法inline,编译器应该在调用点内联它们,所以不会有任何性能损失。但请注意,你不应该为此使用虚拟功能。

+0

你能定义“微不足道的内联方法”吗? – clstaudt

+0

问题是,至少gcc **可能不会真正内联函数,即使它标记为“inline”。请参阅:http://stackoverflow.com/questions/934529/c-inline-functions-using-gcc-why-the-call 另外,gcc有一个'always_inline',但这是非标准功能。 –