C++优化如果性能
C++ optimization if performance
考虑if语句的这两种情况:
if( error ==0 )
{
// DO success stuff
}
else
{
// DO error handling stuff
}
这个:
if( error != 0 )
{
// DO error handling stuff
}
else
{
// DO success stuff
}
哪一个执行得比另一个好,因为我知道大多数时候我都会走成功代码的道路。
与其担心这可能只是在极少数情况下的性能问题,不如问问自己哪一个更可读。对于错误检查,您可以使用guard子句,它可以避免过多的缩进/括号:
if( error != 0 )
{
// DO error handling stuff
return;
}
// DO success stuff
如果你知道一条路径比另一条路径更有可能,并且你确信这确实是性能关键,你可以让编译器知道(例如GCC):
if( _builtin_expect (error == 0, 1) )
{
// DO success stuff
}
else
{
// DO error handling stuff
}
当然,这会使代码更难阅读——只有在真正必要的时候才使用它。
这取决于情况
当代码只运行一次时,从统计数据来看,一开始使用更可能的代码会更快——如果并且仅当分支预测的cpu实现不是在多行之间"共享计数器"(例如,每个第16条语句共享相同的计数器)。然而,大多数代码并不是这样运行的。它将运行数万亿次(例如在while循环中)。
多次跑步
没有人会比其他人表现得更好。原因是分支预测。每次程序运行if语句时,cpu都会向上或向下计数该语句为true的次数。这样,如果代码再次运行,它现在可以高精度地预测下一次。如果你测试你的代码十亿次,你会发现如果你的If或else部分被执行了,那也没关系。CPU将针对其认为最有可能发生的情况进行优化。
这是一个简化的解释,因为CPU分支预测足够聪明,也可以看到某些代码何时总是触发器:真、假、真、假,真、假甚至真、真、假的、真、真。。。
你可以在维基百科上了解到很多关于分支预测的文章
je
或jne
。
如果您知道并希望精细控制哪个调用路径更有可能,请使用以下宏查找控件。
#define likely(x) __builtin_expect((x),1)
#define unlikely(x) __builtin_expect((x),0)
它们的性能相同。您只是在用一条指令jz
交换一条从Assembly级别观察的jnz
。它们中没有一个比另一个执行更多或更复杂的指令。
您不太可能注意到这两段代码之间的差异。与0进行比较是相同的操作,无论代码后来是"true"还是"false"都会跳转。因此,使用最能在代码中表达"含义"的形式,而不是试图"智胜编译器"(除非你真的很擅长,否则你可能只会混淆事情。
由于在这两种情况下都有if ... else ...
(大多数编译器都会生成一个返回点,因此即使在函数中间有return
,它仍然会生成从return
到函数底部的分支,如果条件为false,则生成一个分支以跳过它
解决这一问题的唯一真正有益的方法是使用分支被/未被采用的提示,这至少在一些处理器上是有益的(编译器可以扭转分支,这样不太可能的情况会产生最多的分支)。但它也相当不可移植,因为C和C++语言没有任何功能允许向编译器提供这样的反馈。但有些编译器确实实现了这样的东西。
当然,这样做的效果/结果在很大程度上取决于实际的处理器是什么(如果这个特定的分支没有"历史记录",现代x86会提示处理器输入分支预测单元——一些嵌入式系统等中使用的旧x86不会有。其他处理器可能有也可能没有相同的功能——我相信ARM有几个方面可以说"这很可能被接受/没有被接受")。理想情况下,为此,您需要"配置文件驱动的优化",这样编译器就可以根据最可能的变体来检测和组织代码。
始终使用评测和基准测试来衡量任何优化的结果。只看代码通常很难猜测什么更好(如果你看不到编译器生成的机器代码,情况更糟)。
任何编译器都应该优化差异。证据如下。如果在运行时设置了错误,那么。
g++4.8与-O3
配合使用
这个
int main(int argc, char **argv) {
bool error=argv[1];
if( error ){
return 0;
}else{
return 1;
}
}
使。
main:
xorl %eax, %eax
cmpq $0, 8(%rsi)
setne %al
ret
而这个。。。
int main(int argc, char **argv) {
bool error=argv[1];
if( !error ){
return 1;
}else{
return 0;
}
}
使。。。
main:
xorl %eax, %eax
cmpq $0, 8(%rsi)
setne %al
ret
与CPU相同的东西。如有疑问,请使用机器代码。http://gcc.godbolt.org/
- 如果没有malloc,链表实现将失败
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- 如果我只是不访问queue_front节点的子节点,而是将它们推到队列中呢?还是BFS吗
- std::map<struct,struct>::find 找不到匹配项,但是如果我循环通过 begin() 到 end(),我在那里看到匹配项
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- OpenMP阵列性能较差
- 获取日期异步信号安全吗?如果在信号处理程序中使用,它会导致死锁吗
- 了解算法的性能差异(如果以不同的编程语言实现)
- 性能:否则如果 vs if 在已经返回的函数中
- 虚拟继承的性能开销(如果只有一个基具有数据成员)
- SFINAE的性能,如果不是
- 如果多个线程使用同一对象,性能是否受到影响
- 在这个C++代码中,std::string 是否可以替换为模板参数 T,如果是这样,Meyer 关于其性能成本的论点是否仍然适用?
- 如果构建和破坏了许多向量,自定义分配器会提高性能<T>吗?
- 如果未在类声明中定义函数,则性能损失
- 如果我不关心返回值,我是否会遇到性能问题
- 如果在Xeon Phi上编译时循环计数未知,则性能会降低
- 函数指针:从性能的角度来看,简单的规范使用是否不好?如果是这样的话,c++11的替代方案是什么
- 如果我有固定数量的相互独立的计算,多线程会显著提高性能吗?
- C++优化如果性能