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 #![feature(macro_rules)]
43 #![allow(experimental)]
45 // ignore-pretty very bad with line comments
51 use std::thread::Thread;
54 const LIMIT: f64 = 2.0;
55 const WORKERS: uint = 16;
58 fn mandelbrot<W: io::Writer>(w: uint, mut out: W) -> io::IoResult<()> {
59 assert!(WORKERS % 2 == 0);
61 // Ensure w and h are multiples of 8.
62 let w = (w + 7) / 8 * 8;
65 let chunk_size = h / WORKERS;
67 // Account for remainders in workload division, e.g. 1000 / 16 = 62.5
68 let last_chunk_size = if h % WORKERS != 0 {
69 chunk_size + h % WORKERS
75 let inverse_w_doubled = 2.0 / w as f64;
76 let inverse_h_doubled = 2.0 / h as f64;
77 let v_inverses = f64x2(inverse_w_doubled, inverse_h_doubled);
78 let v_consts = f64x2(1.5, 1.0);
80 // A lot of this code assumes this (so do other lang benchmarks)
82 let mut precalc_r = Vec::with_capacity(w);
83 let mut precalc_i = Vec::with_capacity(h);
85 let precalc_futures = range(0, WORKERS).map(|i| {
86 Thread::spawn(move|| {
87 let mut rs = Vec::with_capacity(w / WORKERS);
88 let mut is = Vec::with_capacity(w / WORKERS);
90 let start = i * chunk_size;
91 let end = if i == (WORKERS - 1) {
92 start + last_chunk_size
97 // This assumes w == h
98 for x in range(start, end) {
100 let xy = f64x2(xf, xf);
102 let f64x2(r, i) = xy * v_inverses - v_consts;
109 }).collect::<Vec<_>>();
111 for res in precalc_futures.into_iter() {
112 let (rs, is) = res.join().ok().unwrap();
113 precalc_r.extend(rs.into_iter());
114 precalc_i.extend(is.into_iter());
117 assert_eq!(precalc_r.len(), w);
118 assert_eq!(precalc_i.len(), h);
120 let arc_init_r = Arc::new(precalc_r);
121 let arc_init_i = Arc::new(precalc_i);
123 let data = range(0, WORKERS).map(|i| {
124 let vec_init_r = arc_init_r.clone();
125 let vec_init_i = arc_init_i.clone();
127 Thread::spawn(move|| {
128 let mut res: Vec<u8> = Vec::with_capacity((chunk_size * w) / 8);
129 let init_r_slice = vec_init_r.as_slice();
131 let start = i * chunk_size;
132 let end = if i == (WORKERS - 1) {
133 start + last_chunk_size
138 for &init_i in vec_init_i.slice(start, end).iter() {
139 write_line(init_i, init_r_slice, &mut res);
144 }).collect::<Vec<_>>();
146 try!(writeln!(&mut out as &mut Writer, "P4\n{} {}", w, h));
147 for res in data.into_iter() {
148 try!(out.write(res.join().ok().unwrap().as_slice()));
153 fn write_line(init_i: f64, vec_init_r: &[f64], res: &mut Vec<u8>) {
154 let v_init_i : f64x2 = f64x2(init_i, init_i);
155 let v_2 : f64x2 = f64x2(2.0, 2.0);
156 const LIMIT_SQUARED: f64 = LIMIT * LIMIT;
158 for chunk_init_r in vec_init_r.chunks(8) {
159 let mut cur_byte = 0xff;
163 let v_init_r = f64x2(chunk_init_r[i], chunk_init_r[i + 1]);
164 let mut cur_r = v_init_r;
165 let mut cur_i = v_init_i;
166 let mut r_sq = v_init_r * v_init_r;
167 let mut i_sq = v_init_i * v_init_i;
170 for _ in range(0, ITER) {
174 cur_i = v_2 * r * i + v_init_i;
175 cur_r = r_sq - i_sq + v_init_r;
177 let f64x2(bit1, bit2) = r_sq + i_sq;
179 if bit1 > LIMIT_SQUARED {
184 if bit2 > LIMIT_SQUARED {
189 r_sq = cur_r * cur_r;
190 i_sq = cur_i * cur_i;
193 cur_byte = (cur_byte << 2) + b;
197 res.push(cur_byte^-1);
202 let args = os::args();
203 let args = args.as_slice();
204 let res = if args.len() < 2 {
205 println!("Test mode: do not dump the image because it's not utf8, \
206 which interferes with the test runner.");
207 mandelbrot(1000, io::util::NullWriter)
209 mandelbrot(args[1].parse().unwrap(), io::stdout())