diff --git a/src/test/bench/shootout-mandelbrot.rs b/src/test/bench/shootout-mandelbrot.rs index 4909d05b35b1..e62cb8ea849d 100644 --- a/src/test/bench/shootout-mandelbrot.rs +++ b/src/test/bench/shootout-mandelbrot.rs @@ -1,182 +1,60 @@ -// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. +use core::cast::transmute; +use core::from_str::FromStr; +use core::i32::range; +use core::libc::{STDOUT_FILENO, c_int, fdopen, fputc}; -// based on: -// http://shootout.alioth.debian.org/ -// u64q/program.php?test=mandelbrot&lang=python3&id=2 -// -// takes 3 optional args: -// square image size, defaults to 80_u -// output path, default is "" (no output), "-" means stdout -// depth (max iterations per pixel), defaults to 50_u -// -// in the shootout, they use 16000 as image size, 50 as depth, -// and write to stdout: -// -// ./shootout_mandelbrot 16000 "-" 50 > /tmp/mandel.pbm -// -// writes pbm image to output path - -use core::io::WriterUtil; -use core::hashmap::HashMap; - -struct cmplx { - re: f64, - im: f64 -} - -impl ops::Mul for cmplx { - fn mul(&self, x: &cmplx) -> cmplx { - cmplx { - re: self.re*(*x).re - self.im*(*x).im, - im: self.re*(*x).im + self.im*(*x).re - } - } -} - -impl ops::Add for cmplx { - fn add(&self, x: &cmplx) -> cmplx { - cmplx { - re: self.re + (*x).re, - im: self.im + (*x).im - } - } -} - -struct Line {i: uint, b: ~[u8]} - -fn cabs(x: cmplx) -> f64 -{ - x.re*x.re + x.im*x.im -} - -fn mb(x: cmplx, depth: uint) -> bool -{ - let mut z = x; - let mut i = 0; - while i < depth { - if cabs(z) >= 4_f64 { - return false; - } - z = z*z + x; - i += 1; - } - true -} - -fn fillbyte(x: cmplx, incr: f64, depth: uint) -> u8 { - let mut rv = 0_u8; - let mut i = 0_u8; - while i < 8_u8 { - let z = cmplx {re: x.re + (i as f64)*incr, im: x.im}; - if mb(z, depth) { - rv += 1_u8 << (7_u8 - i); - } - i += 1_u8; - } - rv -} - -fn chanmb(i: uint, size: uint, depth: uint) -> Line -{ - let bsize = size/8_u; - let mut crv = vec::with_capacity(bsize); - let incr = 2_f64/(size as f64); - let y = incr*(i as f64) - 1_f64; - let xincr = 8_f64*incr; - for uint::range(0_u, bsize) |j| { - let x = cmplx {re: xincr*(j as f64) - 1.5_f64, im: y}; - crv.push(fillbyte(x, incr, depth)); - }; - Line {i:i, b:crv} -} - -struct Devnull(); - -impl io::Writer for Devnull { - fn write(&self, _b: &const [u8]) {} - fn seek(&self, _i: int, _s: io::SeekStyle) {} - fn tell(&self) -> uint {0_u} - fn flush(&self) -> int {0} - fn get_type(&self) -> io::WriterType { io::File } -} - -fn writer(path: ~str, pport: comm::Port, size: uint) -{ - let cout: @io::Writer = match path { - ~"" => { - @Devnull as @io::Writer - } - ~"-" => { - io::stdout() - } - _ => { - result::get( - &io::file_writer(&Path(path), - ~[io::Create, io::Truncate])) - } - }; - cout.write_line("P4"); - cout.write_line(fmt!("%u %u", size, size)); - let mut lines: HashMap = HashMap::new(); - let mut done = 0_u; - let mut i = 0_u; - while i < size { - let aline = pport.recv(); - if aline.i == done { - debug!("W %u", done); - cout.write(aline.b); - done += 1_u; - let mut prev = done; - while prev <= i { - match lines.pop(&prev) { - Some(pl) => { - debug!("WS %u", prev); - cout.write(pl.b); - done += 1_u; - prev += 1_u; - } - None => break - }; - }; - } - else { - debug!("S %u", aline.i); - lines.insert(aline.i, aline); - }; - i += 1_u; - } -} +static ITER: uint = 50; +static LIMIT: f64 = 2.0; +#[fixed_stack_segment] fn main() { - let args = os::args(); - let args = if os::getenv(~"RUST_BENCH").is_some() { - ~[~"", ~"4000", ~"50"] - } else { - args - }; + unsafe { + let w: i32 = FromStr::from_str(os::args()[1]).get(), h = w; + let mut byte_acc: i8 = 0; + let mut bit_num: i32 = 0; - let depth = if vec::len(args) < 4_u { 50_u } - else { uint::from_str(args[3]).get() }; + println(fmt!("P4\n%d %d", w as int, h as int)); - let path = if vec::len(args) < 3_u { ~"" } - else { copy args[2] }; // FIXME: bad for perf + let mode = "w"; + let stdout = fdopen(STDOUT_FILENO as c_int, transmute(&mode[0])); - let size = if vec::len(args) < 2_u { 80_u } - else { uint::from_str(args[1]).get() }; + for range(0, h) |y| { + let y = y as f64; + for range(0, w) |x| { + let mut (Zr, Zi, Tr, Ti) = (0f64, 0f64, 0f64, 0f64); + let Cr = 2.0 * (x as f64) / (w as f64) - 1.5; + let Ci = 2.0 * (y as f64) / (h as f64) - 1.0; - let (pport, pchan) = comm::stream(); - let pchan = comm::SharedChan::new(pchan); - for uint::range(0_u, size) |j| { - let cchan = pchan.clone(); - do task::spawn { cchan.send(chanmb(j, size, depth)) }; - }; - writer(path, pport, size); + for ITER.times { + if Tr + Ti > LIMIT * LIMIT { + break; + } + + Zi = 2.0*Zr*Zi + Ci; + Zr = Tr - Ti + Cr; + Tr = Zr * Zr; + Ti = Zi * Zi; + } + + byte_acc <<= 1; + if Tr + Ti <= LIMIT * LIMIT { + byte_acc |= 1; + } + + bit_num += 1; + + if bit_num == 8 { + fputc(byte_acc as c_int, stdout); + byte_acc = 0; + bit_num = 0; + } else if x == w - 1 { + byte_acc <<= 8 - w%8; + fputc(byte_acc as c_int, stdout); + byte_acc = 0; + bit_num = 0; + } + } + } + } } +