]> git.lizzy.rs Git - rust.git/blob - src/test/bench/shootout-mandelbrot.rs
Doc says to avoid mixing allocator instead of forbiding it
[rust.git] / src / test / bench / shootout-mandelbrot.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 #![feature(macro_rules)]
42 #![feature(simd)]
43 #![allow(experimental)]
44
45 // ignore-pretty very bad with line comments
46
47 use std::io;
48 use std::os;
49 use std::simd::f64x2;
50 use std::sync::{Arc, Future};
51
52 static ITER: int = 50;
53 static LIMIT: f64 = 2.0;
54 static WORKERS: uint = 16;
55
56 #[inline(always)]
57 fn mandelbrot<W: io::Writer>(w: uint, mut out: W) -> io::IoResult<()> {
58     assert!(WORKERS % 2 == 0);
59
60     // Ensure w and h are multiples of 8.
61     let w = (w + 7) / 8 * 8;
62     let h = w;
63
64     let chunk_size = h / WORKERS;
65
66     // Account for remainders in workload division, e.g. 1000 / 16 = 62.5
67     let last_chunk_size = if h % WORKERS != 0 {
68         chunk_size + h % WORKERS
69     } else {
70         chunk_size
71     };
72
73     // precalc values
74     let inverse_w_doubled = 2.0 / w as f64;
75     let inverse_h_doubled = 2.0 / h as f64;
76     let v_inverses = f64x2(inverse_w_doubled, inverse_h_doubled);
77     let v_consts = f64x2(1.5, 1.0);
78
79     // A lot of this code assumes this (so do other lang benchmarks)
80     assert!(w == h);
81     let mut precalc_r = Vec::with_capacity(w);
82     let mut precalc_i = Vec::with_capacity(h);
83
84     let precalc_futures = Vec::from_fn(WORKERS, |i| {
85         Future::spawn(proc () {
86             let mut rs = Vec::with_capacity(w / WORKERS);
87             let mut is = Vec::with_capacity(w / WORKERS);
88
89             let start = i * chunk_size;
90             let end = if i == (WORKERS - 1) {
91                 start + last_chunk_size
92             } else {
93                 (i + 1) * chunk_size
94             };
95
96             // This assumes w == h
97             for x in range(start, end) {
98                 let xf = x as f64;
99                 let xy = f64x2(xf, xf);
100
101                 let f64x2(r, i) = xy * v_inverses - v_consts;
102                 rs.push(r);
103                 is.push(i);
104             }
105
106             (rs, is)
107         })
108     });
109
110     for res in precalc_futures.move_iter() {
111         let (rs, is) = res.unwrap();
112         precalc_r.push_all_move(rs);
113         precalc_i.push_all_move(is);
114     }
115
116     assert_eq!(precalc_r.len(), w);
117     assert_eq!(precalc_i.len(), h);
118
119     let arc_init_r = Arc::new(precalc_r);
120     let arc_init_i = Arc::new(precalc_i);
121
122     let data = Vec::from_fn(WORKERS, |i| {
123         let vec_init_r = arc_init_r.clone();
124         let vec_init_i = arc_init_i.clone();
125
126         Future::spawn(proc () {
127             let mut res: Vec<u8> = Vec::with_capacity((chunk_size * w) / 8);
128             let init_r_slice = vec_init_r.as_slice();
129             for &init_i in vec_init_i.slice(i * chunk_size, (i + 1) * chunk_size).iter() {
130                 write_line(init_i, init_r_slice, &mut res);
131             }
132
133             res
134         })
135     });
136
137     try!(writeln!(&mut out as &mut Writer, "P4\n{} {}", w, h));
138     for res in data.move_iter() {
139         try!(out.write(res.unwrap().as_slice()));
140     }
141     out.flush()
142 }
143
144 fn write_line(init_i: f64, vec_init_r: &[f64], res: &mut Vec<u8>) {
145     let v_init_i : f64x2 = f64x2(init_i, init_i);
146     let v_2 : f64x2 = f64x2(2.0, 2.0);
147     static LIMIT_SQUARED: f64 = LIMIT * LIMIT;
148
149     for chunk_init_r in vec_init_r.chunks(8) {
150         let mut cur_byte = 0xff;
151         let mut i = 0;
152
153         while i < 8 {
154             let v_init_r = f64x2(chunk_init_r[i], chunk_init_r[i + 1]);
155             let mut cur_r = v_init_r;
156             let mut cur_i = v_init_i;
157             let mut r_sq = v_init_r * v_init_r;
158             let mut i_sq = v_init_i * v_init_i;
159
160             let mut b = 0;
161             for _ in range(0, ITER) {
162                 let r = cur_r;
163                 let i = cur_i;
164
165                 cur_i = v_2 * r * i + v_init_i;
166                 cur_r = r_sq - i_sq + v_init_r;
167
168                 let f64x2(bit1, bit2) = r_sq + i_sq;
169
170                 if bit1 > LIMIT_SQUARED {
171                     b |= 2;
172                     if b == 3 { break; }
173                 }
174
175                 if bit2 > LIMIT_SQUARED {
176                     b |= 1;
177                     if b == 3 { break; }
178                 }
179
180                 r_sq = cur_r * cur_r;
181                 i_sq = cur_i * cur_i;
182             }
183
184             cur_byte = (cur_byte << 2) + b;
185             i += 2;
186         }
187
188         res.push(cur_byte^-1);
189     }
190 }
191
192 fn main() {
193     let args = os::args();
194     let args = args.as_slice();
195     let res = if args.len() < 2 {
196         println!("Test mode: do not dump the image because it's not utf8, \
197                   which interferes with the test runner.");
198         mandelbrot(1000, io::util::NullWriter)
199     } else {
200         mandelbrot(from_str(args[1].as_slice()).unwrap(), io::stdout())
201     };
202     res.unwrap();
203 }