Skip to content

Commit ccb54f0

Browse files
committed
Move par into libstd. Closes #2441.
1 parent f5554db commit ccb54f0

File tree

3 files changed

+111
-114
lines changed

3 files changed

+111
-114
lines changed

src/libstd/par.rs

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import comm::port;
2+
import comm::chan;
3+
import comm::send;
4+
import comm::recv;
5+
import future::future;
6+
7+
export map, mapi, alli, any;
8+
9+
#[doc="The maximum number of tasks this module will spawn for a single
10+
operationg."]
11+
const max_tasks : uint = 32u;
12+
13+
#[doc="The minimum number of elements each task will process."]
14+
const min_granularity : uint = 1024u;
15+
16+
#[doc="An internal helper to map a function over a large vector and
17+
return the intermediate results.
18+
19+
This is used to build most of the other parallel vector functions,
20+
like map or alli."]
21+
fn map_slices<A: copy send, B: copy send>(xs: [A],
22+
f: fn~(uint, [const A]/&) -> B)
23+
-> [B] {
24+
25+
let len = xs.len();
26+
if len < min_granularity {
27+
log(info, "small slice");
28+
// This is a small vector, fall back on the normal map.
29+
[f(0u, xs)]
30+
}
31+
else {
32+
let num_tasks = uint::min(max_tasks, len / min_granularity);
33+
34+
let items_per_task = len / num_tasks;
35+
36+
let mut futures = [];
37+
let mut base = 0u;
38+
log(info, "spawning tasks");
39+
while base < len {
40+
let end = uint::min(len, base + items_per_task);
41+
// FIXME: why is the ::<A, ()> annotation required here?
42+
vec::unpack_slice::<A, ()>(xs) {|p, _len|
43+
let f = ptr::addr_of(f);
44+
futures += [future::spawn() {|copy base|
45+
unsafe {
46+
let len = end - base;
47+
let slice = (ptr::offset(p, base),
48+
len * sys::size_of::<A>());
49+
log(info, #fmt("pre-slice: %?", (base, slice)));
50+
let slice : [const A]/& =
51+
unsafe::reinterpret_cast(slice);
52+
log(info, #fmt("slice: %?",
53+
(base, vec::len(slice), end - base)));
54+
assert(vec::len(slice) == end - base);
55+
(*f)(base, slice)
56+
}
57+
}];
58+
};
59+
base += items_per_task;
60+
}
61+
log(info, "tasks spawned");
62+
63+
log(info, #fmt("num_tasks: %?", (num_tasks, futures.len())));
64+
assert(num_tasks == futures.len());
65+
66+
let r = futures.map() {|ys|
67+
ys.get()
68+
};
69+
assert(r.len() == futures.len());
70+
r
71+
}
72+
}
73+
74+
#[doc="A parallel version of map."]
75+
fn map<A: copy send, B: copy send>(xs: [A], f: fn~(A) -> B) -> [B] {
76+
vec::concat(map_slices(xs) {|_base, slice|
77+
vec::map(slice, f)
78+
})
79+
}
80+
81+
#[doc="A parallel version of mapi."]
82+
fn mapi<A: copy send, B: copy send>(xs: [A], f: fn~(uint, A) -> B) -> [B] {
83+
let slices = map_slices(xs) {|base, slice|
84+
vec::mapi(slice) {|i, x|
85+
f(i + base, x)
86+
}
87+
};
88+
let r = vec::concat(slices);
89+
log(info, (r.len(), xs.len()));
90+
assert(r.len() == xs.len());
91+
r
92+
}
93+
94+
#[doc="Returns true if the function holds for all elements in the vector."]
95+
fn alli<A: copy send>(xs: [A], f: fn~(uint, A) -> bool) -> bool {
96+
vec::all(map_slices(xs) {|base, slice|
97+
vec::alli(slice) {|i, x|
98+
f(i + base, x)
99+
}
100+
}) {|x| x }
101+
}
102+
103+
#[doc="Returns true if the function holds for any elements in the vector."]
104+
fn any<A: copy send>(xs: [A], f: fn~(A) -> bool) -> bool {
105+
vec::any(map_slices(xs) {|_base, slice|
106+
vec::any(slice, f)
107+
}) {|x| x }
108+
}

src/libstd/std.rc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export net, net_tcp;
1717
export uv, uv_ll, uv_iotask, uv_global_loop;
1818
export c_vec, util, timer;
1919
export bitv, deque, fun_treemap, list, map, smallintmap, sort, treemap;
20-
export rope, arena, arc;
20+
export rope, arena, arc, par;
2121
export ebml, dbg, getopts, json, rand, sha1, term, time, prettyprint;
2222
export test, tempfile, serialization;
2323

@@ -67,6 +67,7 @@ mod time;
6767
mod prettyprint;
6868
mod arena;
6969
mod arc;
70+
mod par;
7071

7172
#[cfg(unicode)]
7273
mod unicode;

src/test/bench/graph500-bfs.rs

Lines changed: 1 addition & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import std::map::hashmap;
1111
import std::deque;
1212
import std::deque::t;
1313
import std::arc;
14+
import std::par;
1415
import io::writer_util;
1516
import comm::*;
1617
import int::abs;
@@ -515,116 +516,3 @@ fn main(args: [str]) {
515516
#fmt("Total sequential: %? \t Total Parallel: %? \t Speedup: %?x",
516517
total_seq, total_par, total_seq / total_par));
517518
}
518-
519-
520-
// par stuff /////////////////////////////////////////////////////////
521-
522-
mod par {
523-
import comm::port;
524-
import comm::chan;
525-
import comm::send;
526-
import comm::recv;
527-
import future::future;
528-
529-
#[doc="The maximum number of tasks this module will spawn for a single
530-
operationg."]
531-
const max_tasks : uint = 32u;
532-
533-
#[doc="The minimum number of elements each task will process."]
534-
const min_granularity : uint = 1024u;
535-
536-
#[doc="An internal helper to map a function over a large vector and
537-
return the intermediate results.
538-
539-
This is used to build most of the other parallel vector functions,
540-
like map or alli."]
541-
fn map_slices<A: copy send, B: copy send>(xs: [A],
542-
f: fn~(uint, [const A]/&) -> B)
543-
-> [B] {
544-
545-
let len = xs.len();
546-
if len < min_granularity {
547-
log(info, "small slice");
548-
// This is a small vector, fall back on the normal map.
549-
[f(0u, xs)]
550-
}
551-
else {
552-
let num_tasks = uint::min(max_tasks, len / min_granularity);
553-
554-
let items_per_task = len / num_tasks;
555-
556-
let mut futures = [];
557-
let mut base = 0u;
558-
log(info, "spawning tasks");
559-
while base < len {
560-
let end = uint::min(len, base + items_per_task);
561-
// FIXME: why is the ::<A, ()> annotation required here?
562-
vec::unpack_slice::<A, ()>(xs) {|p, _len|
563-
let f = ptr::addr_of(f);
564-
futures += [future::spawn() {|copy base|
565-
unsafe {
566-
let len = end - base;
567-
let slice = (ptr::offset(p, base),
568-
len * sys::size_of::<A>());
569-
log(info, #fmt("pre-slice: %?", (base, slice)));
570-
let slice : [const A]/& =
571-
unsafe::reinterpret_cast(slice);
572-
log(info, #fmt("slice: %?",
573-
(base, vec::len(slice), end - base)));
574-
assert(vec::len(slice) == end - base);
575-
(*f)(base, slice)
576-
}
577-
}];
578-
};
579-
base += items_per_task;
580-
}
581-
log(info, "tasks spawned");
582-
583-
log(info, #fmt("num_tasks: %?", (num_tasks, futures.len())));
584-
assert(num_tasks == futures.len());
585-
586-
let r = futures.map() {|ys|
587-
ys.get()
588-
};
589-
assert(r.len() == futures.len());
590-
r
591-
}
592-
}
593-
594-
#[doc="A parallel version of map."]
595-
fn map<A: copy send, B: copy send>(xs: [A], f: fn~(A) -> B) -> [B] {
596-
vec::concat(map_slices(xs) {|_base, slice|
597-
vec::map(slice, f)
598-
})
599-
}
600-
601-
#[doc="A parallel version of mapi."]
602-
fn mapi<A: copy send, B: copy send>(xs: [A], f: fn~(uint, A) -> B) -> [B] {
603-
let slices = map_slices(xs) {|base, slice|
604-
vec::mapi(slice) {|i, x|
605-
f(i + base, x)
606-
}
607-
};
608-
let r = vec::concat(slices);
609-
log(info, (r.len(), xs.len()));
610-
assert(r.len() == xs.len());
611-
r
612-
}
613-
614-
#[doc="Returns true if the function holds for all elements in the vector."]
615-
fn alli<A: copy send>(xs: [A], f: fn~(uint, A) -> bool) -> bool {
616-
vec::all(map_slices(xs) {|base, slice|
617-
vec::alli(slice) {|i, x|
618-
f(i + base, x)
619-
}
620-
}) {|x| x }
621-
}
622-
623-
#[doc="Returns true if the function holds for any elements in the vector."]
624-
fn any<A: copy send>(xs: [A], f: fn~(A) -> bool) -> bool {
625-
vec::any(map_slices(xs) {|_base, slice|
626-
vec::any(slice, f)
627-
}) {|x| x }
628-
}
629-
630-
}

0 commit comments

Comments
 (0)