为什么链接到librt会在g++和clang之间交换性能
Why does linking to librt swap performance between g++ and clang?
我刚刚从@tony-d中找到了这个答案,其中有一个测试虚拟函数调用开销的测试台代码。我检查了使用g++
:的基准
$ g++ -O2 -o vdt vdt.cpp -lrt
$ ./vdt
virtual dispatch: 150000000 0.128562
switched: 150000000 0.0803207
overheads: 150000000 0.0543323
...
我的表现比他的好(比例大约为2),但后来我用clang
:进行了检查
$ clang++-3.7 -O2 -o vdt vdt.cpp -lrt
$ ./vdt
virtual dispatch: 150000000 0.462368
switched: 150000000 0.0569544
overheads: 150000000 0.0509332
...
现在这个比例上升到70左右!
然后我注意到了-lrt
命令行参数,在谷歌上搜索了librt
之后,我尝试在g++
和clang
:中不使用它
$ g++ -O2 -o vdt vdt.cpp
$ ./vdt
virtual dispatch: 150000000 0.4661
switched: 150000000 0.0815865
overheads: 150000000 0.0543611
...
$ clang++-3.7 -O2 -o vdt vdt.cpp
$ ./vdt
virtual dispatch: 150000000 0.155901
switched: 150000000 0.0568319
overheads: 150000000 0.0492521
...
正如您所看到的,性能被交换。
根据我对librt
的发现,它是clock_gettime
和其他相关时间计算所必需的(也许我错了,在这种情况下纠正我!)但没有-lrt
,代码编译得很好,而且从我所看到的时间似乎是正确的。
为什么链接/不链接librt
会对代码产生如此大的影响?
关于我的系统和编译器的信息:
$ g++ --version
g++-5 (Ubuntu 5.3.0-3ubuntu1~14.04) 5.3.0 20151204
Copyright (C) 2015 Free Software Foundation, Inc.
$ clang++-3.7 --version
Debian clang version 3.7.1-svn254351-1~exp1 (branches/release_37) (based on LLVM 3.7.1)
Target: x86_64-pc-linux-gnu
Thread model: posix
$ uname -a
Linux ****** 3.13.0-86-generic #130-Ubuntu SMP Mon Apr 18 18:27:15 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
我猜这与oprimizer有关(如果指定了-lrt,因为试图与库链接,优化器有更多的数据,可以进行不同的优化)。
至于差异,对于我的g++(4.8.4),我在有和没有-lrt的情况下得到了相同的结果,但clang(3.4.-lubuntu3)存在差异。我试着通过perftools统计来运行这个,结果如下:
$ g++ -O2 -o vdt vdt.cpp -lrt && perf stat -d ./vdt
virtual dispatch: 150000000 1.2304
switched: 150000000 0.131782
overheads: 150000000 0.0842732
virtual dispatch: 150000000 1.13689
switched: 150000000 0.137304
overheads: 150000000 0.0854806
virtual dispatch: 150000000 1.19261
switched: 150000000 0.133561
overheads: 150000000 0.0969093
Performance counter stats for './vdt':
4068.861539 task-clock (msec) # 0.961 CPUs utilized
1,068 context-switches # 0.262 K/sec
0 cpu-migrations # 0.000 K/sec
431 page-faults # 0.106 K/sec
11,977,128,883 cycles # 2.944 GHz [40.18%]
6,088,274,331 stalled-cycles-frontend # 50.83% frontend cycles idle [39.92%]
3,984,855,636 stalled-cycles-backend # 33.27% backend cycles idle [39.98%]
6,581,309,599 instructions # 0.55 insns per cycle
# 0.93 stalled cycles per insn [50.06%]
1,506,617,848 branches # 370.280 M/sec [50.12%]
303,871,937 branch-misses # 20.17% of all branches [49.88%]
2,708,080,460 L1-dcache-loads # 665.562 M/sec [49.94%]
559,844,530 L1-dcache-load-misses # 20.67% of all L1-dcache hits [50.28%]
0 LLC-loads # 0.000 K/sec [40.05%]
0 LLC-load-misses # 0.00% of all LL-cache hits [39.98%]
4.232477683 seconds time elapsed
$ g++ -O2 -o vdt vdt.cpp && perf stat -d ./vdt
virtual dispatch: 150000000 1.11517
switched: 150000000 0.14231
overheads: 150000000 0.0840234
virtual dispatch: 150000000 1.11355
switched: 150000000 0.130082
overheads: 150000000 0.116934
virtual dispatch: 150000000 1.16225
switched: 150000000 0.13281
overheads: 150000000 0.0798615
Performance counter stats for './vdt':
4050.314222 task-clock (msec) # 0.993 CPUs utilized
707 context-switches # 0.175 K/sec
0 cpu-migrations # 0.000 K/sec
402 page-faults # 0.099 K/sec
12,213,599,260 cycles # 3.015 GHz [39.72%]
6,987,416,990 stalled-cycles-frontend # 57.21% frontend cycles idle [40.25%]
4,675,829,189 stalled-cycles-backend # 38.28% backend cycles idle [40.17%]
6,611,623,206 instructions # 0.54 insns per cycle
# 1.06 stalled cycles per insn [50.54%]
1,505,162,879 branches # 371.616 M/sec [50.48%]
298,748,152 branch-misses # 19.85% of all branches [50.30%]
2,710,580,651 L1-dcache-loads # 669.227 M/sec [50.04%]
551,212,908 L1-dcache-load-misses # 20.34% of all L1-dcache hits [49.86%]
3 LLC-loads # 0.001 K/sec [39.62%]
0 LLC-load-misses # 0.00% of all LL-cache hits [40.01%]
4.080288324 seconds time elapsed
$ clang++ -O2 -o vdt vdt.cpp -lrt && perf stat -d ./vdt
virtual dispatch: 150000000 0.276252
switched: 150000000 0.11926
overheads: 150000000 0.0733678
virtual dispatch: 150000000 0.249832
switched: 150000000 0.0892711
overheads: 150000000 0.117108
virtual dispatch: 150000000 0.247705
switched: 150000000 0.109486
overheads: 150000000 0.0762541
Performance counter stats for './vdt':
1347.887606 task-clock (msec) # 0.989 CPUs utilized
222 context-switches # 0.165 K/sec
0 cpu-migrations # 0.000 K/sec
430 page-faults # 0.319 K/sec
3,558,892,668 cycles # 2.640 GHz [42.47%]
1,316,787,839 stalled-cycles-frontend # 37.00% frontend cycles idle [42.61%]
438,592,926 stalled-cycles-backend # 12.32% backend cycles idle [40.57%]
6,388,507,180 instructions # 1.80 insns per cycle
# 0.21 stalled cycles per insn [50.49%]
1,514,291,853 branches # 1123.456 M/sec [50.19%]
1,095,265 branch-misses # 0.07% of all branches [48.66%]
2,485,922,557 L1-dcache-loads # 1844.310 M/sec [47.99%]
577,213,257 L1-dcache-load-misses # 23.22% of all L1-dcache hits [48.20%]
2 LLC-loads # 0.001 K/sec [40.51%]
0 LLC-load-misses # 0.00% of all LL-cache hits [40.17%]
1.362403811 seconds time elapsed
$ clang++ -O2 -o vdt vdt.cpp && perf stat -d ./vdt
virtual dispatch: 150000000 1.0894
switched: 150000000 0.0849747
overheads: 150000000 0.0726611
virtual dispatch: 150000000 1.03949
switched: 150000000 0.0849843
overheads: 150000000 0.0768674
virtual dispatch: 150000000 1.07786
switched: 150000000 0.0893431
overheads: 150000000 0.0725624
Performance counter stats for './vdt':
3667.235804 task-clock (msec) # 0.993 CPUs utilized
356 context-switches # 0.097 K/sec
0 cpu-migrations # 0.000 K/sec
402 page-faults # 0.110 K/sec
11,052,067,182 cycles # 3.014 GHz [39.98%]
5,346,555,173 stalled-cycles-frontend # 48.38% frontend cycles idle [40.10%]
3,480,506,097 stalled-cycles-backend # 31.49% backend cycles idle [40.09%]
6,351,819,740 instructions # 0.57 insns per cycle
# 0.84 stalled cycles per insn [50.07%]
1,524,106,229 branches # 415.601 M/sec [50.17%]
299,296,742 branch-misses # 19.64% of all branches [50.05%]
2,393,484,447 L1-dcache-loads # 652.667 M/sec [49.93%]
554,010,640 L1-dcache-load-misses # 23.15% of all L1-dcache hits [49.88%]
0 LLC-loads # 0.000 K/sec [40.33%]
0 LLC-load-misses # 0.00% of all LL-cache hits [39.83%]
3.692786417 seconds time elapsed
我所看到的是,clang中的分支预测(分支未命中)存在一些差异(这再次适用于优化器)。
相关文章:
- C++中std::resize(n)和std::shrink_to_fit之间的区别
- int(c) 和 c-'0' 之间的区别。C++
- 在cuda线程之间共享大量常量数据
- 如何防止clang格式在流运算符调用之间添加换行符<<
- 嵌套类中 g++ 和 clang++ 之间的不同行为
- 模板转换运算符在 clang 6 和 clang 7 之间的区别
- 为什么 GCC 和 clang 之间编译的 c++17 lambda 存在差异?
- 在继承多个空类时,了解GCC/Clang vs MSVC2015之间的不同填充规则
- Objective-C源代码和clang -rewrite-objc C++代码之间有什么关系?
- GCC和Clang之间的C 不一致
- 为什么链接到librt会在g++和clang之间交换性能
- GCC和clang(SFINAE)之间的过载解决行为差异
- 编译一个相当简单的c++11程序时,gcc和clang之间的结果不同
- Clang - Windows 快照构建和版本 3.7.1 之间的区别
- MSVC和Clang之间的大括号不一致或初始化行为相等
- Clang和GCC中不明确基类转换之间的行为差异
- 重载解析在gcc和clang之间得到不同的结果
- struct和int之间clang中的重新定义不一致
- 编译器在g++4.7.2和英特尔13.0.1与clang++3.2和g++4.8之间的差异
- 对于未实例化的模板,在Clang和GCC之间获得类似的行为