Pages

December 28, 2010

Erlang Ring Benchmark

I am reading Joe Armstrong's Programming Erlang: Software for a Concurrent World, in chapter 8 he poses a little challenge to create a ring benchmark:
Write a ring benchmark. Create N processes in a ring. Send a mes- sage 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.
My solution is below... It was fun.

Usage from erlang command line

1> c(ring2).
2> ring2:start(100, 1000). % ring size = 100, send msg 1000 times round the ring
... sample below ...
42> ring2:start(300, 2000).
Starting ring benchmark on pid=<0.30.0>.
Done initializing nodes.
Got X(600000) >= M(600000) in pid=<0.30.0>.
Done running ring benchmark in Wall Clock = 437, Runtime = 391.
ok

The results above were obtained on a Core 2 Duo E8400 @ 3.00GHz

ring2.erl


-module(ring2).
-include("debug.hrl").
-export([start/2]).

%% ring benchmark

start(N, M) ->
    io:format("Starting ring benchmark on pid=~p.~n", [self()]),
    statistics(wall_clock),
    statistics(runtime),
    NextPid = node(N-1, N*M, self(), self()),
    NextPid ! 1,
    io:format("Done initializing nodes.~n"),
    wait(N*M, NextPid, self()),
    NextPid ! die,
    {_, WC} = statistics(wall_clock),
    {_, RT} = statistics(runtime),
    io:format("Done running ring benchmark in Wall Clock = ~p, Runtime = ~p.~n", [WC, RT]).
     
node(1, M, NextPid, DonePid) ->
    Pid = spawn(fun () -> wait(M, NextPid, DonePid) end),
    ?DEBUG("Creating final node: ~p.~n", [Pid]),
    Pid;
node(N, M, NextPid, DonePid) -> 
    Pid = spawn(fun () -> wait(M, NextPid, DonePid) end),
    ?DEBUG("Creating node ~p = ~p.~n", [N, Pid]),
    node(N-1, M, Pid, DonePid).

wait(M, NextPid, DonePid) ->
    receive
 die ->
     ?DEBUG("~p dying.~n", [self()]),
     if NextPid =/= DonePid -> NextPid ! die;
        true -> void
     end,
     void;
 X when X >= M -> 
     io:format("Got X(~p) >= M(~p) in pid=~p.~n", [X, M, self()]),
     DonePid ! die,
     wait(M, NextPid, DonePid);
 X   ->
     ?DEBUG("Got X = ~p in pid=~p, fwd to ~p.~n", [X, self(), NextPid]),
     NextPid ! X+1,
     wait(M, NextPid, DonePid)
    end.     


I am using a little debugging macro to turn logging on/off. At erlang shell: c(ring2, {d, debug}). to turn debugging trace on.

debug.hrl


-ifdef(debug).
-define(DEBUG(Format, Args), io:format("~s.~w: DEBUG: " ++ Format, [ ?MODULE, ?LINE | Args])).
-else.
-define(DEBUG(Format, Args), true).
-endif.

here are some solutions from other people: http://goo.gl/kE42w

No comments :