]> git.lizzy.rs Git - rust.git/blob - src/test/bench/shootout-spectralnorm.rs
Auto merge of #28827 - thepowersgang:unsafe-const-fn-2, r=Aatch
[rust.git] / src / test / bench / shootout-spectralnorm.rs
1 // The Computer Language Benchmarks Game
2 // http://benchmarksgame.alioth.debian.org/
3 //
4 // contributed by the Rust Project Developers
5
6 // Copyright (c) 2012-2014 The Rust Project Developers
7 //
8 // All rights reserved.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions
12 // are met:
13 //
14 // - Redistributions of source code must retain the above copyright
15 //   notice, this list of conditions and the following disclaimer.
16 //
17 // - Redistributions in binary form must reproduce the above copyright
18 //   notice, this list of conditions and the following disclaimer in
19 //   the documentation and/or other materials provided with the
20 //   distribution.
21 //
22 // - Neither the name of "The Computer Language Benchmarks Game" nor
23 //   the name of "The Computer Language Shootout Benchmarks" nor the
24 //   names of its contributors may be used to endorse or promote
25 //   products derived from this software without specific prior
26 //   written permission.
27 //
28 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
31 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
32 // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
33 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
34 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
35 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
37 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
39 // OF THE POSSIBILITY OF SUCH DAMAGE.
40
41 // no-pretty-expanded FIXME #15189
42
43 #![allow(non_snake_case)]
44 #![feature(unboxed_closures, iter_arith, core_simd, scoped)]
45
46 use std::thread;
47 use std::env;
48 use std::simd::f64x2;
49
50 fn main() {
51     let mut args = env::args();
52     let answer = spectralnorm(if env::var_os("RUST_BENCH").is_some() {
53         5500
54     } else if args.len() < 2 {
55         2000
56     } else {
57         args.nth(1).unwrap().parse().unwrap()
58     });
59     println!("{:.9}", answer);
60 }
61
62 fn spectralnorm(n: usize) -> f64 {
63     assert!(n % 2 == 0, "only even lengths are accepted");
64     let mut u = vec![1.0; n];
65     let mut v = u.clone();
66     let mut tmp = v.clone();
67     for _ in 0..10 {
68         mult_AtAv(&u, &mut v, &mut tmp);
69         mult_AtAv(&v, &mut u, &mut tmp);
70     }
71     (dot(&u, &v) / dot(&v, &v)).sqrt()
72 }
73
74 fn mult_AtAv(v: &[f64], out: &mut [f64], tmp: &mut [f64]) {
75     mult_Av(v, tmp);
76     mult_Atv(tmp, out);
77 }
78
79 fn mult_Av(v: &[f64], out: &mut [f64]) {
80     parallel(out, |start, out| mult(v, out, start, |i, j| A(i, j)));
81 }
82
83 fn mult_Atv(v: &[f64], out: &mut [f64]) {
84     parallel(out, |start, out| mult(v, out, start, |i, j| A(j, i)));
85 }
86
87 fn mult<F>(v: &[f64], out: &mut [f64], start: usize, a: F)
88            where F: Fn(usize, usize) -> f64 {
89     for (i, slot) in out.iter_mut().enumerate().map(|(i, s)| (i + start, s)) {
90         let mut sum = f64x2(0.0, 0.0);
91         for (j, chunk) in v.chunks(2).enumerate().map(|(j, s)| (2 * j, s)) {
92             let top = f64x2(chunk[0], chunk[1]);
93             let bot = f64x2(a(i, j), a(i, j + 1));
94             sum = sum + top / bot;
95         }
96         let f64x2(a, b) = sum;
97         *slot = a + b;
98     }
99 }
100
101 fn A(i: usize, j: usize) -> f64 {
102     ((i + j) * (i + j + 1) / 2 + i + 1) as f64
103 }
104
105 fn dot(v: &[f64], u: &[f64]) -> f64 {
106     v.iter().zip(u).map(|(a, b)| *a * *b).sum()
107 }
108
109
110 // Executes a closure in parallel over the given mutable slice. The closure `f`
111 // is run in parallel and yielded the starting index within `v` as well as a
112 // sub-slice of `v`.
113 fn parallel<'a,T, F>(v: &mut [T], ref f: F)
114                   where T: Send + Sync + 'a,
115                         F: Fn(usize, &mut [T]) + Sync + 'a {
116     // FIXME: pick a more appropriate parallel factor
117     // FIXME: replace with thread::scoped when it exists again
118     let parallelism = 4;
119     let size = v.len() / parallelism + 1;
120     v.chunks_mut(size).enumerate().map(|(i, chunk)| {
121         f(i * size, chunk)
122     }).collect::<Vec<_>>();
123 }