0%

fastpath & slowpath

我们再查看 objc4 源码的时候,会看到苹果的大婶们常用的两个宏定义 fastpathslowpath
我们来看看具体这两个定义是怎么样子的

1
2
#define fastpath(x) (__builtin_expect(bool(x), 1)) // x 大概率为真
#define slowpath(x) (__builtin_expect(bool(x), 0)) // x 大概率为假

大婶们写这个到底有什么意义呢?我们来看看这两个宏定义的意义

__builtin_expect(EXP, N) 这个指令是 GCC 作用是允许程序员将最有可能执行的分支告诉编译器。 它的意思是 EXP == N 的概率很大。

一般情况下,我们都是如何使用它的呢?

__builtin_expect(EXP, N) 的使用

既然我们知道了 __builtin_expect(EXP, N) 的作用,我们可以做一个假设。 比如我现在有个箱子,箱子里面有5个球,4个是蓝色的,1个是红色的。我们知道大概率下。我们随机抽取的球的颜色一定是蓝色的。这样我们就可以用这个指令,来减少指令跳转带来的性能下降

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)

- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
NSArray *balls = [[NSArray alloc] initWithObjects:@"Blue", @"Blue", @"Blue", @"Blue", @"Red", nil];
int index = arc4random() % 5;
NSString *resultStr;
if (likely([[balls objectAtIndex: index] isEqualToString: @"Blue"])) {
resultStr = @"Blue";
} else {
resultStr = @"Red";
}

SCNSLog(@"%@", resultStr);
}

实际上,我们可以使用likely/unlikely宏来预测 x 的结果,然后通知编译器在编译时优化这个分支的汇编代码。

总结

__builtin_expect()GCC (version >= 2.96)提供给程序员使用的,目的是将“分支转移”的信息提供给编译器,这样编译器可以对代码进行优化,以减少指令跳转带来的性能下降。
__builtin_expect((x),1) 表示 x 的值为真的可能性更大;
__builtin_expect((x),0) 表示 x 的值为假的可能性更大。
也就是说,使用 likely(),执行 if 后面的语句的机会更大,使用 unlikely(),执行 else 后面的语句的机会更大。通过这种方式,编译器在编译过程中,会将可能性更大的代码紧跟着起面的代码,从而减少指令跳转带来的性能上的下降。

我们可以查看 __builtin_expect的使用这边文章,有更为详细的描述

-------------本文结束感谢您的阅读-------------