-module(ring). %% erlc ring.erl; erl +P 10000000 -eval 'io:format("~p~n", [ring:start(1000000, 1000)]), init:stop()' -export([start/2]). start(NActors, NRounds) -> io:format("Starting threads...~n"), First = spawn1(NRounds), Peers = [Last | _] = spawnN(NActors - 1, [First], NRounds), First ! {peer, Last}, io:format("Starting measurement (~p processes)...~n", [length(Peers)]), {Microseconds, ok} = timer:tc(fun () -> [P ! {hop, 0} || P <- Peers], wait_for_all(NActors) end), Seconds = Microseconds / 1000000.0, {ok, {{seconds, Seconds}, {hz, NActors * NRounds / Seconds}}}. wait_for_all(0) -> ok; wait_for_all(Remaining) -> receive one_actor_done -> wait_for_all(Remaining - 1) end. spawn1(NRounds) -> Main = self(), spawn(fun () -> forwarder_main(Main, NRounds) end). spawnN(0, Peers, _NRounds) -> Peers; spawnN(Remaining, Peers = [Peer | _], NRounds) -> A = spawn1(NRounds), A ! {peer, Peer}, spawnN(Remaining - 1, [A | Peers], NRounds). forwarder_main(MainActor, NRounds) -> receive {peer, Peer} -> forwarder_main_loop(MainActor, Peer, NRounds) end. forwarder_main_loop(MainActor, Peer, NRounds) -> receive {hop, HopCount} -> if HopCount < NRounds - 1 -> Peer ! {hop, HopCount + 1}; true -> MainActor ! one_actor_done end, forwarder_main_loop(MainActor, Peer, NRounds) end.