我想基准glibc的strlen功能,出于某种原因,发现它显然执行多慢与GCC启用优化,我不知道为什么。
这是我的代码:
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
int main() {
char *s = calloc(1 << 20, 1);
memset(s, 65, 1000000);
clock_t start = clock();
for (int i = 0; i < 128; ++i) {
s[strlen(s)] = 'A';
}
clock_t end = clock();
printf("%lld\n", (long long)(end - start));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在我的机器上,它输出:
$ gcc test.c && ./a.out
13336
$ gcc -O1 test.c && ./a.out
199004
$ gcc -O2 test.c && ./a.out
83415 …Run Code Online (Sandbox Code Playgroud) 使用GCC编译C程序的默认优化级别是-O0.根据GCC文档关闭所有优化.例如:
gcc -O0 test.c
Run Code Online (Sandbox Code Playgroud)
但是,要检查-O0是否真的关闭了所有优化.我执行了这个命令:
gcc -Q -O0 --help=optimizers
Run Code Online (Sandbox Code Playgroud)
在这里,我有点惊讶.我启用了大约50个选项.然后,我使用以下方法检查了传递给gcc的默认参数:
gcc -v
Run Code Online (Sandbox Code Playgroud)
我懂了:
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.8/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.8.4-
2ubuntu1~14.04' --with-bugurl=file:///usr/share/doc/gcc-4.8/README.Bugs --
enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --
program-suffix=-4.8 --enable-shared --enable-linker-build-id --
libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-
gxx-include-dir=/usr/include/c++/4.8 --libdir=/usr/lib --enable-nls --with-
sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-
time=yes --enable-gnu-unique-object --disable-libmudflap --enable-plugin --
with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-
cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64/jre --enable-
java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64 --with-
jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.8-amd64 --with-arch-
directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-
gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --
with-multilib-list=m32,m64,mx32 --with-tune=generic --enable-checking=release
--build=x86_64-linux-gnu …Run Code Online (Sandbox Code Playgroud) c optimization gcc performance-testing compiler-optimization
我希望能够手动预测任意算术的长度(即没有分支或内存,尽管这也很好)x86-64汇编代码将采用特定的体系结构,考虑到指令重新排序,超标量,延迟,消费者价格指数等
什么/描述必须遵循的规则才能实现这一目标?
我想我已经找到了一些初步规则,但是我没有找到任何关于将任何示例代码分解为这个详细程度的引用,所以我不得不做一些猜测.(例如,英特尔优化手册甚至几乎没有提到指令重新排序.)
至少,我正在寻找(1)确认每条规则是正确的,或者是每条规则的正确陈述,以及(2)我可能忘记的任何规则的列表.
addps并且subps使用相同的功能) unit?我如何确定?).和:4此循环已经发出少于超标量宽度(通常)指令的数量.例如,请考虑以下示例代码(计算交叉产品):
shufps xmm3, xmm2, 210
shufps xmm0, xmm1, 201
shufps xmm2, xmm2, 201
mulps xmm0, xmm3
shufps xmm1, xmm1, 210
mulps xmm1, xmm2
subps xmm0, xmm1
Run Code Online (Sandbox Code Playgroud)
我试图预测Haswell的延迟看起来像这样:
; `mulps` Haswell latency=5, CPI=0.5
; `shufps` Haswell latency=1, CPI=1
; `subps` Haswell latency=3, CPI=1
shufps xmm3, xmm2, 210 ; cycle 1
shufps xmm0, xmm1, 201 ; cycle 2
shufps xmm2, xmm2, 201 ; …Run Code Online (Sandbox Code Playgroud) 在谈论ifs的表现时,我们通常会谈论错误预测如何阻止管道.我看到的推荐解决方案是:
我找不到的是我们是否能尽早计算出病情,以便在可能的情况下提供帮助.所以,而不是:
... work
if (a > b) {
... more work
}
Run Code Online (Sandbox Code Playgroud)
做这样的事情:
bool aGreaterThanB = a > b;
... work
if (aGreaterThanB) {
... more work
}
Run Code Online (Sandbox Code Playgroud)
这样的事情可能会完全避免这个条件的停顿(取决于管道的长度和我们可以放在bool和if之间的工作量)?这并不一定是因为我写的,但有什么办法,以评估条件语句早,所以CPU不必尝试和预测的分支?
此外,如果这有帮助,编译器可能会做什么呢?
language-agnostic performance cpu-architecture compiler-optimization branch-prediction
c ×2
gcc ×2
performance ×2
assembly ×1
glibc ×1
latency ×1
optimization ×1
pipeline ×1
superscalar ×1
x86-64 ×1