Skip to content

Commit 1a276db

Browse files
committed
Switch map-reduce control protocol to use pipes. This exposed a bug in the pipe compiler, which is now fixed.
Use hashmaps in MapReduce Tweak word-count difficulty
1 parent d5b8bbb commit 1a276db

File tree

2 files changed

+101
-65
lines changed

2 files changed

+101
-65
lines changed

src/libsyntax/ext/pipes/pipec.rs

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -56,34 +56,11 @@ impl methods for message {
5656

5757
// Return the type parameters actually used by this message
5858
fn get_params() -> ~[ast::ty_param] {
59-
let mut used = ~[];
6059
alt self {
61-
message(_, tys, this, _, next_tys) {
62-
let parms = this.ty_params;
63-
for vec::append(tys, next_tys).each |ty| {
64-
alt ty.node {
65-
ast::ty_path(path, _) {
66-
if path.idents.len() == 1 {
67-
let id = path.idents[0];
68-
69-
let found = parms.find(|p| id == p.ident);
70-
71-
alt found {
72-
some(p) {
73-
if !used.contains(p) {
74-
vec::push(used, p);
75-
}
76-
}
77-
none { }
78-
}
79-
}
80-
}
81-
_ { }
82-
}
83-
}
60+
message(_, _, this, _, _) {
61+
this.ty_params
8462
}
8563
}
86-
used
8764
}
8865

8966
fn gen_send(cx: ext_ctxt) -> @ast::item {

src/test/bench/task-perf-word-count-generic.rs

Lines changed: 99 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ import option = option;
1414
import option::some;
1515
import option::none;
1616
import str;
17-
import std::treemap;
17+
import std::map;
18+
import std::map::hashmap;
1819
import vec;
1920
import io;
2021
import io::{reader_util, writer_util};
@@ -30,10 +31,30 @@ import comm::recv;
3031
import comm::send;
3132
import comm::methods;
3233

34+
macro_rules! move {
35+
{ $x:expr } => { unsafe { let y <- *ptr::addr_of($x); y } }
36+
}
37+
3338
trait word_reader {
3439
fn read_word() -> option<str>;
3540
}
3641

42+
trait hash_key {
43+
fn hash() -> uint;
44+
fn eq(self) -> bool;
45+
}
46+
47+
fn mk_hash<K: const hash_key, V: copy>() -> map::hashmap<K, V> {
48+
fn hashfn<K: const hash_key>(k: K) -> uint { k.hash() }
49+
50+
map::hashmap(hashfn::<K>, |x, y| x.eq(y))
51+
}
52+
53+
impl of hash_key for str {
54+
fn hash() -> uint { str::hash(self) }
55+
fn eq(&&x: str) -> bool { str::eq(self, x) }
56+
}
57+
3758
// These used to be in task, but they disappeard.
3859
type joinable_task = port<()>;
3960
fn spawn_joinable(+f: fn~()) -> joinable_task {
@@ -79,6 +100,23 @@ fn reduce(&&word: str, get: map_reduce::getter<int>) {
79100
io::println(#fmt("%s\t%?", word, count));
80101
}
81102

103+
class box<T> {
104+
let mut contents: option<T>;
105+
new(+x: T) { self.contents = some(x); }
106+
107+
fn swap(f: fn(+T) -> T) {
108+
let mut tmp = none;
109+
self.contents <-> tmp;
110+
self.contents = some(f(option::unwrap(tmp)));
111+
}
112+
113+
fn unwrap() -> T {
114+
let mut tmp = none;
115+
self.contents <-> tmp;
116+
option::unwrap(tmp)
117+
}
118+
}
119+
82120
mod map_reduce {
83121
export putter;
84122
export getter;
@@ -99,54 +137,74 @@ mod map_reduce {
99137
mapper_done
100138
}
101139

140+
141+
proto! ctrl_proto {
142+
open: send<K: copy send, V: copy send> {
143+
find_reducer(K) -> reducer_response<K, V>,
144+
mapper_done -> terminated
145+
}
146+
147+
reducer_response: recv<K: copy send, V: copy send> {
148+
reducer(chan<reduce_proto<V>>) -> open<K, V>
149+
}
150+
151+
terminated: send { }
152+
}
153+
102154
enum reduce_proto<V: copy send> { emit_val(V), done, ref, release }
103155

104-
fn start_mappers<K1: copy send, K2: copy send, V: copy send>(
156+
fn start_mappers<K1: copy send, K2: const copy send hash_key,
157+
V: copy send>(
105158
map: mapper<K1, K2, V>,
106-
ctrl: chan<ctrl_proto<K2, V>>, inputs: ~[K1])
159+
&ctrls: ~[ctrl_proto::server::open<K2, V>],
160+
inputs: ~[K1])
107161
-> ~[joinable_task]
108162
{
109163
let mut tasks = ~[];
110164
for inputs.each |i| {
165+
let (ctrl, ctrl_server) = ctrl_proto::init();
166+
let ctrl = box(ctrl);
111167
vec::push(tasks, spawn_joinable(|| map_task(map, ctrl, i) ));
168+
vec::push(ctrls, ctrl_server);
112169
}
113170
ret tasks;
114171
}
115172

116-
fn map_task<K1: copy send, K2: copy send, V: copy send>(
173+
fn map_task<K1: copy send, K2: const copy send hash_key, V: copy send>(
117174
map: mapper<K1, K2, V>,
118-
ctrl: chan<ctrl_proto<K2, V>>,
175+
ctrl: box<ctrl_proto::client::open<K2, V>>,
119176
input: K1)
120177
{
121178
// log(error, "map_task " + input);
122-
let intermediates = treemap::treemap();
179+
let intermediates = mk_hash();
123180

124-
fn emit<K2: copy send, V: copy send>(
125-
im: treemap::treemap<K2, chan<reduce_proto<V>>>,
126-
ctrl: chan<ctrl_proto<K2, V>>, key: K2, val: V)
127-
{
128-
let c;
129-
alt treemap::find(im, key) {
130-
some(_c) { c = _c; }
181+
do map(input) |key, val| {
182+
let mut c = none;
183+
alt intermediates.find(key) {
184+
some(_c) { c = some(_c); }
131185
none {
132-
let p = port();
133-
send(ctrl, find_reducer(key, chan(p)));
134-
c = recv(p);
135-
treemap::insert(im, key, c);
136-
send(c, ref);
186+
do ctrl.swap |ctrl| {
187+
let ctrl = ctrl_proto::client::find_reducer(ctrl, key);
188+
alt pipes::recv(ctrl) {
189+
ctrl_proto::reducer(c_, ctrl) {
190+
c = some(c_);
191+
move!{ctrl}
192+
}
193+
}
194+
}
195+
intermediates.insert(key, c.get());
196+
send(c.get(), ref);
137197
}
138198
}
139-
send(c, emit_val(val));
199+
send(c.get(), emit_val(val));
140200
}
141201

142-
map(input, {|a,b|emit(intermediates, ctrl, a, b)});
143-
144202
fn finish<K: copy send, V: copy send>(_k: K, v: chan<reduce_proto<V>>)
145203
{
146204
send(v, release);
147205
}
148-
treemap::traverse(intermediates, finish);
149-
send(ctrl, mapper_done);
206+
for intermediates.each_value |v| { send(v, release) }
207+
ctrl_proto::client::mapper_done(ctrl.unwrap());
150208
}
151209

152210
fn reduce_task<K: copy send, V: copy send>(
@@ -184,30 +242,32 @@ mod map_reduce {
184242
reduce(key, || get(p, ref_count, is_done) );
185243
}
186244

187-
fn map_reduce<K1: copy send, K2: copy send, V: copy send>(
245+
fn map_reduce<K1: copy send, K2: const copy send hash_key, V: copy send>(
188246
map: mapper<K1, K2, V>,
189247
reduce: reducer<K2, V>,
190248
inputs: ~[K1])
191249
{
192-
let ctrl = port();
250+
let mut ctrl = ~[];
193251

194252
// This task becomes the master control task. It task::_spawns
195253
// to do the rest.
196254

197-
let reducers = treemap::treemap();
198-
let mut tasks = start_mappers(map, chan(ctrl), inputs);
255+
let reducers = mk_hash();
256+
let mut tasks = start_mappers(map, ctrl, inputs);
199257
let mut num_mappers = vec::len(inputs) as int;
200258

201259
while num_mappers > 0 {
202-
alt recv(ctrl) {
203-
mapper_done {
260+
let (_ready, message, ctrls) = pipes::select(ctrl);
261+
alt option::unwrap(message) {
262+
ctrl_proto::mapper_done(_) {
204263
// #error("received mapper terminated.");
205264
num_mappers -= 1;
265+
ctrl = ctrls;
206266
}
207-
find_reducer(k, cc) {
267+
ctrl_proto::find_reducer(k, cc) {
208268
let c;
209269
// log(error, "finding reducer for " + k);
210-
alt treemap::find(reducers, k) {
270+
alt reducers.find(k) {
211271
some(_c) {
212272
// log(error,
213273
// "reusing existing reducer for " + k);
@@ -221,19 +281,17 @@ mod map_reduce {
221281
vec::push(tasks,
222282
spawn_joinable(|| reduce_task(r, kk, ch) ));
223283
c = recv(p);
224-
treemap::insert(reducers, k, c);
284+
reducers.insert(k, c);
225285
}
226286
}
227-
send(cc, c);
287+
ctrl = vec::append_one(
288+
ctrls,
289+
ctrl_proto::server::reducer(move!{cc}, c));
228290
}
229291
}
230292
}
231293

232-
fn finish<K: copy send, V: copy send>(_k: K, v: chan<reduce_proto<V>>)
233-
{
234-
send(v, done);
235-
}
236-
treemap::traverse(reducers, finish);
294+
for reducers.each_value |v| { send(v, done) }
237295

238296
for tasks.each |t| { join(t); }
239297
}
@@ -254,7 +312,7 @@ fn main(argv: ~[str]) {
254312
}
255313
else {
256314
let num_readers = 50;
257-
let words_per_reader = 1000;
315+
let words_per_reader = 600;
258316
vec::from_fn(
259317
num_readers,
260318
|_i| fn~() -> word_reader {
@@ -301,7 +359,8 @@ class random_word_reader: word_reader {
301359
fn read_word() -> option<str> {
302360
if self.remaining > 0 {
303361
self.remaining -= 1;
304-
some(self.rng.gen_str(5))
362+
let len = self.rng.gen_uint_range(1, 4);
363+
some(self.rng.gen_str(len))
305364
}
306365
else { none }
307366
}

0 commit comments

Comments
 (0)