@@ -0,0 +1,62 @@
1+%% can be run via escript if desired...
7+ ring_size = 1 :: non_neg_integer(),
8+ iterations = 1 :: non_neg_integer()
11+main(Argv) when is_list(Argv) ->
12+ Opts = parse_args(Argv),
13+ {Time, ok} = timer:tc(fun() -> run(Opts) end),
14+ io:format("elapsed (wallclock) time: ~pms~n", [Time / 1000]).
16+run(#opts{ ring_size=RingSize, iterations=SendCount }) ->
18+ Msg = {"foobar", "baz"},
19+ Pid = make_ring(RingSize, Self),
20+ [Pid ! Msg || _ <- lists:seq(1, SendCount)],
27+ {"foobar", "baz"} -> collect(N - 1);
28+ Other -> exit({unexpected_message, Other})
31+-spec(make_ring(integer(), pid()) -> pid()).
32+make_ring(0, NextPid) ->
34+make_ring(NumProcs, NextPid) ->
35+ make_ring(NumProcs - 1, go(NextPid)).
37+-spec(go(pid()) -> pid()).
39+ spawn(fun() -> relay(NextPid) end).
41+-spec(relay(pid()) -> no_return()).
44+ {_, _}=Msg -> NextPid ! Msg, relay(NextPid)
47+-spec(parse_args([string()]) -> #opts{}).
49+ lists:foldl(fun parse_args/2, #opts{}, Argv).
51+parse_args(("-r" ++ Val), Opts) ->
52+ Sz = check_positive(ring_size, list_to_integer(Val)),
53+ Opts#opts{ ring_size = Sz };
54+parse_args(("-i" ++ Val), Opts) ->
55+ Iter = check_positive(iterations, list_to_integer(Val)),
56+ Opts#opts{ iterations = Iter }.
58+check_positive(K, N) when N < 1 ->
59+ io:format("~p must be >= 1~n", [K]),
61+check_positive(_, N) ->