1 // The Computer Language Benchmarks Game
2 // http://benchmarksgame.alioth.debian.org/
4 // contributed by the Rust Project Developers
6 // Copyright (c) 2012-2014 The Rust Project Developers
8 // All rights reserved.
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions
14 // - Redistributions of source code must retain the above copyright
15 // notice, this list of conditions and the following disclaimer.
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
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.
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.
41 // no-pretty-expanded FIXME #15189
43 #![allow(non_snake_case)]
44 #![feature(unboxed_closures)]
46 use std::iter::AdditiveIterator;
47 use std::thread::Thread;
53 use std::str::from_str;
56 let args = os::args();
57 let answer = spectralnorm(if os::getenv("RUST_BENCH").is_some() {
59 } else if args.len() < 2 {
62 from_str(args[1].as_slice()).unwrap()
64 println!("{:.9}", answer);
67 fn spectralnorm(n: uint) -> f64 {
68 assert!(n % 2 == 0, "only even lengths are accepted");
69 let mut u = Vec::from_elem(n, 1.0);
70 let mut v = Vec::from_elem(n, 1.0);
71 let mut tmp = Vec::from_elem(n, 1.0);
72 for _ in range(0u, 10) {
73 mult_AtAv(u.as_slice(), v.as_mut_slice(), tmp.as_mut_slice());
74 mult_AtAv(v.as_slice(), u.as_mut_slice(), tmp.as_mut_slice());
76 (dot(u.as_slice(), v.as_slice()) / dot(v.as_slice(), v.as_slice())).sqrt()
79 fn mult_AtAv(v: &[f64], out: &mut [f64], tmp: &mut [f64]) {
84 fn mult_Av(v: &[f64], out: &mut [f64]) {
85 parallel(out, |start, out| mult(v, out, start, |i, j| A(i, j)));
88 fn mult_Atv(v: &[f64], out: &mut [f64]) {
89 parallel(out, |start, out| mult(v, out, start, |i, j| A(j, i)));
92 fn mult<F>(v: &[f64], out: &mut [f64], start: uint, a: F)
93 where F: Fn(uint, uint) -> f64 {
94 for (i, slot) in out.iter_mut().enumerate().map(|(i, s)| (i + start, s)) {
95 let mut sum = f64x2(0.0, 0.0);
96 for (j, chunk) in v.chunks(2).enumerate().map(|(j, s)| (2 * j, s)) {
97 let top = f64x2(chunk[0], chunk[1]);
98 let bot = f64x2(a(i, j), a(i, j + 1));
101 let f64x2(a, b) = sum;
106 fn A(i: uint, j: uint) -> f64 {
107 ((i + j) * (i + j + 1) / 2 + i + 1) as f64
110 fn dot(v: &[f64], u: &[f64]) -> f64 {
111 v.iter().zip(u.iter()).map(|(a, b)| *a * *b).sum()
117 unsafe impl<T: 'static> Send for Racy<T> {}
119 // Executes a closure in parallel over the given mutable slice. The closure `f`
120 // is run in parallel and yielded the starting index within `v` as well as a
122 fn parallel<T, F>(v: &mut [T], f: F)
123 where T: Send + Sync,
124 F: Fn(uint, &mut [T]) + Sync {
125 let size = v.len() / os::num_cpus() + 1;
127 v.chunks_mut(size).enumerate().map(|(i, chunk)| {
128 // Need to convert `f` and `chunk` to something that can cross the task
130 let f = Racy(&f as *const _ as *const uint);
131 let raw = Racy(chunk.repr());
132 Thread::spawn(move|| {
133 let f = f.0 as *const F;
134 unsafe { (*f)(i * size, mem::transmute(raw.0)) }
136 }).collect::<Vec<_>>();