Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add bridge from Iterator to ParallelIterator #550

Merged
merged 12 commits into from
Jun 6, 2018
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ exclude = ["ci"]

[dependencies]
rayon-core = { version = "1.4", path = "rayon-core" }
crossbeam-deque = "0.2.0"

# This is a public dependency!
[dependencies.either]
Expand Down
5 changes: 5 additions & 0 deletions rayon-demo/src/life/bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,8 @@ fn generations(b: &mut ::test::Bencher) {
fn parallel_generations(b: &mut ::test::Bencher) {
b.iter(|| super::parallel_generations(Board::new(200, 200).random(), 100));
}

#[bench]
fn as_parallel_generations(b: &mut ::test::Bencher) {
b.iter(|| super::par_bridge_generations(Board::new(200, 200).random(), 100));
}
19 changes: 19 additions & 0 deletions rayon-demo/src/life/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use time;

use docopt::Docopt;
use rayon::prelude::*;
use rayon::iter::ParallelBridge;

#[cfg(test)]
mod bench;
Expand Down Expand Up @@ -93,6 +94,15 @@ impl Board {
self.next_board(new_brd)
}

pub fn par_bridge_next_generation(&self) -> Board {
let new_brd = (0..self.len())
.par_bridge()
.map(|cell| self.successor_cell(cell))
.collect();

self.next_board(new_brd)
}

fn cell_live(&self, x: usize, y: usize) -> bool {
!(x >= self.cols || y >= self.rows) && self.board[y * self.cols + x]
}
Expand Down Expand Up @@ -145,6 +155,11 @@ fn parallel_generations(board: Board, gens: usize) {
for _ in 0..gens { brd = brd.parallel_next_generation(); }
}

fn par_bridge_generations(board: Board, gens: usize) {
let mut brd = board;
for _ in 0..gens { brd = brd.par_bridge_next_generation(); }
}

fn measure(f: fn(Board, usize) -> (), args: &Args) -> u64 {
let (n, gens) = (args.flag_size, args.flag_gens);
let brd = Board::new(n, n).random();
Expand All @@ -168,5 +183,9 @@ pub fn main(args: &[String]) {
let parallel = measure(parallel_generations, &args);
println!("parallel: {:10} ns -> {:.2}x speedup", parallel,
serial as f64 / parallel as f64);

let par_bridge = measure(par_bridge_generations, &args);
println!("par_bridge: {:10} ns -> {:.2}x speedup", par_bridge,
serial as f64 / par_bridge as f64);
}
}
5 changes: 5 additions & 0 deletions rayon-demo/src/nbody/bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ fn nbody_par(b: &mut ::test::Bencher) {
nbody_bench(b, |n| { n.tick_par(); });
}

#[bench]
fn nbody_par_bridge(b: &mut ::test::Bencher) {
nbody_bench(b, |n| { n.tick_par_bridge(); });
}

#[bench]
fn nbody_parreduce(b: &mut ::test::Bencher) {
nbody_bench(b, |n| { n.tick_par_reduce(); });
Expand Down
195 changes: 117 additions & 78 deletions rayon-demo/src/nbody/nbody.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@
// [1]: https://github.com/IntelLabs/RiverTrail/blob/master/examples/nbody-webgl/NBody.js

use cgmath::{InnerSpace, Point3, Vector3, Zero};
use rayon::prelude::*;
use rand::{Rand, Rng};
use rayon::prelude::*;
#[cfg(test)]
use rayon::iter::ParallelBridge;
use std::f64::consts::PI;

const INITIAL_VELOCITY: f64 = 8.0; // set to 0.0 to turn off.
Expand All @@ -50,8 +52,7 @@ pub struct Body {

impl NBodyBenchmark {
pub fn new<R: Rng>(num_bodies: usize, rng: &mut R) -> NBodyBenchmark {
let bodies0: Vec<_> =
(0..num_bodies)
let bodies0: Vec<_> = (0..num_bodies)
.map(|_| {
let position = Point3 {
x: f64::rand(rng).floor() * 40_000.0,
Expand All @@ -71,7 +72,11 @@ impl NBodyBenchmark {
z: f64::rand(rng) * INITIAL_VELOCITY,
};

Body { position: position, velocity: velocity, velocity2: velocity2 }
Body {
position: position,
velocity: velocity,
velocity2: velocity2,
}
})
.collect();

Expand All @@ -91,16 +96,44 @@ impl NBodyBenchmark {
};

let time = self.time;
out_bodies.par_iter_mut()
.zip(&in_bodies[..])
.for_each(|(out, prev)| {
let (vel, vel2) = next_velocity(time, prev, in_bodies);
out.velocity = vel;
out.velocity2 = vel2;
out_bodies
.par_iter_mut()
.zip(&in_bodies[..])
.for_each(|(out, prev)| {
let (vel, vel2) = next_velocity(time, prev, in_bodies);
out.velocity = vel;
out.velocity2 = vel2;

let next_velocity = vel - vel2;
out.position = prev.position + next_velocity;
});

let next_velocity = vel - vel2;
out.position = prev.position + next_velocity;
});
self.time += 1;

out_bodies
}

#[cfg(test)]
pub fn tick_par_bridge(&mut self) -> &[Body] {
let (in_bodies, out_bodies) = if (self.time & 1) == 0 {
(&self.bodies.0, &mut self.bodies.1)
} else {
(&self.bodies.1, &mut self.bodies.0)
};

let time = self.time;
out_bodies
.iter_mut()
.zip(&in_bodies[..])
.par_bridge()
.for_each(|(out, prev)| {
let (vel, vel2) = next_velocity(time, prev, in_bodies);
out.velocity = vel;
out.velocity2 = vel2;

let next_velocity = vel - vel2;
out.position = prev.position + next_velocity;
});

self.time += 1;

Expand All @@ -115,16 +148,17 @@ impl NBodyBenchmark {
};

let time = self.time;
out_bodies.par_iter_mut()
.zip(&in_bodies[..])
.for_each(|(out, prev)| {
let (vel, vel2) = next_velocity_par(time, prev, in_bodies);
out.velocity = vel;
out.velocity2 = vel2;

let next_velocity = vel - vel2;
out.position = prev.position + next_velocity;
});
out_bodies
.par_iter_mut()
.zip(&in_bodies[..])
.for_each(|(out, prev)| {
let (vel, vel2) = next_velocity_par(time, prev, in_bodies);
out.velocity = vel;
out.velocity2 = vel2;

let next_velocity = vel - vel2;
out.position = prev.position + next_velocity;
});

self.time += 1;

Expand Down Expand Up @@ -207,57 +241,57 @@ fn next_velocity(time: usize, prev: &Body, bodies: &[Body]) -> (Vector3<f64>, Ve
let zero: Vector3<f64> = Vector3::zero();
let (diff, diff2) = bodies
.iter()
.fold(
(zero, zero),
|(mut diff, mut diff2), body| {
let r = body.position - prev.position;

// make sure we are not testing the particle against its own position
let are_same = r == Vector3::zero();

let dist_sqrd = r.magnitude2();

if dist_sqrd < zone_sqrd && !are_same {
let length = dist_sqrd.sqrt();
let percent = dist_sqrd / zone_sqrd;

if dist_sqrd < repel {
let f = (repel / percent - 1.0) * 0.025;
let normal = (r / length) * f;
diff += normal;
diff2 += normal;
} else if dist_sqrd < align {
let thresh_delta = align - repel;
let adjusted_percent = (percent - repel) / thresh_delta;
let q = (0.5 - (adjusted_percent * PI * 2.0).cos() * 0.5 + 0.5) * 100.9;

// normalize vel2 and multiply by factor
let vel2_length = body.velocity2.magnitude();
let vel2 = (body.velocity2 / vel2_length) * q;

// normalize own velocity
let vel_length = prev.velocity.magnitude();
let vel = (prev.velocity / vel_length) * q;
.fold((zero, zero), |(mut diff, mut diff2), body| {
let r = body.position - prev.position;

// make sure we are not testing the particle against its own position
let are_same = r == Vector3::zero();

let dist_sqrd = r.magnitude2();

if dist_sqrd < zone_sqrd && !are_same {
let length = dist_sqrd.sqrt();
let percent = dist_sqrd / zone_sqrd;

if dist_sqrd < repel {
let f = (repel / percent - 1.0) * 0.025;
let normal = (r / length) * f;
diff += normal;
diff2 += normal;
} else if dist_sqrd < align {
let thresh_delta = align - repel;
let adjusted_percent = (percent - repel) / thresh_delta;
let q = (0.5 - (adjusted_percent * PI * 2.0).cos() * 0.5 + 0.5) * 100.9;

// normalize vel2 and multiply by factor
let vel2_length = body.velocity2.magnitude();
let vel2 = (body.velocity2 / vel2_length) * q;

// normalize own velocity
let vel_length = prev.velocity.magnitude();
let vel = (prev.velocity / vel_length) * q;

diff += vel2;
diff2 += vel;
}

diff += vel2;
diff2 += vel;
}
if dist_sqrd > attract {
// attract
let thresh_delta2 = 1.0 - attract;
let adjusted_percent2 = (percent - attract) / thresh_delta2;
let c =
(1.0 - ((adjusted_percent2 * PI * 2.0).cos() * 0.5 + 0.5)) * attract_power;

if dist_sqrd > attract { // attract
let thresh_delta2 = 1.0 - attract;
let adjusted_percent2 = (percent - attract) / thresh_delta2;
let c = (1.0 - ((adjusted_percent2 * PI * 2.0).cos() * 0.5 + 0.5)) * attract_power;
// normalize the distance vector
let d = (r / length) * c;

// normalize the distance vector
let d = (r / length) * c;

diff += d;
diff2 -= d;
}
diff += d;
diff2 -= d;
}
}

(diff, diff2)
});
(diff, diff2)
});

acc += diff;
acc2 += diff2;
Expand Down Expand Up @@ -294,8 +328,7 @@ fn next_velocity(time: usize, prev: &Body, bodies: &[Body]) -> (Vector3<f64>, Ve
}

/// Compute next velocity of `prev`
fn next_velocity_par(time: usize, prev: &Body, bodies: &[Body])
-> (Vector3<f64>, Vector3<f64>) {
fn next_velocity_par(time: usize, prev: &Body, bodies: &[Body]) -> (Vector3<f64>, Vector3<f64>) {
let time = time as f64;
let center = Point3 {
x: (time / 22.0).cos() * -4200.0,
Expand Down Expand Up @@ -344,8 +377,9 @@ fn next_velocity_par(time: usize, prev: &Body, bodies: &[Body])

let (diff, diff2) = bodies
.par_iter()
.fold(|| (Vector3::zero(), Vector3::zero()),
|(mut diff, mut diff2), body| {
.fold(
|| (Vector3::zero(), Vector3::zero()),
|(mut diff, mut diff2), body| {
let r = body.position - prev.position;

// make sure we are not testing the particle against its own position
Expand Down Expand Up @@ -379,10 +413,12 @@ fn next_velocity_par(time: usize, prev: &Body, bodies: &[Body])
diff2 += vel;
}

if dist_sqrd > attract { // attract
if dist_sqrd > attract {
// attract
let thresh_delta2 = 1.0 - attract;
let adjusted_percent2 = (percent - attract) / thresh_delta2;
let c = (1.0 - ((adjusted_percent2 * PI * 2.0).cos() * 0.5 + 0.5)) * attract_power;
let c = (1.0 - ((adjusted_percent2 * PI * 2.0).cos() * 0.5 + 0.5))
* attract_power;

// normalize the distance vector
let d = (r / length) * c;
Expand All @@ -393,9 +429,12 @@ fn next_velocity_par(time: usize, prev: &Body, bodies: &[Body])
}

(diff, diff2)
})
.reduce(|| (Vector3::zero(), Vector3::zero()),
|(diffa, diff2a), (diffb, diff2b)| (diffa + diffb, diff2a + diff2b));
},
)
.reduce(
|| (Vector3::zero(), Vector3::zero()),
|(diffa, diff2a), (diffb, diff2b)| (diffa + diffb, diff2a + diff2b),
);

acc += diff;
acc2 += diff2;
Expand Down
3 changes: 3 additions & 0 deletions src/iter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ use self::plumbing::*;
// e.g. `find::find()`, are always used **prefixed**, so that they
// can be readily distinguished.

mod par_bridge;
pub use self::par_bridge::{ParallelBridge, IterParallel};

mod find;
mod find_first_last;
mod chain;
Expand Down
Loading