self halt

May 23, 2008

Ring Benchmark – my first concurrent Erlang

Filed under: coding4fun, erlang — Ernest Micklei @ 10:47 pm
Tags: ,

Following the advice of Dave Thomas who said: “any developer should learn a new language every year” on RailsConf 2007 in Berlin, I decided that Erlang was going to be my challenge for 2008. However, the first months of 2008 passed without any Erlang until I listened to Joe Armstrong himself at Qcon in London. His talk was inspiring to me so right afterwards I bought his book and start reading it on my flight home.

After working myself through the first chapters, I finally got to the part that explained concurrent programming. In his book, he invites the reader to create an Erlang program that implements the Ring Benchmark. So I did and here is my version.

Problem:

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.

Solution:


-module(ring_benchmark).
-export([start/2]).
%
% Create a ring of N processes through which a message is send M times.
% First, create a chain of processes: First,...,Last
% Then send a composed message to the first process containing:
% - throw, the type of request
% - the message (payload)
% - the process id of the last created process of the ring
% - number of times the message must be thrown through the ring.
%
% @author Ernest Micklei, PhilemonWorks.com, May 2008
%
start(N,M) ->
	First = spawn(fun() -> receive_send(void) end),
	io:format("Created ~p~n",[First]),
	Last = connect(First,N-1),
	io:format("~p will send messages to ~p~n", [First,Last]),
	First ! {throw,ball,Last,M},
	done.
%
% Create a new process that will send messages to the process with ID = To
% Repeat this Count times, forming a chain (not a ring!) of processes.
% Return the process ID of the last created process.
%
connect(To,Count) ->
	Next = spawn(fun() -> receive_send(To) end),
	io:format("Created ~p~n",[Next]),
	io:format("~p will send messages to ~p~n", [Next,To]),
 	case (Count =:= 1) of
		true -> Next;
		false -> connect(Next,Count-1)
	end.
%
% Each process will exectue this in a loop.
% To is the process ID of the next process in the ring.
% If a throw request is received then send it to the ring.
% When the message is received, throw it again if the count > 0
% Else, send a die request to kill all processes of the ring.
%
receive_send(To) ->
	receive
		{Message,Ring,Count} ->
			case (To =:= void) of
				true ->
					io:format("~p received ~p (~p)~n",[self(),Message,Count]),
					case (Count =:= 0) of
						true ->
							{_,TimeAfter} = statistics(runtime),
							io:format("Completed in ~p [ms]~n",[TimeAfter]),
							Ring ! die;
						false ->
							Ring ! {Message,Ring,Count-1}
					end,
					receive_send(void);
				false ->
					io:format("~p received ~p (~p), sending it to: ~p~n",
						[self(),Message,Count,To]),
					To ! {Message,Ring,Count},
					receive_send(To)
			end;
		{throw,Message,Ring,Count} ->
			io:format("start throwing ~p ~p times through ring starting at: ~p~n",
				[Message,Count,Ring]),
			statistics(runtime),
			Ring ! {Message,Ring,Count},
			receive_send(To);
		die ->
			io:format("~p died~n",[self()]),
			case (To =:= void) of
				true -> void;
				false -> To ! die
			end
	end.


Download source

If you are interested in numbers, N=10.000, M=10.000 on my Mac Book Pro took 101.290 milliseconds (runtime). I might update this post later after doing some more tests with different parameter sets.

May 15, 2008

SelfDiagnose for Ruby on Rails

Filed under: SelfDiagnose, rails — Ernest Micklei @ 11:41 am
Tags: , , ,

SelfDianogse is a library of tasks to diagnose a running system with respect to its dependent external resources. Recently, I did some Rails development and was thinking about how to implement it for the Ruby on Rails framework ? Obvious choice is to make a plugin that on installation adds the SelfDiagnoseController.rb to the application. Because of the scripting nature of Rails framework, putting the configuration in XML (as it is done for Java) is not the Ruby-way. So either use YAML or put the configuration directly into the controller. Let’s investigate the latter.

class SelfdiagnoseController < ActionController
  include SelfDiagnose

  tasks {
      check_database_connection 'mysql'
      check_directory_readable '/path/to/dir'
      check_log_writeable 'production.log'
      check_url_accessable 'http://s3browse.com'
  }
end

And the module would be defined as something similar to:

module SelfDiagnose
  def tasks
    yield if block_given?
  end
  def check_database_connection(db_name)
    # create a new CheckDatabaseConnection task and register it for running
  end
  def check_log_writeable(log_name)
    # create a new CheckLogWriteable task and register it for running
  end
end # module

Looking back at this approach, I don’t see the need for having a task registration in the Rails version of SelfDiagnose. I might as well implement the controller like this:

class SelfdiagnoseController < ActionController
  include SelfDiagnose

  def index
      check_database_connection 'mysql'
      check_directory_readable '/path/to/dir'
      check_log_writeable 'production.log'
      check_url_accessable 'http://s3browse.com'
  end
end

Then, the index.html.erb will put together a nice report of the results.

Blog at WordPress.com.