From f0c345841ce14f6ce618d1ed09c1d728bd253c87 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Wed, 30 May 2012 15:18:45 -0700 Subject: [PATCH] Added a factory version of par::mapi, which avoids the need for share_arc, and copies arcs between tasks better. --- src/libstd/par.rs | 55 ++++++++++++++++++++++++---------- src/test/bench/graph500-bfs.rs | 54 +++++++++++++++++---------------- 2 files changed, 68 insertions(+), 41 deletions(-) diff --git a/src/libstd/par.rs b/src/libstd/par.rs index f7d81b3fb09..5263237d684 100644 --- a/src/libstd/par.rs +++ b/src/libstd/par.rs @@ -4,7 +4,7 @@ import comm::send; import comm::recv; import future::future; -export map, mapi, alli, any; +export map, mapi, alli, any, mapi_factory; #[doc="The maximum number of tasks this module will spawn for a single operationg."] @@ -18,15 +18,16 @@ return the intermediate results. This is used to build most of the other parallel vector functions, like map or alli."] -fn map_slices(xs: [A], - f: fn~(uint, [const A]/&) -> B) +fn map_slices( + xs: [A], + f: fn() -> fn~(uint, [const A]/&) -> B) -> [B] { let len = xs.len(); if len < min_granularity { log(info, "small slice"); // This is a small vector, fall back on the normal map. - [f(0u, xs)] + [f()(0u, xs)] } else { let num_tasks = uint::min(max_tasks, len / min_granularity); @@ -40,7 +41,7 @@ fn map_slices(xs: [A], let end = uint::min(len, base + items_per_task); // FIXME: why is the :: annotation required here? vec::unpack_slice::(xs) {|p, _len| - let f = ptr::addr_of(f); + let f = f(); futures += [future::spawn() {|copy base| unsafe { let len = end - base; @@ -52,7 +53,7 @@ fn map_slices(xs: [A], log(info, #fmt("slice: %?", (base, vec::len(slice), end - base))); assert(vec::len(slice) == end - base); - (*f)(base, slice) + f(base, slice) } }]; }; @@ -73,16 +74,40 @@ fn map_slices(xs: [A], #[doc="A parallel version of map."] fn map(xs: [A], f: fn~(A) -> B) -> [B] { - vec::concat(map_slices(xs) {|_base, slice| - vec::map(slice, f) + vec::concat(map_slices(xs) {|| + fn~(_base: uint, slice : [const A]/&) -> [B] { + vec::map(slice, f) + } }) } #[doc="A parallel version of mapi."] fn mapi(xs: [A], f: fn~(uint, A) -> B) -> [B] { - let slices = map_slices(xs) {|base, slice| - vec::mapi(slice) {|i, x| - f(i + base, x) + let slices = map_slices(xs) {|| + fn~(base: uint, slice : [const A]/&) -> [B] { + vec::mapi(slice) {|i, x| + f(i + base, x) + } + } + }; + let r = vec::concat(slices); + log(info, (r.len(), xs.len())); + assert(r.len() == xs.len()); + r +} + +#[doc="A parallel version of mapi. + +In this case, f is a function that creates functions to run over the +inner elements. This is to skirt the need for copy constructors."] +fn mapi_factory( + xs: [A], f: fn() -> fn~(uint, A) -> B) -> [B] { + let slices = map_slices(xs) {|| + let f = f(); + fn~(base: uint, slice : [const A]/&) -> [B] { + vec::mapi(slice) {|i, x| + f(i + base, x) + } } }; let r = vec::concat(slices); @@ -93,16 +118,16 @@ fn mapi(xs: [A], f: fn~(uint, A) -> B) -> [B] { #[doc="Returns true if the function holds for all elements in the vector."] fn alli(xs: [A], f: fn~(uint, A) -> bool) -> bool { - vec::all(map_slices(xs) {|base, slice| + vec::all(map_slices(xs) {|| fn~(base: uint, slice : [const A]/&) -> bool { vec::alli(slice) {|i, x| f(i + base, x) } - }) {|x| x } + }}) {|x| x } } #[doc="Returns true if the function holds for any elements in the vector."] fn any(xs: [A], f: fn~(A) -> bool) -> bool { - vec::any(map_slices(xs) {|_base, slice| + vec::any(map_slices(xs) {|| fn~(_base : uint, slice: [const A]/&) -> bool { vec::any(slice, f) - }) {|x| x } + }}) {|x| x } } diff --git a/src/test/bench/graph500-bfs.rs b/src/test/bench/graph500-bfs.rs index 70e81e8bdd7..577d6bec155 100644 --- a/src/test/bench/graph500-bfs.rs +++ b/src/test/bench/graph500-bfs.rs @@ -227,7 +227,7 @@ fn pbfs(graph: graph, key: node_id) -> bfs_result { } } - let (_res, graph) = arc::shared_arc(copy graph); + let graph = arc::arc(copy graph); let mut i = 0u; while par::any(colors, is_gray) { @@ -236,33 +236,35 @@ fn pbfs(graph: graph, key: node_id) -> bfs_result { i += 1u; let old_len = colors.len(); - let (_res, color) = arc::shared_arc(copy colors); + let color = arc::arc(colors); - colors = par::mapi(colors) {|i, c| - let c : color = c; - let colors = &arc::get_arc(color); - let colors = arc::get(colors); - let graph = &arc::get_arc(graph); - let graph = arc::get(graph); - alt c { - white { - let i = i as node_id; - - let neighbors = (*graph)[i]; - - let mut color = white; - - neighbors.each() {|k| - if is_gray((*colors)[k]) { - color = gray(k); - false - } - else { true } + colors = par::mapi_factory(*arc::get(&color)) {|| + let colors = arc::clone(&color); + let graph = arc::clone(&graph); + fn~(i: uint, c: color) -> color { + let c : color = c; + let colors = arc::get(&colors); + let graph = arc::get(&graph); + alt c { + white { + let i = i as node_id; + + let neighbors = (*graph)[i]; + + let mut color = white; + + neighbors.each() {|k| + if is_gray((*colors)[k]) { + color = gray(k); + false + } + else { true } }; - color - } - gray(parent) { black(parent) } - black(parent) { black(parent) } + color + } + gray(parent) { black(parent) } + black(parent) { black(parent) } + } } }; assert(colors.len() == old_len);