找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 5938|回复: 5

【C】牙膏厂分支预测优化与Linux的宏if(likely(x))与if(unlikely(x))

[复制链接]
发表于 2018-6-8 16:36:27 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有账号?立即注册→加入我们

×
牙膏厂(挤牙膏的Intel)在跳转(包括jcc等条件跳转或者各种短跳转等)后,会刷新指令队列,同样ARM也会刷新它的三级流水线。这会导致CPU不得不重新把指令读取到指令队列里,再排队执行。

然而我们的条件概率并不总是平均的,有时候有的条件是被算作“意外”的,比如各种异常判断、小概率事件判断等,在这种情况下如果大概率事件成立的时候,你的CPU都不得不跳转一下的话,那就亏了。所以,Linux的likely和unlikely就是这样的一种优化的宏,让你给编译器一个提示,告诉它什么事件是“很有可能发生”的,什么是“不太可能发生”的。likely就是“有可能”而unlikely就是“不太可能”。

定义:

#define likely(x)       __builtin_expect((x),1)
#define unlikely(x)     __builtin_expect((x),0)

也就是说,它是靠__builtin_expect这个gcc钦定功能来实现的。

典型例子:if(arg == NULL)return WRONG_USAGE;这样的代码,很显然arg是参数,并且是个指针,然后WRONG_USAGE大概是一个用来表达错误的返回值,返回一个“函数使用不当”的返回值。这种设计是为了实现“鲁棒性”(“肉棒性”“罗棒性”……)也就是robust特性(刚那些玩意儿都是robust的音译),保证就算用户瞎几把调用也不会导致删库跑路的严重后果。Windows的API都具有一定程度的肉棒性。

但参数填错、错误调用的情况通常只存在于调试阶段,正常情况下发布的程序都不应该有错误参数的。在此时,这种参数判断就显得有点多余了。我们希望的是让它在这个时候尽量减少开支,也就是不要“因为参数正确了”而刷新指令队列,就好像参数正确反而算是一种惩罚一样。所以这代码要这样改:

if(unlikely(arg == NULL))return WRONG_USAGE;

因为arg不太可能是NULL,所以我们用unlikely来暗示编译器:这种情况不太可能。那么编译器就会帮你减少跳转开支,让代码顺畅运行。而这个时候,你只需要很低的成本就能维持住你的肉棒性,可以说是很赚。

这个宏只对GCC有用,对于非GCC的情况,则需要看对应编译器有没有对应功能,没有的话就只能#define likely(x) (x)了。

参考资料:
How do the likely() and unlikely() macros in the Linux kernel work and what is their benefit?
https://stackover
f
low.com/questions/
109710
/how-do-the-likely-and-unlikely-macros-in-the-linux-kernel-work-and-what-
is
-
t

Branch predictor
h
tt
ps://
en
.wikipedia.org/wiki/Branch_predictor

本帖被以下淘专辑推荐:

回复

使用道具 举报

发表于 2018-6-8 16:43:37 | 显示全部楼层
都不知道在说什么
回复 赞! 靠!

使用道具 举报

发表于 2018-6-9 23:07:07 | 显示全部楼层
看不懂,太高深了,顶起
回复 赞! 靠!

使用道具 举报

发表于 2018-6-20 12:41:44 | 显示全部楼层
MSVC有个相似用途的宏叫做__assume:
https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/1b3fsfxw(v%3dvs.100)
回复 赞! 靠!

使用道具 举报

 楼主| 发表于 2018-6-20 13:47:27 | 显示全部楼层
tangptr@126.com 发表于 2018-6-20 12:41
MSVC有个相似用途的宏叫做__assume:
https://docs.microsoft.com/en-us/previous-versions/visualstudio/vi ...

这个__assume感觉和GCC的还有点不太一样,因为它可以用于告诉编译器,某switch语句的某条件一般跑不到。

此外,这个__assume要是没用好,貌似还会导致编译器的未定义的行为,原文:
If the compiler can reach an invalid __assume statement, the program might cause unpredictable and potentially dangerous behavior.
大概还是不能乱用。
回复 赞! 靠!

使用道具 举报

发表于 2018-6-20 15:19:51 | 显示全部楼层
微软的程序员一般都是用,语句逻辑来处理这些问题。比如说是条件真跳转,
  1. if (true) return;
复制代码
或者是条件假才跳转。
  1. if (false) goto done;

  2. done:
  3. return;
复制代码
回复 赞! 靠!

使用道具 举报

本版积分规则

QQ|Archiver|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2024-11-21 22:18 , Processed in 0.038410 second(s), 30 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表