Optimization 锈出环?

Optimization 锈出环?,optimization,gcc,rust,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()); } C代码如下

我正在做一些非常简单的基准测试来比较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());
}
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;
}
然后,我尝试启用优化标志,再次启用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
这些结果令我惊讶。我确实希望优化会有一些效果,但是优化的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

是的,编译器确实使用
1+…+n=n*(n+1)/2
优化以消除循环,对于求和变量的任何幂也有类似的技巧。e、 一般来说,甚至还有一个计算公式


您可以使用更复杂的表达式,这样编译器就不会有任何技巧来删除循环。e、 g

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());
}


分别(两个编译器都使用
-O

仅仅是一个数据点,clang将
movabsq$-5340232262128654848,%rsi
用于简单求和,而
movabsq$166735283405484844,%rsi
用于
i*i*i
,因此消除循环的锈蚀并没有那么特别(我有点惊讶gcc没有)。谢谢,我低估了编译器:)。但是为什么LLVM包含这样一个特殊的优化呢?
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());
}
#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;
}
real    0m0.700s
user    0m0.692s
sys     0m0.004s
real    0m0.698s
user    0m0.692s
sys     0m0.000s