zerocaffe.in Blog of Uncaffeinated Experiences on Entrepreneurship and Everything Else

10Jul/081

Erlang Ring Code

Erlang Ring Benchmark Problem:
In the Programming Erlang book by Joe Armstrong, we find this problem at the end of the Concurrent Programming chapter.

Write a ring benchmark. Create N processes in a ring. Send a message round the ring M times so that a total of N * M messages get sent. Time how long this takes for different values of N and M. Write a similar program in some other programming language you are familiar with. Compare the results. Write a blog, and publish the results on the Internet!

My contribution to the already growing list of Erlang Ring Benchmark problem. However this is just the code for the Erlang, a N ring setup and M messages moving around the ring in parallel.

-module(ring).
-export([benchmark/2]).
 
%% run benchmark for N processes and M messages.
benchmark(N, M) ->
        Pids = makering(N),
        for(1, M, fun() -> spawn(fun() -> start(message, Pids) end) end).
 
%% setting up the process ring for sending
%% messages & return the Pids array
makering(M)     ->
        %% create the processes
        Pids = for(1, M, fun() -> spawn(fun() -> loop() end) end),
        [Head | _T] = Pids,
        %% now setup the ring. one simple init loop to make each
        %% each process aware of its next process in the ring
        %% we need to pass Head head here as we want to connect
        %% the last process back to the head.
        connect(Head, Pids),
        %% return the Pids
        Pids.
 
%% If only two elements are left in the list just point
%% the first process to the next process. And point the
%% the last process to the first process.
connect(Head, [H, N])   ->
        H ! {next, N},
        N ! {next, Head};
%% Connect the head and the next element and move to the
%% next elements
connect(Head, [H, N | T])       ->
        H ! {next, N},
        connect(Head, [N | T]).
 
%% send message from the beggining of the 
%% ring.
start(Mesg, Pids)	->
	[Head|T] = Pids,
	Head ! {lists:last(T), Mesg, length(Pids)}.
 
%% order a mass suicide for all process nodes	
killall(Pids)	->
	lists:foreach(fun(Pid) -> Pid ! die end, Pids).
 
%% message waiting loop. waits for message and sends 
%% it to the next process node. commits sepukku if 
%% it is ordered to die.
loop()	->
	receive
		%% now that we have the next pid, we move into the
		%% the listening loop for that function. remember
		%% the loop/1 will share the same Pid as this, so
		%% no worries.
		{next, NextPid} ->
			io:format("Set next for ~p as ~p~n", [self(), NextPid]),
			wait(NextPid)
	end.
 
wait(NextPid)	->
	receive
		{From, Mesg, NumHops}	when NumHops >= 0 ->
			io:format("~w from ~p to ~p~n", [Mesg, From, self()]),
			NextPid ! {self(), Mesg, NumHops - 1},
			wait(NextPid);
		die -> void
	end.
 
%% custom for loops
for(N,N,F)	->	[F()];
for(M,N,F)	->  [F()|for(M + 1, N, F)].
Comments (1) Trackbacks (0)
  1. Try this…

    -module(proces).
    -export([do_ring/1, loopx/0, loopm/3, do_test/0]).

    do_ring(N) -> A = spawn(proces,loopx,[]),
    A ! {create, A, N-1},
    A.

    loopm(Pid0,NextPid, N) -> receive
    0 ->
    %% _ = io:format(“~s ~b~n”,["0 in node", N]),
    %% _ = io:format(“~w ~n”, [now()]),
    loopm(Pid0, NextPid, N);
    die ->
    %% _ = io:format(“~s ~b~n”,["die in node", N]),
    NextPid ! die;
    M when NextPid == Pid0 ->
    %% _ = io:format(“~b ~s ~b~n”,[M,"in node!", N]),
    NextPid ! M-1,
    loopm(Pid0, NextPid, N);
    M ->
    %% _ = io:format(“~b ~s ~b~n”,[M,"in node", N]),
    NextPid ! M,
    loopm(Pid0, NextPid, N)
    end.

    loopx() -> receive
    {create, Pid0, 0} ->
    loopm(Pid0,Pid0, 0);
    {create, Pid0, N} ->
    A = spawn(proces, loopx, []),
    A ! {create, Pid0, N-1},
    loopm(Pid0,A,N)
    end.

    do_test() ->
    P = do_ring(5000),
    _ = io:format(“~w ~n”, [now()]),
    P ! 1000,
    _ = io:format(“~w ~n”, [now()]).


Leave a comment

No trackbacks yet.