例子:
if (almost_always_false_condition) {
// do something
}
有没有办法建议编译器在 99% 的情况下是错误的。条件计算需要大约 60 个周期来检查,并且编译器本身无法在编译时计算。
(GCC 4.3)
例子:
if (almost_always_false_condition) {
// do something
}
有没有办法建议编译器在 99% 的情况下是错误的。条件计算需要大约 60 个周期来检查,并且编译器本身无法在编译时计算。
(GCC 4.3)
如果您想向 GCC 建议某个条件可能具有给定值作为安排代码流的提示,您应该使用__builtin_expect( )
:
if (__builtin_expect(almost_always_false_condition,0)) {
// do something
}
但是,听起来您想找到一种方法来避免评估条件,但这是__builtin_expect( )
行不通的。有没有一种方法可以快速逼近条件,并且只有在逼近为真时才进行全面检查:
if (__builtin_expect(fastCheckThatIsTrueIfFullConditionIsTrue,0)) {
// most of the time, we don't even get to here, so you don't need
// to evaluate the condition
if (almostAlwaysFalseCondition) {
// do something
}
}
你能告诉我们更多关于条件是什么吗?
如果在一次运行期间结果可能会有所不同,您可以使用布尔运算符的惰性求值将您的条件分成便宜的部分和昂贵的部分,然后先运行便宜的部分。
if (a == 5 && somethingexpensive())
{
...
}
由于计算a == 5
比 便宜somethingexpensive()
,如果它几乎总是false
你应该先运行它,这样可以避免评估somethingexpensive
子句。
另一方面,如果程序运行的结果是恒定的,您可以通过将计算结果存储在静态或全局变量中来优化它。
static int result = doevalfunctiononlyonce();
if (result)
{
....
}
通过这种方式,您可以将成本降低if
到简单的内存查找。
如果条件仅响应另一个过程中的操作而更改,则可以从该过程更新全局:
int condition;
void appendToList(int a)
{
list.append(a);
if (list.somethingexpensive())
{
condition = true;
} else
{
condition = false;
}
}
void someotherfunction()
{
// if (list.somethingexpensive())
if (condition)
{
...
}
}
someotherfunction
如果比appendtolist
函数更频繁地调用,这很有用。
首先,在else
子句中或程序的其他地方花费了多少个周期?如果您分析或拍摄堆栈照片,您是否在该测试中花费了至少 10% 的时间?如果没有,您可能应该首先查看更大的问题。
其次,如果您在该测试中花费超过 10% 的时间,您应该查看是否可以调整算法以使决策点的概率接近 50-50。50-50 的决策点在执行时会产生 1 位信息,而 99-1 的决策点仅会产生大约 0.07 位。*(即它不会告诉您太多信息,因此它对 CPU 周期的使用效率低下。 ) 这种现象的一个例子是,如果您将线性搜索与二分搜索进行比较。
*如果你有一个二元决策点并且结果的概率是a
和b
,那么以比特为单位的信息产量(熵)是-(a*log(a) + b*log(b))/log(2)
。
文档表明 gcc 确实(或可以)进行配置文件驱动的优化。这不是我曾经尝试用 gcc 做的事情,所以无法提供任何进一步的建议,它可能值得你去谷歌。
在我看来,执行这种优化的最好方法是使用-fprofile-generate
and-fprofile-use
选项。这需要一个具有代表性的用例库来收集关于什么是可能的和什么不是的信息,但是测试可以用于此目的。另一方面,代码没有用丑陋的、不可移植的指令修饰。
有关这两个选项的更多信息,请参阅https://gcc.gnu.org/onlinedocs/gcc-4.3.6/gcc/Optimize-Options.html#Optimize-Options。