2014-07-01 03:00:27 -05:00
|
|
|
// The Computer Language Benchmarks Game
|
|
|
|
// http://benchmarksgame.alioth.debian.org/
|
2013-11-17 05:04:36 -06:00
|
|
|
//
|
2014-07-01 03:00:27 -05:00
|
|
|
// contributed by the Rust Project Developers
|
|
|
|
|
|
|
|
// Copyright (c) 2012-2014 The Rust Project Developers
|
|
|
|
//
|
|
|
|
// All rights reserved.
|
|
|
|
//
|
|
|
|
// Redistribution and use in source and binary forms, with or without
|
|
|
|
// modification, are permitted provided that the following conditions
|
|
|
|
// are met:
|
|
|
|
//
|
|
|
|
// - Redistributions of source code must retain the above copyright
|
|
|
|
// notice, this list of conditions and the following disclaimer.
|
|
|
|
//
|
|
|
|
// - Redistributions in binary form must reproduce the above copyright
|
|
|
|
// notice, this list of conditions and the following disclaimer in
|
|
|
|
// the documentation and/or other materials provided with the
|
|
|
|
// distribution.
|
|
|
|
//
|
|
|
|
// - Neither the name of "The Computer Language Benchmarks Game" nor
|
|
|
|
// the name of "The Computer Language Shootout Benchmarks" nor the
|
|
|
|
// names of its contributors may be used to endorse or promote
|
|
|
|
// products derived from this software without specific prior
|
|
|
|
// written permission.
|
|
|
|
//
|
|
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
|
|
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
|
|
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
|
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
|
|
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
|
|
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
|
|
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
|
|
|
// OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
2014-05-13 15:15:11 -05:00
|
|
|
#![feature(macro_rules)]
|
2014-05-14 13:08:06 -05:00
|
|
|
#![feature(simd)]
|
|
|
|
#![allow(experimental)]
|
2013-08-05 23:11:25 -05:00
|
|
|
|
2014-05-10 19:39:08 -05:00
|
|
|
// ignore-pretty very bad with line comments
|
|
|
|
|
2014-05-03 07:53:52 -05:00
|
|
|
use std::io;
|
2014-05-14 13:08:06 -05:00
|
|
|
use std::os;
|
2014-05-20 22:24:17 -05:00
|
|
|
use std::simd::f64x2;
|
2014-12-22 11:04:23 -06:00
|
|
|
use std::str::from_str;
|
2014-06-07 13:13:26 -05:00
|
|
|
use std::sync::{Arc, Future};
|
2013-11-17 05:04:36 -06:00
|
|
|
|
2014-10-06 23:16:35 -05:00
|
|
|
const ITER: int = 50;
|
|
|
|
const LIMIT: f64 = 2.0;
|
|
|
|
const WORKERS: uint = 16;
|
2012-02-03 19:46:17 -06:00
|
|
|
|
2014-05-14 13:08:06 -05:00
|
|
|
#[inline(always)]
|
|
|
|
fn mandelbrot<W: io::Writer>(w: uint, mut out: W) -> io::IoResult<()> {
|
|
|
|
assert!(WORKERS % 2 == 0);
|
2014-05-13 15:15:11 -05:00
|
|
|
|
2014-05-14 13:08:06 -05:00
|
|
|
// Ensure w and h are multiples of 8.
|
|
|
|
let w = (w + 7) / 8 * 8;
|
|
|
|
let h = w;
|
|
|
|
|
|
|
|
let chunk_size = h / WORKERS;
|
2014-05-13 15:15:11 -05:00
|
|
|
|
2014-05-14 13:08:06 -05:00
|
|
|
// Account for remainders in workload division, e.g. 1000 / 16 = 62.5
|
2014-07-13 17:52:11 -05:00
|
|
|
let last_chunk_size = if h % WORKERS != 0 {
|
2014-05-14 13:08:06 -05:00
|
|
|
chunk_size + h % WORKERS
|
|
|
|
} else {
|
|
|
|
chunk_size
|
|
|
|
};
|
|
|
|
|
|
|
|
// precalc values
|
|
|
|
let inverse_w_doubled = 2.0 / w as f64;
|
|
|
|
let inverse_h_doubled = 2.0 / h as f64;
|
|
|
|
let v_inverses = f64x2(inverse_w_doubled, inverse_h_doubled);
|
|
|
|
let v_consts = f64x2(1.5, 1.0);
|
|
|
|
|
|
|
|
// A lot of this code assumes this (so do other lang benchmarks)
|
|
|
|
assert!(w == h);
|
|
|
|
let mut precalc_r = Vec::with_capacity(w);
|
|
|
|
let mut precalc_i = Vec::with_capacity(h);
|
|
|
|
|
|
|
|
let precalc_futures = Vec::from_fn(WORKERS, |i| {
|
2014-11-26 07:12:18 -06:00
|
|
|
Future::spawn(move|| {
|
2014-05-14 13:08:06 -05:00
|
|
|
let mut rs = Vec::with_capacity(w / WORKERS);
|
|
|
|
let mut is = Vec::with_capacity(w / WORKERS);
|
|
|
|
|
|
|
|
let start = i * chunk_size;
|
2014-07-13 17:52:11 -05:00
|
|
|
let end = if i == (WORKERS - 1) {
|
|
|
|
start + last_chunk_size
|
2014-05-14 13:08:06 -05:00
|
|
|
} else {
|
|
|
|
(i + 1) * chunk_size
|
|
|
|
};
|
|
|
|
|
|
|
|
// This assumes w == h
|
|
|
|
for x in range(start, end) {
|
|
|
|
let xf = x as f64;
|
|
|
|
let xy = f64x2(xf, xf);
|
|
|
|
|
|
|
|
let f64x2(r, i) = xy * v_inverses - v_consts;
|
|
|
|
rs.push(r);
|
|
|
|
is.push(i);
|
2014-05-13 15:15:11 -05:00
|
|
|
}
|
|
|
|
|
2014-05-14 13:08:06 -05:00
|
|
|
(rs, is)
|
|
|
|
})
|
|
|
|
});
|
|
|
|
|
2014-09-14 22:27:36 -05:00
|
|
|
for res in precalc_futures.into_iter() {
|
2014-05-14 13:08:06 -05:00
|
|
|
let (rs, is) = res.unwrap();
|
2014-10-10 18:46:59 -05:00
|
|
|
precalc_r.extend(rs.into_iter());
|
|
|
|
precalc_i.extend(is.into_iter());
|
2014-05-14 13:08:06 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
assert_eq!(precalc_r.len(), w);
|
|
|
|
assert_eq!(precalc_i.len(), h);
|
|
|
|
|
|
|
|
let arc_init_r = Arc::new(precalc_r);
|
|
|
|
let arc_init_i = Arc::new(precalc_i);
|
|
|
|
|
|
|
|
let data = Vec::from_fn(WORKERS, |i| {
|
|
|
|
let vec_init_r = arc_init_r.clone();
|
|
|
|
let vec_init_i = arc_init_i.clone();
|
|
|
|
|
2014-11-26 07:12:18 -06:00
|
|
|
Future::spawn(move|| {
|
2014-05-14 13:08:06 -05:00
|
|
|
let mut res: Vec<u8> = Vec::with_capacity((chunk_size * w) / 8);
|
|
|
|
let init_r_slice = vec_init_r.as_slice();
|
2014-10-11 15:29:10 -05:00
|
|
|
|
|
|
|
let start = i * chunk_size;
|
|
|
|
let end = if i == (WORKERS - 1) {
|
|
|
|
start + last_chunk_size
|
|
|
|
} else {
|
|
|
|
(i + 1) * chunk_size
|
|
|
|
};
|
|
|
|
|
|
|
|
for &init_i in vec_init_i.slice(start, end).iter() {
|
2014-05-14 13:08:06 -05:00
|
|
|
write_line(init_i, init_r_slice, &mut res);
|
|
|
|
}
|
|
|
|
|
|
|
|
res
|
|
|
|
})
|
|
|
|
});
|
|
|
|
|
|
|
|
try!(writeln!(&mut out as &mut Writer, "P4\n{} {}", w, h));
|
2014-09-14 22:27:36 -05:00
|
|
|
for res in data.into_iter() {
|
2014-05-14 13:08:06 -05:00
|
|
|
try!(out.write(res.unwrap().as_slice()));
|
2014-05-13 15:15:11 -05:00
|
|
|
}
|
2014-05-14 13:08:06 -05:00
|
|
|
out.flush()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn write_line(init_i: f64, vec_init_r: &[f64], res: &mut Vec<u8>) {
|
|
|
|
let v_init_i : f64x2 = f64x2(init_i, init_i);
|
|
|
|
let v_2 : f64x2 = f64x2(2.0, 2.0);
|
2014-10-06 23:16:35 -05:00
|
|
|
const LIMIT_SQUARED: f64 = LIMIT * LIMIT;
|
2014-05-13 15:15:11 -05:00
|
|
|
|
2014-05-03 07:53:52 -05:00
|
|
|
for chunk_init_r in vec_init_r.chunks(8) {
|
2014-05-14 13:08:06 -05:00
|
|
|
let mut cur_byte = 0xff;
|
|
|
|
let mut i = 0;
|
2014-05-13 15:15:11 -05:00
|
|
|
|
|
|
|
while i < 8 {
|
2014-05-14 13:08:06 -05:00
|
|
|
let v_init_r = f64x2(chunk_init_r[i], chunk_init_r[i + 1]);
|
|
|
|
let mut cur_r = v_init_r;
|
|
|
|
let mut cur_i = v_init_i;
|
|
|
|
let mut r_sq = v_init_r * v_init_r;
|
|
|
|
let mut i_sq = v_init_i * v_init_i;
|
2014-05-13 15:15:11 -05:00
|
|
|
|
2014-05-14 13:08:06 -05:00
|
|
|
let mut b = 0;
|
2013-11-17 05:04:36 -06:00
|
|
|
for _ in range(0, ITER) {
|
2014-05-14 13:08:06 -05:00
|
|
|
let r = cur_r;
|
|
|
|
let i = cur_i;
|
|
|
|
|
|
|
|
cur_i = v_2 * r * i + v_init_i;
|
|
|
|
cur_r = r_sq - i_sq + v_init_r;
|
|
|
|
|
|
|
|
let f64x2(bit1, bit2) = r_sq + i_sq;
|
|
|
|
|
|
|
|
if bit1 > LIMIT_SQUARED {
|
|
|
|
b |= 2;
|
|
|
|
if b == 3 { break; }
|
|
|
|
}
|
|
|
|
|
|
|
|
if bit2 > LIMIT_SQUARED {
|
|
|
|
b |= 1;
|
|
|
|
if b == 3 { break; }
|
|
|
|
}
|
|
|
|
|
|
|
|
r_sq = cur_r * cur_r;
|
|
|
|
i_sq = cur_i * cur_i;
|
2013-11-17 05:04:36 -06:00
|
|
|
}
|
2014-05-13 15:15:11 -05:00
|
|
|
|
|
|
|
cur_byte = (cur_byte << 2) + b;
|
|
|
|
i += 2;
|
2014-05-03 07:53:52 -05:00
|
|
|
}
|
|
|
|
|
2014-05-14 13:08:06 -05:00
|
|
|
res.push(cur_byte^-1);
|
2012-02-03 21:50:32 -06:00
|
|
|
}
|
2014-05-03 07:53:52 -05:00
|
|
|
}
|
2013-11-17 05:04:36 -06:00
|
|
|
|
2014-05-03 07:53:52 -05:00
|
|
|
fn main() {
|
2014-05-14 13:08:06 -05:00
|
|
|
let args = os::args();
|
2014-05-05 02:29:59 -05:00
|
|
|
let args = args.as_slice();
|
2014-05-03 07:53:52 -05:00
|
|
|
let res = if args.len() < 2 {
|
|
|
|
println!("Test mode: do not dump the image because it's not utf8, \
|
|
|
|
which interferes with the test runner.");
|
2014-05-14 13:08:06 -05:00
|
|
|
mandelbrot(1000, io::util::NullWriter)
|
2014-05-03 07:53:52 -05:00
|
|
|
} else {
|
2014-05-20 01:19:56 -05:00
|
|
|
mandelbrot(from_str(args[1].as_slice()).unwrap(), io::stdout())
|
2014-05-03 07:53:52 -05:00
|
|
|
};
|
|
|
|
res.unwrap();
|
2012-02-03 19:46:17 -06:00
|
|
|
}
|