In my previous post, I presented a Java solution to the Ring problem. Following is my Erlang solution.
-module(ring_benchmark).
-export([start/2, ring_starter/1, ring_member/1, count_down/0]).

start(N, M) ->
	statistics(runtime),
	statistics(wall_clock),

	CountDown = spawn(?MODULE, count_down, []),
	First = spawn(?MODULE, ring_starter, [CountDown]),
	Last = init_ring(N-1, First),

	{_, Spawn_RT} = statistics(runtime),
	{_, Spawn_WC} = statistics(wall_clock),
	io:format("Spawn time=~p (~p) milliseconds~n" , [Spawn_RT, Spawn_WC]),

	Messages = create_messages(M),

	CountDown ! {start},
	[First ! {pass, Last, AMessage} || AMessage <- Messages],

	ok.

init_ring(0, Neighbor) ->
	Neighbor;
init_ring(N, Neighbor) ->
	Next = spawn(?MODULE, ring_member, [Neighbor]),
	init_ring(N-1, Next).

%% Creates M messages. The last message is {quit}
create_messages(1) ->
	[quit];
create_messages(M) ->
	[M | create_messages(M - 1)].

%% First member in the ring
ring_starter(CountDown) ->
	receive
		{quit} ->
			CountDown ! {stop};
		{Message} ->
			ring_starter(CountDown);
		{pass, To, Message} ->
			To ! {Message},
			ring_starter(CountDown)
	end.

%% Represents all other members in a ring
ring_member(Neighbor) ->
	receive
		{quit} ->
			Neighbor ! {quit};
		{Message} ->
			Neighbor ! {Message},
			ring_member(Neighbor)
	end.

count_down() ->
	receive
		{start} ->
			statistics(runtime),
			statistics(wall_clock),
			count_down();
		{stop} ->
			{_, PassEnd_RT} = statistics(runtime),
			{_, PassEnd_WC} = statistics(wall_clock),
			io:format("Message passing time=~p (~p) milliseconds~n" , [PassEnd_RT, PassEnd_WC])
	end.
The starting point of the program is start(N, M). A ring of N members is constructed with init_ring() functions. The Pid of each member is passed to the next member during creation of ring_member. The first member of the ring is ring_starter(). It starts passing messages by sending message to the last member and waits for the same message to come back to it. The last message is {quit}. When the last message comes back to the ring_starter() the program ends. count_down() is used to track the time taken. I've stripped out io:format() statements, which are like debug statements. They show messages being passed around in the ring. The same program with io:format() statements is given below:
-module(ring).
-export([start/2, ring_starter/1, ring_member/1, count_down/0]).

start(N, M) ->
	statistics(runtime),
	statistics(wall_clock),

	CountDown = spawn(?MODULE, count_down, []),
	First = spawn(?MODULE, ring_starter, [CountDown]),
	Last = init_ring(N-1, First),

	{_, Spawn_RT} = statistics(runtime),
	{_, Spawn_WC} = statistics(wall_clock),
	io:format("Spawn time=~p (~p) milliseconds~n" , [Spawn_RT, Spawn_WC]),

	Messages = create_messages(M),

	CountDown ! {start},
	[First ! {pass, Last, AMessage} || AMessage <- Messages],

	ok.

init_ring(0, Neighbor) ->
	Neighbor;
init_ring(N, Neighbor) ->
	Next = spawn(?MODULE, ring_member, [Neighbor]),
	init_ring(N-1, Next).

%% Creates M messages. The last message is {quit}
create_messages(1) ->
	[quit];
create_messages(M) ->
	[M | create_messages(M - 1)].

%% First member in the ring
ring_starter(CountDown) ->
	receive
		{quit} ->
			CountDown ! {stop},
			io:format("~w received ~w~n", [self(), quit]);
		{Message} ->
			io:format("~w received ~w~n", [self(), Message]),
			ring_starter(CountDown);
		{pass, To, Message} ->
			To ! {Message},
			io:format("~w sent ~w to ~w~n", [self(), Message, To]),
			ring_starter(CountDown)
	end.

%% Represents all other members in a ring
ring_member(Neighbor) ->
	receive
		{quit} ->
			Neighbor ! {quit},
			io:format("~w sent ~w to ~w~n", [self(), quit, Neighbor]);
		{Message} ->
			Neighbor ! {Message},
			io:format("~w sent ~w to ~w~n", [self(), Message, Neighbor]),
			ring_member(Neighbor)
	end.

count_down() ->
	receive
		{start} ->
			statistics(runtime),
			statistics(wall_clock),
			count_down();
		{stop} ->
			{_, PassEnd_RT} = statistics(runtime),
			{_, PassEnd_WC} = statistics(wall_clock),
			io:format("Message passing time=~p (~p) milliseconds~n" , [PassEnd_RT, PassEnd_WC])
	end.
I construct a list of M messages and pass each message at a time. This line does exactly that:
[First ! {pass, Last, AMessage} || AMessage <- Messages]
This is equivalent to the call: pass_messages(First, Last, Messages)
pass_messages(First, Last, [Message | []]) ->
	First ! {pass, Last, Message};
pass_messages(First, Last, [Message | Rest]) ->
	First ! {pass, Last, Message},
	pass_messages(First, Last, Rest).
In my next post, I'll show message processing times for different values of N and M in Java 6 and Erlang.