我正在考虑将c ++用于性能关键应用程序。我认为C和C ++都有相似的运行时间。但是我发现c ++函数需要运行4次>才能运行类似的C片段。
当我进行反汇编时,我看到end(),++,!=都是作为函数调用实现的。是否有可能使它们(至少其中一些)内联?
这是C ++代码:
typedef struct pfx_s {
unsigned int start;
unsigned int end;
unsigned int count;
} pfx_t;
typedef std::list<pfx_t *> pfx_list_t;
int
eval_one_pkt (pfx_list_t *cfg, unsigned int ip_addr)
{
const_list_iter_t iter;
for (iter = cfg->begin(); iter != cfg->end(); iter++) {
if (((*iter)->start <= ip_addr) &&
((*iter)->end >= ip_addr)) {
(*iter)->count++;
return 1;
}
}
return 0;
}
这是等效的C代码:
int
eval_one_pkt (cfg_t *cfg, unsigned int ip_addr)
{
pfx_t *pfx;
TAILQ_FOREACH (pfx, &cfg->pfx_head, next) {
if ((pfx->start <= ip_addr) &&
(pfx->end >= ip_addr)) {
pfx->count++;
return 1;
}
}
return 0;
}
答案 0 :(得分:7)
值得注意的是,您使用的数据结构并不完全等效。您的C列表实现为直接元素列表。您的C ++列表实现为指向实际元素的指针列表。为什么要将C ++列表列为指针?
当然,这并不会导致性能上的四倍差异。但是,它可能会影响代码对其更糟糕的内存位置的性能。
我猜你有时间调试你的代码版本,甚至可能用该库的调试版编译。
答案 1 :(得分:4)
你有真的有充分的理由在这里使用列表吗?乍一看,看起来std::vector
将是更好的选择。你可能也不想要一个指针容器,只是一个容器的容器。
您还可以更加巧妙地完成标准算法:
typedef std::vector<pfx_t> pfx_list_t;
int
eval_one_pkt(pfx_list_t const &cfg, unsigned int ip_addr) {
auto pos = std::find_if(cfg.begin(), cfg.end(),
[ip_addr](pfx_t const &p) {
return ip_addr >= p.begin && ip_addr <= p.end;
});
if (pos != cfg.end()) {
++(pos->count);
return 1;
}
return 0;
}
但是,如果我这样做,我可能会将其转换为通用算法:
template <class InIter>
int
eval_one_pkt(InIter b, InIter e, unsigned int ip_addr) {
auto pos = std::find_if(b, e,
[ip_addr](pfx_t const &p) {
return ip_addr >= p.begin && ip_addr <= p.end;
});
if (pos != cfg.end()) {
++(pos->count);
return 1;
}
return 0;
}
虽然与C与C ++无关,但为了对范围检查进行可能的进一步优化,您可能想尝试这样的事情:
return ((unsigned)(ip_addr-p.begin) <= (p.end-p.begin));
使用启用了优化的现代编译器,我希望模板在使用时完全内联扩展,因此根本不会涉及任何函数调用。
答案 2 :(得分:4)
我复制了你的代码并运行10,000个元素列表的失败(因此完成)搜索时间:
没有优化:
TAILQ_FOREACH
0.717s std::list<pfx_t *>
2.397s std::list<pfx_t>
1.98s (请注意,我为next
pfx_t
添加TAILQ
,并使用与std::list
相同的冗余结构
您可以看到指针列表比对象列表更糟糕。现在进行优化:
TAILQ_FOREACH
0.467s std::list<pfx_t *>
0.553s std::list<pfx_t>
0.345s 正如大家所指出的,优化是使用集合类型的紧密内循环中的主导术语。即使是最慢的变化也比最快的未优化版本快。也许更令人惊讶的是胜利者的变化 - 这可能是由于编译器更好地识别std
代码中的优化机会而不是OS提供的宏。