“可能”和“不太可能”宏的使用量太多了?


12

通常称为likely和的unlikely宏可帮助编译器了解if通常是要输入还是要跳过的。使用它可以带来一些(而不是很小的)性能改进。

我最近开始使用它们,我不确定应该多久使用一次此类提示。我目前将其与错误检查ifs 配合使用,通常将其标记为unlikely。例如:

mem = malloc(size);
if (unlikely(mem == NULL))
  goto exit_no_mem;

看起来还可以,但是错误检查if经常发生,因此使用了所述宏。

我的问题是,是不是太有likelyunlikely宏的每个错误的检查if

当我们在这里时,他们经常在其他什么地方使用?


在我当前的用法中,它位于从实时子系统进行抽象的库中,因此程序可以在RTAI,QNX和其他程序之间移植。也就是说,大多数功能都很小,可以直接调用一个或两个其他功能。许多甚至是static inline功能。

因此,首先,它不是我可以描述的应用程序。“识别瓶颈”是没有意义的,因为它是一个库,而不是一个独立的应用程序。

其次,有点像“我知道这不太可能,我不妨告诉编译器”。我没有积极尝试优化if


7
对我来说,微优化的后备...
棘轮怪胎

2
对于应用程序代码,仅当分析显示该代码在热路径中使用时,我才添加它们。
CodesInChaos


@james,这只是说likelyunlikely存在以及它们的作用。我没有发现任何真正建议何时何地使用它们的建议。
Shahbaz 2013年

@Shahbaz“如果条件经常为假,则执行不是线性的。中间有一大堆未使用的代码,这不仅会由于预取而污染L1i,还会导致分支预测问题。如果分支预测是错误的,条件表达式可能效率很低。” 因此,要确保所需指令在L1i高速缓存中的紧密循环
James

Answers:


12

您是否需要性能差强人意的代码呢?这是次要的优化。

  • 代码是否在紧密循环中运行?
  • 您的应用程序是否存在性能问题?
  • 您是否已对应用程序进行了概要分析,并确定此特定循环会占用大量CPU时间?

除非您能回答yes以上所有问题,否则请勿理会此类内容。

编辑:响应于编辑。即使您无法剖析,也通常可以估计热点。每个人都调用的内存分配函数是一个不错的选择,尤其是因为它只需要使用一次宏就可以为整个库工作。


1
为了清楚起见,我没有对你投反对票。但是,您的回答并没有真正回答我的问题。您是否要说(un)likely很少使用宏,而仅在性能至关重要的代码中使用宏?是经常使用它还是“不必要的”“坏习惯”?
Shahbaz 2013年

@Shahbaz它使代码的可读性降低,并且性能优化的范围可能从微不足道的损失到微不足道的损失。当关于可能性的假设不正确或由于以后对代码其他部分的更改而更改为不正确时,后者。除非需要,否则永远不要使用。
彼得

3
@Peter:虽然太糟糕了,语法也不是更好,但是关于可能或不太可能的语法的注释可能会为正在阅读代码的提供有用的信息。例如,看到的某人if (likely(x==2 || x==3)) doOneThing(); else switch(x) { ... }可能会判断程序员if对值2和3使用a不仅是程序员不知道C可以将两个case标签与单个处理程序相关联的结果。
2015年

没有人提到我的观点很关键。不仅仅是“不太可能”的路径发生的频率降低,还可能是因为您根本不在乎速度的情况限制了该路径。例如,外围设备变得无响应,因此无论如何您都必须重置它并入睡。
本杰明·林德奎斯特

2

如果您是为x86 / x64编写的(并且未使用20年之久的CPU),则使用__builtin_expect()带来的性能提升将是微不足道的。其原因是现代x86 / x64 CPU(尽管不能100%确定Atom)具有动态分支预测功能,因此从本质上讲,CPU“了解”分支的频率更高。当然,只能为有限数量的分支存储此信息,但是,只有两种情况。如果(a)它是“经常使用”的分支,则您的程序将从该动态分支预测中受益;如果(b)它是“稀有”的分支,您将不会真正看到由于错误预测导致的实际性能下降如此罕见的分支(如果分支预测错误在蓝月亮中发生一次,则20个CPU周期的分支错误预测不会太糟糕)。

注意:这并不意味着在现代x86 / x64上,分支预测错误的重要性降低了:任何具有50-50跳转无跳转机会的分支仍然会受到惩罚(IIRC 10-20 CPU周期),因此在内部循环中,分支可能仍然需要避免。__builtin_expect()在x86 / x64上已减少(IIRC,大约在10-15年前左右)的重要性很重要-主要是由于动态分支预测。

NB2:适用于x86 / x64以外的其他平台,YMMV。


好了,编译器知道cpu期望哪个分支的可能性较小。它可以安排它实际上是不可能的。但是编译器可能已经知道了没有unlikely-notation的那个模式。
重复数据删除器

@Deduplicator:使用动态分支预测,编译器不知道哪个分支更有可能,因为CPU在运行时根据代码的这一点基于先前的运行对其进行计算。
No-Bugs野兔
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.