rust/src/test/bench/shootout-mandelbrot.rs

195 lines
4.8 KiB
Rust
Raw Normal View History

// Copyright 2012 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// based on:
2012-02-03 21:50:32 -06:00
// 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
// yield frequency, defaults to 10_u (yield every 10 spawns)
// output path, default is "" (no output), "-" means stdout
//
// in the shootout, they use 16000 as image size
// yield frequency doesn't seem to have much effect
//
// writes pbm image to output path
#[legacy_modes];
extern mod std;
2012-09-05 14:32:05 -05:00
use io::WriterUtil;
2012-09-10 17:38:28 -05:00
use std::map::HashMap;
struct cmplx {
re: f64,
im: f64
}
impl cmplx : ops::Mul<cmplx,cmplx> {
pure 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 cmplx : ops::Add<cmplx,cmplx> {
pure fn add(&self, x: &cmplx) -> cmplx {
cmplx {
re: self.re + (*x).re,
im: self.im + (*x).im
}
}
}
type line = {i: uint, b: ~[u8]};
pure fn cabs(x: cmplx) -> f64
{
2012-02-03 21:50:32 -06:00
x.re*x.re + x.im*x.im
}
fn mb(x: cmplx) -> bool
{
let mut z = cmplx {re: 0f64, im: 0f64};
let mut i = 0;
let mut in = true;
2012-02-03 21:50:32 -06:00
while i < 50 {
z = z*z + x;
if cabs(z) >= 4f64 {
2012-02-03 21:50:32 -06:00
in = false;
break;
}
i += 1;
}
in
}
fn fillbyte(x: cmplx, incr: f64) -> u8 {
let mut rv = 0_u8;
let mut i = 0_u8;
2012-02-03 21:50:32 -06:00
while i < 8_u8 {
let z = cmplx {re: x.re + (i as f64)*incr, im: x.im};
2012-02-03 21:50:32 -06:00
if mb(z) {
rv += 1_u8 << (7_u8 - i);
}
i += 1_u8;
}
rv
}
2012-12-13 16:18:47 -06:00
fn chanmb(i: uint, size: uint, ch: oldcomm::Chan<line>) -> ()
{
let mut crv = ~[];
let incr = 2f64/(size as f64);
let y = incr*(i as f64) - 1f64;
let xincr = 8f64*incr;
2012-06-30 18:19:07 -05:00
for uint::range(0_u, size/8_u) |j| {
let x = cmplx {re: xincr*(j as f64) - 1.5f64, im: y};
crv.push(fillbyte(x, incr));
2012-02-03 21:50:32 -06:00
};
2012-12-13 16:18:47 -06:00
oldcomm::send(ch, {i:i, b:crv});
}
type devnull = {dn: int};
2012-08-14 15:38:35 -05:00
impl devnull: io::Writer {
fn write(_b: &[const u8]) {}
fn seek(+_i: int, +_s: io::SeekStyle) {}
fn tell() -> uint {0_u}
fn flush() -> int {0}
2012-08-14 15:38:35 -05:00
fn get_type() -> io::WriterType { io::File }
}
2012-12-13 16:18:47 -06:00
fn writer(path: ~str, writech: oldcomm::Chan<oldcomm::Chan<line>>, size: uint)
{
2012-12-13 16:18:47 -06:00
let p: oldcomm::Port<line> = oldcomm::Port();
let ch = oldcomm::Chan(&p);
oldcomm::send(writech, ch);
2012-08-14 15:38:35 -05:00
let cout: io::Writer = match path {
2012-08-03 21:59:04 -05:00
~"" => {
2012-08-14 15:38:35 -05:00
{dn: 0} as io::Writer
}
2012-08-03 21:59:04 -05:00
~"-" => {
io::stdout()
}
2012-08-03 21:59:04 -05:00
_ => {
result::get(
2012-09-25 18:23:04 -05:00
&io::file_writer(&Path(path),
2012-08-14 15:38:35 -05:00
~[io::Create, io::Truncate]))
}
};
cout.write_line(~"P4");
2012-08-22 19:24:52 -05:00
cout.write_line(fmt!("%u %u", size, size));
let lines: HashMap<uint, ~[u8]> = HashMap();
let mut done = 0_u;
let mut i = 0_u;
2012-02-03 21:50:32 -06:00
while i < size {
2012-12-13 16:18:47 -06:00
let aline = oldcomm::recv(p);
2012-02-03 21:50:32 -06:00
if aline.i == done {
2012-08-22 19:24:52 -05:00
debug!("W %u", aline.i);
2012-02-03 21:50:32 -06:00
cout.write(aline.b);
done += 1_u;
let mut prev = done;
2012-02-03 21:50:32 -06:00
while prev <= i {
if lines.contains_key(prev) {
2012-08-22 19:24:52 -05:00
debug!("WS %u", prev);
cout.write(lines.get(prev));
2012-02-03 21:50:32 -06:00
done += 1_u;
lines.remove(prev);
prev += 1_u;
}
else {
break
}
};
}
else {
2012-08-22 19:24:52 -05:00
debug!("S %u", aline.i);
lines.insert(aline.i, copy aline.b); // FIXME: bad for perf
2012-02-03 21:50:32 -06:00
};
i += 1_u;
}
}
fn main() {
let args = os::args();
let args = if os::getenv(~"RUST_BENCH").is_some() {
~[~"", ~"4000", ~"10"]
} else {
args
};
let path = if vec::len(args) < 4_u { ~"" }
else { copy args[3] }; // FIXME: bad for perf
let yieldevery = if vec::len(args) < 3_u { 10_u }
else { uint::from_str(args[2]).get() };
let size = if vec::len(args) < 2_u { 80_u }
else { uint::from_str(args[1]).get() };
2012-12-13 16:18:47 -06:00
let writep = oldcomm::Port();
let writech = oldcomm::Chan(&writep);
do task::spawn |move path| {
writer(copy path, writech, size);
2012-02-03 21:50:32 -06:00
};
2012-12-13 16:18:47 -06:00
let ch = oldcomm::recv(writep);
2012-06-30 18:19:07 -05:00
for uint::range(0_u, size) |j| {
task::spawn(|| chanmb(j, size, ch) );
2012-02-03 21:50:32 -06:00
if j % yieldevery == 0_u {
2012-08-22 19:24:52 -05:00
debug!("Y %u", j);
2012-02-03 21:50:32 -06:00
task::yield();
};
};
}