技术宅的结界

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

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 457|回复: 5
收起左侧

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

[复制链接]

996

主题

2213

帖子

5万

积分

用户组: 管理员

一只技术宅

UID
1
精华
197
威望
261 点
宅币
16510 个
贡献
32858 次
宅之契约
0 份
在线时间
1574 小时
注册时间
2014-1-26
发表于 2018-6-8 16:36:27 | 显示全部楼层 |阅读模式

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

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

x
牙膏厂(挤牙膏的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

47

主题

68

帖子

594

积分

用户组: 大·技术宅

UID
3260
精华
7
威望
12 点
宅币
466 个
贡献
1 次
宅之契约
0 份
在线时间
19 小时
注册时间
2017-12-26
发表于 2018-6-8 16:43:37 | 显示全部楼层
都不知道在说什么

8

主题

76

帖子

515

积分

用户组: 大·技术宅

UID
3808
精华
1
威望
7 点
宅币
393 个
贡献
27 次
宅之契约
0 份
在线时间
71 小时
注册时间
2018-5-6
发表于 2018-6-9 23:07:07 | 显示全部楼层
看不懂,太高深了,顶起
菜鸟一枚,直接指正,不必留情

25

主题

65

帖子

1768

积分

用户组: 管理员

UID
1043
精华
8
威望
38 点
宅币
1528 个
贡献
59 次
宅之契约
0 份
在线时间
268 小时
注册时间
2015-8-15
发表于 2018-6-20 12:41:44 | 显示全部楼层
MSVC有个相似用途的宏叫做__assume:
https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/1b3fsfxw(v%3dvs.100)
flowers for Broken spirits - a woman turned into stake will hold the world in the basin of fire.

996

主题

2213

帖子

5万

积分

用户组: 管理员

一只技术宅

UID
1
精华
197
威望
261 点
宅币
16510 个
贡献
32858 次
宅之契约
0 份
在线时间
1574 小时
注册时间
2014-1-26
 楼主| 发表于 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.
大概还是不能乱用。

25

主题

82

帖子

1116

积分

用户组: 版主

UID
1821
精华
6
威望
57 点
宅币
859 个
贡献
31 次
宅之契约
0 份
在线时间
200 小时
注册时间
2016-7-12
发表于 2018-6-20 15:19:51 | 显示全部楼层
微软的程序员一般都是用,语句逻辑来处理这些问题。比如说是条件真跳转,
[C] 纯文本查看 复制代码
if (true) return;
或者是条件假才跳转。
[C] 纯文本查看 复制代码
if (false) goto done;
…
done:
return;

本版积分规则

QQ|申请友链|Archiver|手机版|小黑屋|技术宅的结界 ( 滇ICP备16008837号|网站地图

GMT+8, 2018-10-19 10:38 , Processed in 0.107922 second(s), 36 queries , Gzip On.

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

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