diff options
| -rw-r--r-- | src/main.rs | 129 |
1 files changed, 105 insertions, 24 deletions
diff --git a/src/main.rs b/src/main.rs index 0e1e5ff..c36da4f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,6 @@ extern crate rand; extern crate num_complex; extern crate png; -use std::io; use num_complex::Complex; //stuff for PNG output @@ -14,6 +13,12 @@ use png::HasParameters; use std::cmp; +use std::thread; +use std::sync::mpsc; +use std::time; + +use std::ops::{Add,AddAssign}; + use rand::distributions::{IndependentSample, Range}; struct Trajectory @@ -30,7 +35,6 @@ struct Pixel r : u32, g : u32, b : u32, - a : u32 } impl Trajectory { @@ -63,6 +67,34 @@ impl Trajectory { } } +impl Add for Pixel +{ + type Output = Pixel; + + fn add(self, other:Pixel) -> Pixel{ + Pixel{ + r: self.r + other.r, + g: self.g + other.g, + b: self.b + other.b, + } + } +} + +impl<'a> AddAssign<&'a Pixel> for Pixel +{ + fn add_assign(&mut self, other: &Pixel) { + self.r += other.r; + self.g += other.g; + self.b += other.b; + } +} + +impl Pixel{ + fn max(&self) -> u32{ + cmp::max(self.r,cmp::max(self.g,self.b)) + } +} + fn write_png(filename : &str, pixels : &Vec<Pixel>, max_cnt : u32, width : u32, height : u32){ let mut png_data : Vec<u8> = Vec::with_capacity(pixels.len()*4); for pix in pixels.iter() @@ -94,32 +126,20 @@ fn get_pixel(path_point : &Complex<f64>, width : i32, height : i32) -> i32{ return x_index + y_index*width; } - -fn main() { - - let x = 1920; - let y = 1080; - - let trajectory_count = 1000000; - let path_length = 10000; - - let bailout = 50.0; - - //arrays would do, if we knew size at compile time. We do right now, but we want them tweakable later on +fn buddhabrot(x : usize, y : usize, path_length : usize, bailout : f64, returner : mpsc::Sender<Vec<Pixel>>, syncer : mpsc::Receiver<bool>) { + //thread_local workspace let mut workspace = Vec::with_capacity(x*y); for _number in 0..x*y { - workspace.push(Pixel{r:0, g:0, b:0,a:1}); + workspace.push(Pixel{r:0, g:0, b:0}); } - - - let mut max_cnt = 1; - + let x_range = Range::new(-2.5,1.0); let y_range = Range::new(-1.0,1.0); let mut rng = rand::thread_rng(); - - - for _traj in 0..trajectory_count { + + //println!("Worker initialized, starting calculation"); + //keep on generating until main thread signals us to stop: + while let Err(_e) = syncer.try_recv(){ let offset = Complex::new(x_range.ind_sample(&mut rng),y_range.ind_sample(&mut rng)); let mut traj = Trajectory::new(path_length,offset); traj.run(bailout); @@ -139,13 +159,74 @@ fn main() { item.r = item.r + 1; item.g = item.g + 1; item.b = item.g + 1; - max_cnt = cmp::max(cmp::max(max_cnt,item.b),cmp::max(item.r,item.g)); } } - } + //just send the result. + returner.send(workspace).unwrap(); +} + + +fn main() { + let x = 1920; + let y = 1080; + let path_length = 10000; + + let bailout = 50.0; + + let threads = 16; + + let mut generation_time = 30; + + println!("Starting Threads"); + + let mut thread_handles = Vec::with_capacity(threads); + let mut stop_senders = Vec::with_capacity(threads); + + let (ret_sender, ret_receiver) = mpsc::channel(); + + for _i in 0..threads{ + let (stop_sender, stop_receiver) = mpsc::channel(); + let ret_sender_clone = ret_sender.clone(); + let handle = thread::spawn(move|| { + buddhabrot(x,y,path_length,bailout,ret_sender_clone,stop_receiver); + }); + thread_handles.push(handle); + stop_senders.push(stop_sender); + } + + println!("Letting workers work"); + while generation_time > 0{ + println!("Remaining time: {}",generation_time); + thread::sleep(time::Duration::from_secs(cmp::min(5,generation_time))); + generation_time -= 5; + } + + println!("Telling workers to stop"); + //inform worker threads that they should stop + for sender in stop_senders{ + sender.send(true).unwrap(); + } + + println!("Transmitting first result"); + //wait for all messages. We use the first workspace to come back to accumulate the data + let mut workspace = ret_receiver.recv().unwrap(); + println!("Reading other results and combining them"); + for _i in 1..threads{ + let otherworkspace = ret_receiver.recv().unwrap(); + for idx in 0..workspace.len(){ + workspace[idx] += &otherworkspace[idx]; + } + } + + println!("Normalizing colors"); + let mut max_cnt = 1; + for pixel in &workspace{ + max_cnt = cmp::max(max_cnt,pixel.max()); + } + println!("Writing png"); write_png(r"image.png",&workspace, max_cnt,x as u32,y as u32); } |
