为了了解类组合的运行时性能,我编写了以下测试代码。在其中,我比较了直接调用函数作为类的成员函数与通过以原始类作为成员的复合类调用函数所花费的时间。
看起来这些方法应该花费可比的时间,但事实并非如此:通过复合类调用花费的时间几乎是原来的两倍。
代码如下:
const int REPS(1e8);
const double INPUT(5.29);
class Base {
public:
inline double BaseFunc(double x) const;
};
double Base::BaseFunc(double x) const {
return 2.718*x + 3.14;
};
class Super {
public:
inline double BaseFunc(double x) const;
private:
Base b_;
};
double Super::BaseFunc(double x) const {
return b_.BaseFunc(x);
};
int main() {
auto t0 = std::chrono::high_resolution_clock::now();
// Construct objects.
Base b;
Super s;
// Call to base directly.
for (int i = 0; i < REPS; ++i)
b.BaseFunc(INPUT);
auto t1 = std::chrono::high_resolution_clock::now();
// Call to base through composited class.
for (int i = 0; i < REPS; ++i)
s.BaseFunc(INPUT);
auto t2 = std::chrono::high_resolution_clock::now();
// Find average durations.
auto diff1 = std::chrono::duration_cast<std::chrono::nanoseconds>(t1-t0).count();
diff1 /= REPS;
auto diff2 = std::chrono::duration_cast<std::chrono::nanoseconds>(t2-t1).count();
diff2 /= REPS;
std::cout << "Calling directly to base took " << diff1 << "nsec.\n";
std::cout << "Calling to base through a composited class took " << diff2 << "nsec.\n";
}
使用 g++ 版本 4.7.2 和 -std=c++11 -O0 -Winline 编译,我得到:
Calling directly to base took 13nsec.
Calling to base through a composited class took 24nsec.
为什么这两种调用本质上相同的函数的方式之间存在如此大的差异?我想既然一切都是内联的(gcc 没有告诉我其他情况)这些应该是同一件事。
我是否完全错误地考虑了这一点?任何帮助表示赞赏!谢谢!
更新 感谢您的帮助!我返回并在函数调用中放入更多内容(在 vector 上调用 inner_product)并在每次重复时使用所有结果,以确保 gcc 没有优化掉任何东西。然后我打开了优化。你们都是对的:差异消失了。
我想我学到了两件重要的事情:1) 关闭优化后,gcc 甚至不会尝试内联,所以 -Winline 标志没有意义,2) 没有有意义的区别在这两种调用函数的方式之间。我可以自信地从其他类中调用成员函数!
再次感谢!
最佳答案
该程序未经优化编译 (-O0
)。这意味着我们不能期望通常的代码质量。为了找出问题所在,我们需要查看生成的代码。可能没有发生内联(尽管使用 inline
请求)。这可能会使运行时调用的数量加倍,因此运行时间大约加倍。
如果程序经过适当优化,两个循环都将被完全删除。我认为这个基准是没有实际意义的,无论结果是什么,都是没有意义的。在生产中,将执行全面优化和实际工作负载。
关于c++ - 函数调用在复合类中花费更长的时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18362792/