【发布时间】:2012-07-25 23:31:28
【问题描述】:
我有一个带有enum 成员变量的类。其中一个成员函数的行为基于此enum,因此作为“可能的”优化,我将两种不同的行为作为两个不同的函数,并且我给类一个在构造时设置的成员函数指针。我是这样模拟这种情况的:
enum catMode {MODE_A, MODE_B};
struct cat
{
cat(catMode mode) : stamp_(0), mode_(mode) {}
void
update()
{
stamp_ = (mode_ == MODE_A) ? funcA() : funcB();
}
uint64_t stamp_;
catMode mode_;
};
struct cat2
{
cat2(catMode mode) : stamp_(0), mode_(mode)
{
if (mode_ = MODE_A)
func_ = funcA;
else
func_ = funcB;
}
void
update()
{
stamp_ = func_();
}
uint64_t stamp_;
catMode mode_;
uint64_t (*func_)(void);
};
然后我创建一个 cat 对象和一个长度为 32 的数组。我遍历数组将其放入缓存中,然后调用猫更新方法32 次并使用rdtsc 将延迟存储在数组中...
然后我使用rand()、ulseep() 和一些任意的strcmp()..调用一个循环数百次的函数。回来我再做32 的事情。
结果是带有分支的方法似乎总是在44 +/- 10 周期附近,而带有函数指针的方法往往在130 附近。我很好奇为什么会这样?
如果有的话,我会期待类似的表现。此外,模板化几乎不是一种选择,因为真正的 cat 类针对该函数的完全专业化将是多余的。
【问题讨论】:
-
@sixlettervariables - 可能更多的是 CPU 具有分支预测,而函数指针调用涉及清除堆栈/寄存器。您不一定会从汇编中看到这一点
-
取决于
funcA和funcBs 的复杂性,它们可能已经被内联。我同意@sixlettervariables 的观点,即检查程序集是个好主意。这很容易做到,如果不出意外,至少你会排除一些可能的解释。 -
当您使用模板结构来包装特定函数时,您可以避免完全专业化。那么你只需要特化结构体,猫类只需要指定一次。
-
这是什么处理器?另外,您能否提供一个完整的 SSCCE,以便我自己运行?
-
@tokage 等等,这很有趣,我在哪里可以读到这个或它是如何工作的?
标签: c++ performance optimization function-pointers