C++ likely与unlikely

最近发现C++ 20标准也已经出了,发现里面正式新增了likelyunlikely关键字,其用途主要是在分支预测时,用于告诉编译器哪个分支更容易被执行,哪个不容易执行,方便编译器做优化,同时提高CPU分支预测的准确率。关键字的宏定义如下:

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

本次主要探究下使用了likelyunlikely的优化程序与普通程序的区别,本次使用个简单的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>

using namespace std;

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

void func1() {
cout << "x >= 1" << endl;
}

void func2() {
cout << "x < 1" << endl;
}


int main() {
int x = 10;
if (unlikely(x >= 1)) {
func1();
}
else {
func2();
}
return 0;
}

在linux环境下,可以使用objdump -d反汇编相应的可执行文件,此实查看代码段中main函数汇编。对于函数符号可以使用c++filt funcName查看相应的函数名

1
2
$ c++filt _Z5func1v
func1()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
00000000000008ba <_Z5func1v>:
8ba: 55 push %rbp
8bb: 48 89 e5 mov %rsp,%rbp
8be: 48 8d 35 70 01 00 00 lea 0x170(%rip),%rsi # a35 <_ZStL19piecewise_construct+0x1>
8c5: 48 8d 3d 54 07 20 00 lea 0x200754(%rip),%rdi # 201020 <_ZSt4cout@@GLIBCXX_3.4>
8cc: e8 9f fe ff ff callq 770 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
8d1: 48 89 c2 mov %rax,%rdx
8d4: 48 8b 05 f5 06 20 00 mov 0x2006f5(%rip),%rax # 200fd0 <_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@GLIBCXX_3.4>
8db: 48 89 c6 mov %rax,%rsi
8de: 48 89 d7 mov %rdx,%rdi
8e1: e8 9a fe ff ff callq 780 <_ZNSolsEPFRSoS_E@plt>
8e6: 90 nop
8e7: 5d pop %rbp
8e8: c3 retq

00000000000008e9 <_Z5func2v>:
8e9: 55 push %rbp
8ea: 48 89 e5 mov %rsp,%rbp
8ed: 48 8d 35 48 01 00 00 lea 0x148(%rip),%rsi # a3c <_ZStL19piecewise_construct+0x8>
8f4: 48 8d 3d 25 07 20 00 lea 0x200725(%rip),%rdi # 201020 <_ZSt4cout@@GLIBCXX_3.4>
8fb: e8 70 fe ff ff callq 770 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
900: 48 89 c2 mov %rax,%rdx
903: 48 8b 05 c6 06 20 00 mov 0x2006c6(%rip),%rax # 200fd0 <_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@GLIBCXX_3.4>
90a: 48 89 c6 mov %rax,%rsi
90d: 48 89 d7 mov %rdx,%rdi
910: e8 6b fe ff ff callq 780 <_ZNSolsEPFRSoS_E@plt>
915: 90 nop
916: 5d pop %rbp
917: c3 retq

0000000000000918 <main>:
918: 55 push %rbp
919: 48 89 e5 mov %rsp,%rbp
91c: 48 83 ec 10 sub $0x10,%rsp
920: c7 45 fc 0a 00 00 00 movl $0xa,-0x4(%rbp)
927: 83 7d fc 00 cmpl $0x0,-0x4(%rbp)
92b: 0f 9f c0 setg %al
92e: 0f b6 c0 movzbl %al,%eax
931: 48 85 c0 test %rax,%rax
934: 74 07 je 93d <main+0x25>
936: e8 7f ff ff ff callq 8ba <_Z5func1v>
93b: eb 05 jmp 942 <main+0x2a>
93d: e8 a7 ff ff ff callq 8e9 <_Z5func2v>
942: b8 00 00 00 00 mov $0x0,%eax
947: c9 leaveq
948: c3 retq

对照组的main函数汇编

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>

using namespace std;

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

void func1() {
cout << "x >= 1" << endl;
}

void func2() {
cout << "x < 1" << endl;
}


int main() {
int x = 10;
if (x >= 1) {
func1();
}
else {
func2();
}
return 0;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
00000000000008ba <_Z5func1v>:
8ba: 55 push %rbp
8bb: 48 89 e5 mov %rsp,%rbp
8be: 48 8d 35 60 01 00 00 lea 0x160(%rip),%rsi # a25 <_ZStL19piecewise_construct+0x1>
8c5: 48 8d 3d 54 07 20 00 lea 0x200754(%rip),%rdi # 201020 <_ZSt4cout@@GLIBCXX_3.4>
8cc: e8 9f fe ff ff callq 770 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
8d1: 48 89 c2 mov %rax,%rdx
8d4: 48 8b 05 f5 06 20 00 mov 0x2006f5(%rip),%rax # 200fd0 <_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@GLIBCXX_3.4>
8db: 48 89 c6 mov %rax,%rsi
8de: 48 89 d7 mov %rdx,%rdi
8e1: e8 9a fe ff ff callq 780 <_ZNSolsEPFRSoS_E@plt>
8e6: 90 nop
8e7: 5d pop %rbp
8e8: c3 retq

00000000000008e9 <_Z5func2v>:
8e9: 55 push %rbp
8ea: 48 89 e5 mov %rsp,%rbp
8ed: 48 8d 35 38 01 00 00 lea 0x138(%rip),%rsi # a2c <_ZStL19piecewise_construct+0x8>
8f4: 48 8d 3d 25 07 20 00 lea 0x200725(%rip),%rdi # 201020 <_ZSt4cout@@GLIBCXX_3.4>
8fb: e8 70 fe ff ff callq 770 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
900: 48 89 c2 mov %rax,%rdx
903: 48 8b 05 c6 06 20 00 mov 0x2006c6(%rip),%rax # 200fd0 <_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@GLIBCXX_3.4>
90a: 48 89 c6 mov %rax,%rsi
90d: 48 89 d7 mov %rdx,%rdi
910: e8 6b fe ff ff callq 780 <_ZNSolsEPFRSoS_E@plt>
915: 90 nop
916: 5d pop %rbp
917: c3 retq

0000000000000918 <main>:
918: 55 push %rbp
919: 48 89 e5 mov %rsp,%rbp
91c: 48 83 ec 10 sub $0x10,%rsp
920: c7 45 fc 0a 00 00 00 movl $0xa,-0x4(%rbp)
927: 83 7d fc 00 cmpl $0x0,-0x4(%rbp)
92b: 7e 07 jle 934 <main+0x1c>
92d: e8 88 ff ff ff callq 8ba <_Z5func1v>
932: eb 05 jmp 939 <main+0x21>
934: e8 b0 ff ff ff callq 8e9 <_Z5func2v>
939: b8 00 00 00 00 mov $0x0,%eax
93e: c9 leaveq
93f: c3 retq

上述截取了主要的反汇编的信息,比对后发现好像没有什么较大的区别,似乎和网上阐述的不太一样,此次先记录着,后续有新的发现继续补充。。