Jan*_*ček 4 optimization gcc rust
我正在做一些非常简单的基准来比较C和Rust的性能.我使用了一个函数添加整数1 + 2 + ... + n(我可以通过手工计算验证的东西),其中n = 10^10.
Rust中的代码如下所示:
fn main() {
let limit: u64 = 10000000000;
let mut buf: u64 = 0;
for u64::range(1, limit) |i| {
buf = buf + i;
}
io::println(buf.to_str());
}
Run Code Online (Sandbox Code Playgroud)
C代码如下:
#include <stdio.h>
int main()
{
unsigned long long buf = 0;
for(unsigned long long i = 0; i < 10000000000; ++i) {
buf = buf + i;
}
printf("%llu\n", buf);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我编译并运行它们:
$ rustc sum.rs -o sum_rust
$ time ./sum_rust
13106511847580896768
real 6m43.122s
user 6m42.597s
sys 0m0.076s
$ gcc -Wall -std=c99 sum.c -o sum_c
$ time ./sum_c
13106511847580896768
real 1m3.296s
user 1m3.172s
sys 0m0.024s
Run Code Online (Sandbox Code Playgroud)
然后我尝试使用优化标志,再次使用C和Rust:
$ rustc sum.rs -o sum_rust -O
$ time ./sum_rust
13106511847580896768
real 0m0.018s
user 0m0.004s
sys 0m0.012s
$ gcc -Wall -std=c99 sum.c -o sum_c -O9
$ time ./sum_c
13106511847580896768
real 0m16.779s
user 0m16.725s
sys 0m0.008s
Run Code Online (Sandbox Code Playgroud)
这些结果让我很惊讶.我确实期望优化会产生一些影响,但优化的Rust版本要快100000倍 :).
我尝试改变n(唯一的限制是u64,运行时间几乎为零),甚至尝试了一个不同的问题(1^5 + 2^5 + 3^5 + ... + n^5),结果相似:编译的可执行文件rustc -O比没有标志的情况快几个数量级,并且也是很多次比编译的同一算法更快gcc -O9.
所以我的问题是:发生了什么?:)我可以理解编译器优化1 + 2 + .. + n = (n*n + n)/2,但我无法想象任何编译器都可以派生出一个公式1^5 + 2^5 + 3^5 + .. + n^5.另一方面,据我所知,结果必须以某种方式计算(并且它似乎是正确的).
哦,并且:
$ gcc --version
gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
$ rustc --version
rustc 0.6 (dba9337 2013-05-10 05:52:48 -0700)
host: i686-unknown-linux-gnu
Run Code Online (Sandbox Code Playgroud)
是的,编译器确实使用1 + ... + n = n*(n+1)/2优化来移除循环,并且对于求和变量的任何幂都有类似的技巧.例如ķ 1是三角形数,ķ 2是锥体号码,ķ 3被取平方三角形号码等.通常,存在甚至一个公式来计算Σ ķ ķ p为任何p.
您可以使用更复杂的表达式,以便编译器没有任何删除循环的技巧.例如
fn main() {
let limit: u64 = 1000000000;
let mut buf: u64 = 0;
for u64::range(1, limit) |i| {
buf += i + i ^ (i*i);
}
io::println(buf.to_str());
}
Run Code Online (Sandbox Code Playgroud)
和
#include <stdio.h>
int main()
{
unsigned long long buf = 0;
for(unsigned long long i = 0; i < 1000000000; ++i) {
buf += i + i ^ (i * i);
}
printf("%llu\n", buf);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这给了我
real 0m0.700s
user 0m0.692s
sys 0m0.004s
Run Code Online (Sandbox Code Playgroud)
和
real 0m0.698s
user 0m0.692s
sys 0m0.000s
Run Code Online (Sandbox Code Playgroud)
分别(-O对于两个编译器).