<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-5411139659011156551</id><updated>2012-01-10T03:05:38.761-08:00</updated><category term='puppet'/><category term='bittorrent'/><category term='SML'/><category term='test'/><category term='dart'/><category term='sysadmin'/><category term='zeromq'/><category term='erlang'/><category term='debugging'/><category term='theorem proving'/><category term='haskell'/><category term='event tracing'/><category term='code'/><category term='parsing'/><category term='benchmarks'/><category term='programming languages'/><category term='twelf'/><category term='tracing'/><category term='concurrency'/><category term='MLton'/><category term='rant'/><category term='language design'/><title type='text'>JLOUIS Ramblings</title><subtitle type='html'>Musings of a mathematically oriented Computer Scientist. Anything that tickles my brain might go in here, be it Computer Science, mathematics, society, relationships, sex, 0xf00d, pets, leashes and secretaries.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>70</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-2016684057050663365</id><published>2011-12-30T10:00:00.001-08:00</published><updated>2011-12-30T12:40:05.939-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><category scheme='http://www.blogger.com/atom/ns#' term='code'/><category scheme='http://www.blogger.com/atom/ns#' term='programming languages'/><category scheme='http://www.blogger.com/atom/ns#' term='language design'/><category scheme='http://www.blogger.com/atom/ns#' term='concurrency'/><title type='text'>On Abstraction in Erlang</title><content type='html'>Programs of a certain size are complex. As long as the program is written by a single programmer and is fairly small, say under 1000 lines of code, then everything is easy. The programmer can keep the whole program in the head and it is easy to do stuff with that program. If on the other hand the program grows in size or we add more programmers, then we can't rely on the singular knowledge of a programmer.&lt;br /&gt;
&lt;br /&gt;
The only way to solve this problem is to build in abstractions in your programs. We will review two such methods in Erlang. The idea of abstraction, informally, is that we will hide certain details and only provide a clean interface through which to manipulate stuff. Erlang is a "Mutually Consenting Adult Language" (read: dynamically typed with full term introspection - or more violently - unityped crap with everything in one big union type). So this abstraction is not possible in reality. On the other hand, the dialyzer can provide us with much of the necessary tooling for abstraction.&lt;br /&gt;
&lt;br /&gt;
As an example of so-called modular abstraction, let us consider a small toy module:&lt;br /&gt;
&lt;pre&gt;&lt;code&gt; -module(myq).

 -export([push/2,
          empty/0,
          pop/1]).
 -type t() :: {fifo, [integer()], [integer()]}.
 -export_type([t/0]).

 -spec empty() -&amp;gt; t().
 -spec push(integer(), t()) -&amp;gt; t().
 -spec pop(t())     -&amp;gt; 'empty' | {'value', integer(), t()}.&lt;/code&gt;&lt;/pre&gt;
These are the definitions and specs of the module we are implementing. We are writing a simple queue module for a FIFO queue, based on two lists that are kept back-to-back. I am using a Standard ML / Ocaml trick here by calling the canonical type it operates on for 't'. The operations &lt;em&gt;push/2&lt;/em&gt; and &lt;em&gt;pop/1&lt;/em&gt; are used to push and pop elements to and from the queue respectively. Note we are prefixing queues by the atom 'fifo' to discriminate them from other tuples. The implementation of the queue is equally simple:&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt; empty() -&amp;gt; {fifo, [], []}.

 push(E, {fifo, Front, Back}) -&amp;gt; {fifo, Front, [E | Back]}.

 pop({fifo, [E | N], Back}) -&amp;gt; {value, E, {fifo, N, Back}};
 pop({fifo, [], []})        -&amp;gt; empty;
 pop({fifo, [], Back})      -&amp;gt; pop({fifo, lists:reverse(Back), []}).
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
We always push to the back list and always pop from the front list. If the front list ever becomes empty, we reverse the back list to the front. Not used persistently, this queue has amortized O(1) run-time and is as such pretty fast.&lt;br /&gt;
&lt;br /&gt;
The neat thing is that all operations are local to the myq module when you want to operate on queues. This abstracts away details about queues when you are using them via this module. There can much code inside such a module which is never exposed to the outside and thus we have an easier time managing the program.&lt;br /&gt;
&lt;br /&gt;
There is a problem with this though, which is that the implementation of the queue is &lt;em&gt;transparent&lt;/em&gt;. A user of the myq module can, when handed a queue, Q, of type myq:t() we can discriminate on it like this user:&lt;br /&gt;
&lt;pre&gt;&lt;code&gt; -module(u).

 -compile(export_all).

 -spec f(myq:t()) -&amp;gt; myq:t().
 f(Q) -&amp;gt;
     case Q of
         {fifo, [], []} -&amp;gt;
             myq:push(7, Q);
         _Otherwise -&amp;gt;
             Q
     end.&lt;/code&gt;&lt;/pre&gt;
Note how we match on the queue and manipulate it. This is &lt;em&gt;bad&lt;/em&gt; practice! If the myq module defined the representation of the queue it ought to be the &lt;em&gt;only&lt;/em&gt; module that manipulate the internal representation of a queue. Otherwise we might lose the modularity since the representation has bled all over the place. Now, since Erlang is for mutually consenting adults, you need to make sure this data structural representation leak doesn't happen yourself. It is &lt;em&gt;especially&lt;/em&gt; important with records. If you want modular code, avoid putting records in included header files if possible unless you are &lt;em&gt;dead sure&lt;/em&gt; the representation won't change all of a sudden. Otherwise the record will bleed all over your code and make it harder to change stuff later on. Also changes are not module-local but in several modules. This hurts the reusability of code.&lt;br /&gt;
&lt;br /&gt;
However, the dialyzer has a neat trick! If we instead of&lt;br /&gt;
&lt;pre&gt;&lt;code&gt; -type t() :: {fifo, [integer()], [integer()]}.&lt;/code&gt;&lt;/pre&gt;
had defined the type as &lt;em&gt;opaque&lt;/em&gt;&lt;br /&gt;
&lt;pre&gt;&lt;code&gt; -opaque t() :: {fifo, [integer()], [integer()]}.&lt;/code&gt;&lt;/pre&gt;
Then the dialyzer will report the following when run on the code:&lt;br /&gt;
&lt;pre&gt;&lt;code&gt; u.erl:9: The call myq:push(7,Q::{'fifo',[],[]}) does not have an
      opaque term of type myq:t() as 2nd argument&lt;/code&gt;&lt;/pre&gt;
which is a warning that we are breaking the opaqueness abstraction of the myq:t() type.&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;The Other kind of abstraction in Erlang&lt;/span&gt;&lt;br /&gt;
Languages like Haskell or ML has these kind of tricks up their sleeve in the type system. You can enforce a type to be opaque and get type errors if a user tries to dig into the structure of the representation.  Since the dialyzer came later in Erlang one might wonder why one could write programs larger than a million lines of code in Erlang and get away with it when there was no enforcement of opaqueness. The answer is subtle and peculiar. Part of the answer is naturally the functional heritage of Erlang. Functional languages tend to have excellent reusability properties because the task of handling &lt;i&gt;state &lt;/i&gt;is diminished. Also, functional code tend to be easier to maintain since it is much more data-flow oriented than control-flow oriented. But&amp;nbsp;Erlang has another kind of abstraction which is pretty unique to it, namely that of a process:&lt;br /&gt;
&lt;br /&gt;
If I create a process, then its internal state is not observable from the outside. The only thing I can do is to communicate with the process by protocol: I can send it a message and I can await messages from it. This makes the process &lt;em&gt;abstract&lt;/em&gt; when viewed from the outside. The internal representation is not visible and you could completely substitute the proces for another one without the caller knowing.  In Erlang this principle of process isolation is &lt;em&gt;key&lt;/em&gt; to the abstractional facilities. &lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;What does this mean really?&lt;/span&gt;&lt;br /&gt;
Erlang has not one, but two kinds of ways to handle large applications: You can use modules, exports of types and opaqueness constraints to hide representations. While you &lt;em&gt;can&lt;/em&gt; break the abstraction, the dialyzer will warn you when you are doing so. This is a compile-time and program-code abstractional facility. Orthogonally to this, a process is a runtime isolation abstraction. It enforces a given protocol at run time which you must abide. It can hide the internal representation of a process. It provides an abstractional facility as well. It is also the base of fault tolerance. If a process dies, only its internal state can be directly affected. Other processes not logically bound to it can still run. It is my hunch that these two tools together is invaluable when it comes to building large Erlang programs, several hundred thousand lines of code - and get away with it!&lt;br /&gt;
&lt;br /&gt;
So in conclusion: To create modular code-level functional abstractions, rely on the dialyzer to create them for you like in the queue example from above. To create a modular runtime, split your program into processes, where each process handles a concurrent task. &lt;br /&gt;
&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-2016684057050663365?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/2016684057050663365/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=2016684057050663365' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/2016684057050663365'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/2016684057050663365'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2011/12/on-abstraction-in-erlang.html' title='On Abstraction in Erlang'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-3930920031770070410</id><published>2011-12-18T11:39:00.001-08:00</published><updated>2011-12-18T13:54:03.067-08:00</updated><title type='text'>An example of Property Based Testing in Erlang</title><content type='html'>&lt;h2&gt;Introduction&lt;/h2&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;The unit test is the lowest common denominator. We can use them, but they are cumbersome and they only peek once into the fabric of our work. A better solution for many tasks, namely Property Based Testing exists for Erlang. This post is an example of how to use the &lt;code&gt;statem&lt;/code&gt; type of test, mainly because there are so few of these out there. The outset is this: We will randomly generate operations on a priority queue and then validate that these operations are correct according to a simpler model.&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;The setup was that Michael Truog had a nice library of (min) priority queues which he had written (see &lt;a href="https://github.com/okeuday/pqueue"&gt;okeuday/pqueue&lt;/a&gt;) He was mostly interested in how they benchmarked, but before benchmarking, you need to have some kind of knowledge that your PrioQ is correct indeed. Otherwise, you may just return the value &lt;code&gt;42&lt;/code&gt; on each output and claim that this is the "right" thing to do. So the system under test (the SUT) is the various priority queue implementations by Michael. In order to test them, we need a &lt;em&gt;model&lt;/em&gt; of a priority queue though.&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;The model of a SUT is some code we write which can reflect the observations of the SUT. In the case of a priority queue, there is a very simple model we can choose. We can simply base it upon a naive priority queue. The idea is then, that our PrioQ is easy to write but it may not be particularly fast. If an error shows up, it means that the SUT and our model will disagree (hopefully) and we can figure out if the problem is with our Model or the SUT.&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;We are going to use PropEr. The choice could equally well have been Erlang QuickCheck though, with minor changes. Both tools reflect the same interface for this kind of work, even though their real working might be slightly different in practice.&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; All code is in Michaels repository linked above. If you want to digest the code yourself, go read it there - after having read this blog post. I've pulled out the important parts, but eh real repo has a bit more code in it.&lt;/p&gt;&lt;h2&gt;Building the model&lt;/h2&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;The model in this case is fairly simple. When constructing the model you need to have an idea of what you are going to test for. The goal is to get the model as &lt;em&gt;small&lt;/em&gt; as possible while still being able to handle everything you may need. On the other end of the spectrum, you build up a model that is a complete specification - which can in some cases actually mean your model will be larger than the SUT. But in this case the model is way smaller and simpler than the queue it tests.&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;For this particular example though, we are very lucky. Essentially our example is a complex implementation (implementations) of a simple idea. So our model goes for reflecting the simple idea instead.&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;Let us write a priority queue to serve as the model. Our representation is &lt;code&gt;[{priority(), [element()]}]&lt;/code&gt; that is a list of tuple-pairs where the firstelement is a priority and the second element is the list of values we are storing under that priority. We require that the list is &lt;em&gt;sorted&lt;/em&gt; by the priorities. This makes lookup a bit faster.&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;Insertion is awfully simple. Just skip until we hit the right spot and inject the value:&lt;/p&gt;&lt;pre&gt;
&lt;code&gt;%% A listq is a sorted list of priorities
listq_insert({P, V}, []) -&amp;gt; [{P, [V]}];
listq_insert({P, V}, [{P1, _} | _] = LQ) when P &amp;lt; P1 -&amp;gt;
    [{P, [V]} | LQ];
listq_insert({P, V}, [{P1, Vs} | Next]) when P == P1 -&amp;gt;
    [{P, Vs ++ [V]} | Next];
listq_insert({P, V}, [{P1, Vs} | Next]) when P &amp;gt; P1 -&amp;gt;
     [{P1, Vs} | listq_insert({P, V}, Next)].
&lt;/code&gt;
&lt;/pre&gt;&lt;p&gt;Note that if we get a hit on the priority, we just add the next value in the back. This is slow, but we don't care since we only need the model to carry out tests. Now, converting a prioq to a list is easy. So is taking the length of a priority queue in the model:&lt;/p&gt;&lt;pre&gt;
&lt;code&gt;listq_to_list(L) -&amp;gt;
    lists:concat(
      [ Vals || {_Prio, Vals} &amp;lt;- L]).

listq_length(L) -&amp;gt;
    lists:sum(
      [ length(Vs) || {_Prio, Vs} &amp;lt;- L]).
&lt;/code&gt;
&lt;/pre&gt;&lt;p&gt;There! Michael have two ways to remove elements from a priority queue. The first is the common solution where you remove the next element. Note that if the queue is empty then the result is an empty queue. Also note, we don't return the removed element. This semantics seem a little odd to me, but on the other hand, it is better to make the model reflect the expected behavior here:&lt;/p&gt;&lt;pre&gt;
&lt;code&gt;listq_rem([]) -&amp;gt; [];
listq_rem([{_P, [_V]} | Next]) -&amp;gt; Next;
listq_rem([{P, [_V1 | Vs]} | Next]) -&amp;gt; [{P, Vs} | Next].
&lt;/code&gt;
&lt;/pre&gt;&lt;p&gt;Michael also have a variant where we remove an element of a given priority. We can simply dig through the list until we find the desired priority and then remove an element from that one. If there are no more elements left of that priority, we kill the pair:&lt;/p&gt;&lt;pre&gt;
&lt;code&gt;listq_rem([], _P) -&amp;gt; [];
listq_rem([{P, [_]} | Next], P) -&amp;gt; Next;
listq_rem([{P, [_ | Vs]} | Next], P) -&amp;gt; [{P, Vs} | Next];
listq_rem([{P1, Vs} | Next], P) -&amp;gt; [{P1, Vs} | listq_rem(Next, P)].
&lt;/code&gt;
&lt;/pre&gt;&lt;p&gt;Finally, we need to be able to peek into the queue. There are three variants. We can peek for the minimal element. We can peek for the element with a given priority, or we can peek for an element but also obtain its priority in question:&lt;/p&gt;&lt;pre&gt;
&lt;code&gt;listq_peek([]) -&amp;gt; empty;
listq_peek([{_P, [V | _]} | _]) -&amp;gt; {value, V}.

listq_prio_peek([{P, [V | _]} | _], P) -&amp;gt; {value, V};
listq_prio_peek([{_P1, _} | Next], P) -&amp;gt; listq_prio_peek(Next, P);
listq_prio_peek([], _P) -&amp;gt; empty.

listq_ppeek([]) -&amp;gt; empty;
listq_ppeek([{P, [V | _]} | _]) -&amp;gt; {value, V, P}.
&lt;/code&gt;
&lt;/pre&gt;&lt;h2&gt;Making a gen_server to drive the SUT.&lt;/h2&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;Strictly speaking, this example does not need a &lt;code&gt;proper&lt;em&gt;statem&lt;/em&gt;&lt;/code&gt;&lt;em&gt; test. You could just build up the priority queue by using valid operations and then make tests. But to illustrate the use of &lt;code&gt;statem&lt;/code&gt; we have built a simple driver for a priority queue. This code is in &lt;a href="https://github.com/okeuday/pqueue/blob/master/src/queue_srv.erl"&gt;okeuday/pqueue/src/queue&lt;/a&gt;&lt;/em&gt;&lt;a href="https://github.com/okeuday/pqueue/blob/master/src/queue_srv.erl"&gt;srv.erl&lt;/a&gt; and it is not that interesting. We just have a separate process which keeps track of the internal state of the priority queue for us. This means, that we can only observe the &lt;code&gt;queue_srv&lt;/code&gt; by means of what we prod it to do and what it answers with.&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;You can have a look at the code, but it is not that interesting. It merely reflects what operations are allowed on a priority queue.&lt;/p&gt;&lt;h2&gt;Introducing the StateM behaviour&lt;/h2&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;We need a bit of work in order to support the &lt;code&gt;proper_statem&lt;/code&gt; behaviour:&lt;/p&gt;&lt;pre&gt;
&lt;code&gt;-module(pqueue_proper).
-include_lib("proper/include/proper.hrl").
-behaviour(proper_statem).

-export([command/1, initial_state/0, next_state/3, postcondition/3,
    precondition/2]).
&lt;/code&gt;
&lt;/pre&gt;&lt;p&gt;The next part is somewhat wrong, from a type perspective. I should probably change it. The state is tracked far too broadly here, but the code will still function properly.&lt;/p&gt;&lt;pre&gt;
&lt;code&gt;-type value() :: integer().
-record(state, { in_queue :: [{value(), term()}] }).
-define(SERVER, queue_srv).
&lt;/code&gt;
&lt;/pre&gt;&lt;p&gt;Now we are at the point where we need to handle the given callbacks from &lt;code&gt;proper_statem&lt;/code&gt;. The first one we will be attacking is the &lt;code&gt;command/1&lt;/code&gt; which states what commands are eligible for firing. But before doing that, we need some helpers:&lt;/p&gt;&lt;pre&gt;
&lt;code&gt;priority() -&amp;gt; integer(-20, 20).
value() -&amp;gt; integer().
&lt;/code&gt;
&lt;/pre&gt;&lt;p&gt;This is a generator of priorities and one of values. Michael decided that priorities should be in the range -20 to 20, so we reflect that in our generator. The values are always integers, but they have no bound on the other hand.&lt;/p&gt;&lt;pre&gt;
&lt;code&gt;priority(InQ) -&amp;gt; elements([P || {P, _} &amp;lt;- InQ]).
&lt;/code&gt;
&lt;/pre&gt;&lt;p&gt;Given a queue, we extract all the priorities from that queue. And then we use &lt;code&gt;elements&lt;/code&gt; to select one at random. This is a generator of &lt;em&gt;existing&lt;/em&gt; priorites that are already in the queue. Then there is the initial state of the system, which is the empty priority queue:&lt;/p&gt;&lt;pre&gt;
&lt;code&gt;initial_state() -&amp;gt; #state { in_queue = [] }.
&lt;/code&gt;
&lt;/pre&gt;&lt;h2&gt;Commands&lt;/h2&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;Now we are ready to define the command function. It is keyed by the current state, so we can take that into consideration as well. It may be that the current state limits what commands are eligible for firing.&lt;/p&gt;&lt;pre&gt;
&lt;code&gt;command(#state { in_queue = InQ }) -&amp;gt;
    oneof([{call, ?SERVER, in, [value()]},
           {call, ?SERVER, in, [value(), priority()]},
           {call, ?SERVER, is_empty, []},
           {call, ?SERVER, is_queue, []},
           {call, ?SERVER, len, []},
           {call, ?SERVER, out, []}] ++
          [{call, ?SERVER, out, [priority(InQ)]} || InQ =/= []] ++
          [{call, ?SERVER, pout, []},
          {call, ?SERVER, to_list, []}]).
&lt;/code&gt;
&lt;/pre&gt;&lt;p&gt;We generate &lt;em&gt;calls&lt;/em&gt; to &lt;code&gt;?SERVER&lt;/code&gt; which is our &lt;code&gt;queue&lt;em&gt;srv&lt;/em&gt;&lt;/code&gt;&lt;em&gt; gen&lt;/em&gt;server construction. We use the already given generators to generate random values and priorities where applicable. Note the trick &lt;code&gt;[priority(InQ) || InQ =/= []]&lt;/code&gt; which is a degenerate list comprehension. The list is &lt;code&gt;[]&lt;/code&gt; if InQ is empty. Otherwise it uses the &lt;code&gt;priority/1&lt;/code&gt; function from above to pick a random priority to remove &lt;em&gt;among those already in the queue&lt;/em&gt;.&lt;/p&gt;&lt;h2&gt;Updating our model&lt;/h2&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;Now, assume we have run an operation on the SUT with the &lt;code&gt;command/1&lt;/code&gt; callback. Then our model needs to be updated with the same value as well. Otherwise we could not check for correctness. The function &lt;code&gt;next_state(State, Ret, Call)&lt;/code&gt; reflects this change. The three parameters taken are the current State of the model, the return value of the operation we invoked, and &lt;em&gt;Call&lt;/em&gt; describes the command we executed.&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; There is one very important thing with the &lt;code&gt;next_state/3&lt;/code&gt; function. It is used twice internally in PropEr/QuickCheck. First it is used in an &lt;em&gt;abstract&lt;/em&gt; mode where all values are symbolic in nature. That is you can not rely on a return value being a "real" value. Rather you must only transfer values around without discriminating on them. Secondly, the function is used &lt;em&gt;concretely&lt;/em&gt; when you are running the test cases. The notion used is &lt;em&gt;symbolic&lt;/em&gt; and &lt;em&gt;dynamic&lt;/em&gt; respectively. Just keep this in mind when you write your own tests. Since you may be executing this with symbolic values, it is limited how you can discriminate values as they may be symbolic in nature.&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;Here is the first clause:&lt;/p&gt;&lt;pre&gt;
&lt;code&gt;next_state(#state { in_queue = InQ } = S, _V, {call, _, out, []}) -&amp;gt;
    S#state { in_queue = listq_rem(InQ) };
&lt;/code&gt;
&lt;/pre&gt;&lt;p&gt;This means we had a call to &lt;code&gt;out/0&lt;/code&gt; on the queue and we should remove an element from the queue. We can then call our own &lt;code&gt;listq_rem/1&lt;/code&gt; function to track this operation in our own model state. Note also that some of the clauses are not going to update the state since the calls generated does not alter the state. Also note that we sometimes look inside the call to figure out what values were generated as input so we can transition our model state accordingly:&lt;/p&gt;&lt;pre&gt;
&lt;code&gt;next_state(#state { in_queue = InQ } = S, _V, {call, _, out, [Prio]}) -&amp;gt;
    S#state { in_queue = listq_rem(InQ, Prio) };
next_state(#state { in_queue = InQ } = S, _V, {call, _, pout, _}) -&amp;gt;
    S#state { in_queue = listq_rem(InQ) };
next_state(S, _V, {call, _, to_list, _}) -&amp;gt; S;
next_state(S, _V, {call, _, is_queue, _}) -&amp;gt; S;
next_state(S, _V, {call, _, is_empty, _}) -&amp;gt; S;
next_state(S, _V, {call, _, len, _}) -&amp;gt; S;
next_state(#state { in_queue = InQ } = S, _V,
               {call, _, in, [Value, Prio]}) -&amp;gt;
    S#state { in_queue = listq_insert({Prio, Value}, InQ) };
next_state(#state { in_queue = InQ } = S, _V,
              {call, _, in, [Value]}) -&amp;gt;
    S#state { in_queue = listq_insert({0, Value}, InQ) }.
&lt;/code&gt;
&lt;/pre&gt;&lt;h2&gt;Preconditions&lt;/h2&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;This example does not use preconditions:&lt;/p&gt;&lt;p&gt;precondition(_S, _Call) -&amp;gt; true&lt;/p&gt;&lt;p&gt;Normally you use preconditions to limit what calls can be done in what state. That is, if the precondition fails, then the given transition is not allowed. One can use this as a constraining measure in some tests. But for this example, everything can always fire, so there is no reason to limit the calls in any way.&lt;/p&gt;&lt;h2&gt;Postconditions&lt;/h2&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;The &lt;em&gt;postcondition&lt;/em&gt; is where we check that the model and SUT agrees on the observations. This is not executed symbolically, but is entirely dynamic execution. Here is the first clause:&lt;/p&gt;&lt;pre&gt;
&lt;code&gt;postcondition(#state { in_queue = InQ }, {call, _, out, [Prio]}, R) -&amp;gt;
    R == listq_prio_peek(InQ, Prio);
&lt;/code&gt;
&lt;/pre&gt;&lt;p&gt;it states: If we have a current state, &lt;code&gt;InQ&lt;/code&gt; and a call to &lt;code&gt;out&lt;/code&gt; with a specific priority, &lt;code&gt;Prio&lt;/code&gt; and the SUT returned the value R. Then peeking in &lt;code&gt;InQ&lt;/code&gt; for the first element at that given priority should be the same element. After this test, the state transition with &lt;code&gt;next_state/3&lt;/code&gt; will happen. Equally:&lt;/p&gt;&lt;pre&gt;
&lt;code&gt;postcondition(#state { in_queue = InQ }, {call, _, pout, _}, R) -&amp;gt;
    R == listq_ppeek(InQ);
postcondition(#state { in_queue = InQ }, {call, _, out, _}, R) -&amp;gt;
    R == listq_peek(InQ);
&lt;/code&gt;
&lt;/pre&gt;&lt;p&gt;handles the remaining checks for removing elements from the priority queue. Converting to a list or taking the length can also be done by calling our model variants and looking for equality:&lt;/p&gt;&lt;pre&gt;
&lt;code&gt;postcondition(S, {call, _, to_list, _}, R) -&amp;gt;
    R == listq_to_list(S#state.in_queue);
postcondition(S, {call, _, len, _}, L) -&amp;gt;
    L == listq_length(S#state.in_queue);
&lt;/code&gt;
&lt;/pre&gt;&lt;p&gt;Finally, one can ask if we have a queue, which should always be &lt;code&gt;true&lt;/code&gt; - and we could ask if the queue is currently empty, which we can determine by discriminating on our model state. In this case they should also agree. Inserting elements into a queue always succeeds in addition:&lt;/p&gt;&lt;pre&gt;
&lt;code&gt;postcondition(_S, {call, _, is_queue, _}, true) -&amp;gt; true;
postcondition(S, {call, _, is_empty, _}, Res) -&amp;gt;
    Res == (S#state.in_queue == []);
postcondition(_S, {call, _, in, _}, _) -&amp;gt;
    true;
&lt;/code&gt;
&lt;/pre&gt;&lt;p&gt;All other outcomes are errors:&lt;/p&gt;&lt;pre&gt;
&lt;code&gt;postcondition(_, _, _) -&amp;gt;
    false.
&lt;/code&gt;
&lt;/pre&gt;&lt;h2&gt;Running the test&lt;/h2&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;Now, running this property test is the following property:&lt;/p&gt;&lt;pre&gt;
&lt;code&gt;correct(M) -&amp;gt;
   ?FORALL(Cmds, commands(?MODULE),
      ?TRAPEXIT(
        begin
           ?SERVER:start_link(M),
               {History,State,Result} = run_commands(?MODULE, Cmds),
               ?SERVER:stop(),
               ?WHENFAIL(
                 io:format("History: ~w\nState: ~w\nResult: ~w\n",
                               [History,State,Result]),
                               aggregate(
                                command_names(Cmds),
                                Result =:= ok))
                end)).
&lt;/code&gt;
&lt;/pre&gt;&lt;p&gt;Where &lt;code&gt;M&lt;/code&gt; describes the module we wish to test. Michael wrote several and we can test them all with the same code! Then we start a &lt;code&gt;queue_srv&lt;/code&gt; with &lt;code&gt;M&lt;/code&gt; as the module and then we run a series of commands. The server is then stopped. Then, upon failure, we output necessary stuff to figure out what went wrong. Also, we aggregate how often the commands are hti so we are sure we have a decent coverage.&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;The test uncovered some errors straight away. Here is one such which was much much bigger but got minimized down by PropEr:&lt;/p&gt;&lt;pre&gt;
&lt;code&gt;[{set,{var,1},{call,queue_srv,in,[-18]}},
 {set,{var,5},{call,queue_srv,in,[9]}},
 {set,{var,6},{call,queue_srv,in,[-10,-4]}},
 {set,{var,18},{call,queue_srv,in,[-29]}},
 {set,{var,22},{call,queue_srv,in,[11]}},
 {set,{var,26},{call,queue_srv,len,[]}}]
&lt;/code&gt;
&lt;/pre&gt;&lt;p&gt;So, if you insert [-18, 9, -4 at priority -10, -29, 11] and then ask for the length of the priority queue, something failed (the pqueue code crashed).&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;The point here is that normal unit tests won't usually come up with examples this complex. But by starting out asking: "What &lt;em&gt;can&lt;/em&gt; be done here?" by means of generators and then carrying out random operations uncovers nasty errors quickly. Michaels code now routinely survives 1500 PropEr test runs on all his priority queue modules. Given that it took 1-2 hours writing the test, it seems like it was worth it.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-3930920031770070410?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/3930920031770070410/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=3930920031770070410' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/3930920031770070410'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/3930920031770070410'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2011/12/example-of-property-based-testing-in.html' title='An example of Property Based Testing in Erlang'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-1765086747678815384</id><published>2011-10-23T09:00:00.000-07:00</published><updated>2011-10-23T09:01:48.799-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='event tracing'/><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><category scheme='http://www.blogger.com/atom/ns#' term='tracing'/><category scheme='http://www.blogger.com/atom/ns#' term='test'/><category scheme='http://www.blogger.com/atom/ns#' term='debugging'/><title type='text'>Using the Event Tracer tool set in Erlang</title><content type='html'>A common problem in concurrent systems is the following: events fire from all places all the time and you have no direct control over when and why events fire. Thus, to figure out problems one can often make use of a sequence diagram like this one (thanks Wikipedia):&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://upload.wikimedia.org/wikipedia/commons/2/20/Restaurant-UML-SEQ.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://upload.wikimedia.org/wikipedia/commons/2/20/Restaurant-UML-SEQ.gif" width="315" /&gt;&lt;/a&gt;&lt;/div&gt;
The purpose of such a diagram is to show the interactions between different concurrent parties. In this case, Fred, Bob, Hank and Renee - in a restaurant. One can easily draw such diagrams on paper. But the problem with such a drawing is that it is disconnected from the machine. What the drawing shows may or may not be what the program actually does.&lt;br /&gt;
&lt;br /&gt;
Wouldn't it be neat if you could make such diagrams by tracing what the code does and then build up the diagram in a&amp;nbsp;programmatic way? Well, with Erlang, you can. I'll use some code I wrote as an example for how to do it.&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Step 1: Build a tracer function&lt;/span&gt;&lt;br /&gt;
The first step is to construct a tracer function. Mine look like the following and resides in a module &lt;span style="font-family: inherit;"&gt;called "utp".&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;report_event(DetailLevel, FromTo, Label, Contents) -&amp;gt;
    %% N.B External call
    ?MODULE:report_event(DetailLevel, FromTo, FromTo, Label, Contents).

report_event(_DetailLevel, _From, _To, _Label, _Contents) -&amp;gt;
    hopefully_traced.
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;
&lt;/code&gt;&lt;/pre&gt;
The basic idea is found in the latter of these two definitions. It defines a dummy-function taking 5 arguments which are thrown away promptly. The return value "hopefully_traced" is arbitrary, but it signifies what we want out of this function. The first variant, is used when it is the same party that does both things.&lt;br /&gt;
&lt;br /&gt;
The arguments are as follows:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;DetailLevel: A number between 0 and 100. It signifies the level of detail for this event. We can use it to give major events low level and more detailed event at a finer grained scale higher levels. The event tracer can cut off events based on this value so we get the desired graininess.&lt;/li&gt;
&lt;li&gt;From: The party from which the event originates.&lt;/li&gt;
&lt;li&gt;To: The party to which the event is sent.&lt;/li&gt;
&lt;li&gt;Label: The notational label to put on the message.&lt;/li&gt;
&lt;li&gt;Contents: If you click on the event, we will show this term to the user. It can be used to pack up more detailed information to present, while avoiding cluttering up the diagram.&lt;/li&gt;
&lt;/ul&gt;
&lt;span style="font-size: large;"&gt;Step 2: Trace the events in the program&lt;/span&gt;&lt;br /&gt;
Whenever something important in the program happens, you add a call to "utp:report_event/5" or whatever the designation for your tracing function is. This will be default do nothing, but it allows us to hook that function later with Erlangs tracing facilities. As an example, here is the interaction from above:&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;trace_test() -&amp;gt;
    Events = [{fred, bob, order_food},
              {bob, hank, order_food},
              {bob, fred, serve_wine},
              {hank, bob, pickup},
              {bob, fred, serve_feed},
              {fred, renee, pay}],
    [utp:report_event(50, F, T, L, [])
     || {F,T,L} &amp;lt;- Events].
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;
&lt;/code&gt;&lt;/pre&gt;
But note that anything can be reported really, by spreading the event reporting function out over your code base. Rather than run scores of debug statements, you can add a reporter at the point in the code. Also note I have condensed it a bit in the above example with a list comprehension because I don't care for the detail level and the contents.&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Step 3: Introduce code to invoke the et application&lt;/span&gt;&lt;br /&gt;
Next, we need to invoke Erlangs et application in the right way. I have a module, called "utp_filter" which does it, even though it still doesn't contain any filter function. Here is the code of interest:&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;start(ExtraOptions) -&amp;gt;
    Options =
        [{event_order, event_ts},
         {scale, 2},
         {max_actors, 10},
         {detail_level, 90},
         {actors, [fred, bob, hank, renee]},
         {trace_pattern, {utp, max}},
         {trace_global, true},
         {title, "uTP tracer"} | ExtraOptions],
    et_viewer:start(Options).
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;
&lt;/code&gt;&lt;/pre&gt;
What this code does is to initalize the et_viewer in a way such that it can be used with our example. The event order is event_ts which means we are timestamping events at when they fire and not when they are received. The actors define the order in which the actors appear. The trace_pattern is pretty important. It is what makes us hook to the "utp:report_event/5" call. You can give a lot of options to this or event produce such patterns yourself. But just name the module in which your trace function is placed will work.&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Step 4: Test&lt;/span&gt;&lt;br /&gt;
If we invoke "utp_filter:start([])" which starts up the et viewer by executing the code in step 3, we can then invoke the trace test code from step 2 to obtain:&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/-UUYkdPGEEsY/TqQ3iJjOjKI/AAAAAAAAARQ/9NxkrZf8Mes/s1600/Screenshot+at+2011-10-23+17%253A47%253A57.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="311" src="http://1.bp.blogspot.com/-UUYkdPGEEsY/TqQ3iJjOjKI/AAAAAAAAARQ/9NxkrZf8Mes/s400/Screenshot+at+2011-10-23+17%253A47%253A57.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Which should reflect the example from Wikipedia, but now obtained by executing a program in Erlang. This idea has been used by me to capture and find bugs in TCP-stack variants, in particular uTP:&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;a href="http://1.bp.blogspot.com/-ejD5oeV0-0Y/TqQ4INwx0lI/AAAAAAAAARY/YqTKwgbmrzE/s1600/Screenshot-uTP+tracer+%2528filter%253A+all%2529-2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="400" src="http://1.bp.blogspot.com/-ejD5oeV0-0Y/TqQ4INwx0lI/AAAAAAAAARY/YqTKwgbmrzE/s400/Screenshot-uTP+tracer+%2528filter%253A+all%2529-2.png" width="382" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: left;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: left;"&gt;
(Even if these diagrams are small, the basic idea should be in there - it is not about the diagrams, but about the steps to obtain the glory yourself :). For a TCP stack-like protocol it is very powerful: You have a tcpdump(1) output, an strace(1) output, as well as the internal protocol state in the same diagram. I found quite some bugs with these tools in my code, simply by inspecting the interaction of the programs.&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: left;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: left;"&gt;
And thats it. With the above code in your application, you can enable a graphical trace viewer on your code at any time. If you don't enable it, the overhead of the trace functions are negligible - unless you have a very hot critical path indeed. If you do enable it, you can see exactly what your code does in the given situation.&lt;/div&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-1765086747678815384?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/1765086747678815384/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=1765086747678815384' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/1765086747678815384'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/1765086747678815384'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2011/10/using-event-tracer-tool-set-in-erlang.html' title='Using the Event Tracer tool set in Erlang'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-UUYkdPGEEsY/TqQ3iJjOjKI/AAAAAAAAARQ/9NxkrZf8Mes/s72-c/Screenshot+at+2011-10-23+17%253A47%253A57.png' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-4670047024813708084</id><published>2011-10-10T07:03:00.000-07:00</published><updated>2011-10-10T07:04:15.504-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rant'/><category scheme='http://www.blogger.com/atom/ns#' term='dart'/><category scheme='http://www.blogger.com/atom/ns#' term='programming languages'/><category scheme='http://www.blogger.com/atom/ns#' term='language design'/><category scheme='http://www.blogger.com/atom/ns#' term='concurrency'/><title type='text'>Musings on Dart</title><content type='html'>&lt;br /&gt;
Now the Dart language is out at &lt;a href="http://dartlang.org/"&gt;http://dartlang.org&lt;/a&gt;, we can begin looking at the language and see what we think of it. Everything here are musings from reading the spec of the Dart language. Note that my points here are quite subjective at times. Don't expect this to be an objective run down of the language. Rather, I wanted to write down what I thought about the language just by looking at the specification alone.&lt;br /&gt;
&lt;br /&gt;
Starting out, we generally won't focus on the syntax of the language. The syntax is boring, tedious and just there. It is Java/Javascript-like, mostly to interest the right kinds of people on the language. We note that the syntax is considerably shorter and leaner than the equivalent Java code and that there are notational&lt;br /&gt;
stuff going on to make certain things easier to write down in the programs.&lt;br /&gt;
&lt;br /&gt;
The major goal of Dart is to clean up Javascript and make design choices in the language which does not hamper raw execution speed. Javascript is not built for compilation into fast programs. There are simply too many nasty warts and design choices in the language which makes it very hard to compile. V8 is astoundingly good at it, but by altering the source language a little bit, you can squeeze out much more power with very little effort.&lt;br /&gt;
&lt;br /&gt;
I think that this is a goal of Dart which is central. Don't design yourself into a corner by language features.&lt;br /&gt;
&lt;br /&gt;
Dart is Single Threaded but support concurrency through an Actor-like concept of isolates. The choice of making the runtime single threaded is understandable. It is vastly simpler to write a compiler for a single threaded runtime than it is for a multi-threaded one. Also, the focus is perhaps on writing programs for web browsers and the amount of extra processing power to be had there from multiple processors is perhaps limited. Note that while the language specification says it is single threaded, the Isolate concept in the library talks about heavy isolates which are separate threads. One could imagine that the execution inside an isolated region is always single-threaded (Like in, Erlang for instance), but the system as a whole might have several isolates working simultaneously.&lt;br /&gt;
&lt;br /&gt;
On the other hand, even your modern mobile device goes multi-core. Thus, the choice is as much as a gamble as opting for a multi-core solution from day one. This choice is the conservative one.&lt;br /&gt;
&lt;br /&gt;
Dart makes it explicit that it has several kinds of errors and that these may come "lazily" on demand. The idea is to facilitate JIT-compilation, so an implementation is not required to report all errors up front. An understandable and interesting choice. For a programmer with the proactive view (Haskell, Java, Ocaml) on error &amp;nbsp;reporting, this sounds rather bad, but for a programmer with an reactive view (Erlang), it sounds quite familiar.&lt;br /&gt;
&lt;br /&gt;
Naturally, the language makes the almost ubiquitous billion dollar mistake of C.A.R Hoare: the language includes null as a default. Almost all non-functional languages do.&lt;br /&gt;
&lt;br /&gt;
An interesting choice is to enforce simplicity on static/final values. This is to ensure fast startup times, so a program can't hide a large computation in a global variable at startup.&lt;br /&gt;
&lt;br /&gt;
Amusingly, the language must make sure that every function returns 'null' in the case where the function has no return statement. This is funny because in functional languages, this kind of problem doesn't exist. a 'void' function can't be used in expression context in an imperative language, but since Dart type system is not enforcing, there are no guarantees. Hence a kludge is introduced.&lt;br /&gt;
&lt;br /&gt;
Functions are first class values with a simple notation for the equivalent of a lambda construction.&lt;br /&gt;
&lt;br /&gt;
The language has operator overloading, but as is common in imperative languages, you cannot define your own operator. Rather, you must use the operators that come with the language.&lt;br /&gt;
&lt;br /&gt;
Stealing ideas from other languages, there are convenience notation for getters and setters. On the other hand, there is no mention of lenses. The language is pretty much a standard OO-language with no mention of prototypical OO as in Javascript. This choice is probably smart since prototypical OO is irritating to compile.&lt;br /&gt;
&lt;br /&gt;
There is a built-in notion of factory construction, much like the notation of getters and setters. The idea is to allow a constructor to act as a factory under the hood so the callers don't need to get exposed to the fact that there is a factory. One could imagine this concept extended to other classic design patterns over time.&lt;br /&gt;
&lt;br /&gt;
The language is single-inheritance+interface+generics. Unlike Go, this language does support generics with upper bounds on the class hierarchy. In other words, the language has bounded quantification. And it even support F-bounded quantification on generics (also called recursively bounded quantification - you allow the class parameter T to occur in the bound as well: "T extends I(T)&lt;t&gt;", see wikipedia on &lt;a href="http://en.wikipedia.org/wiki/Bounded_quantification"&gt;bounded quantification&lt;/a&gt;).&lt;/t&gt;&lt;br /&gt;
&lt;br /&gt;
The language is pure. Everything is an object. You see that choice since null is the sole instance of class Null for example.&lt;br /&gt;
&lt;br /&gt;
Dart has true integers of unbounded size. There is no cramming everything into double values. There are no pesky size bounds to battle. In other words, Dart picked the innovative choice.&lt;br /&gt;
&lt;br /&gt;
I wonder... if a bool is an object, can I have a null bool?&lt;br /&gt;
&lt;br /&gt;
Strings are unicode. We got lists and maps in the language. We have a functional expression notation for fast notation of small simple function evaluation thingies. It is perhaps the easiest way to get some functional ideas into a language without making it not seem like Java.&lt;br /&gt;
&lt;br /&gt;
Note that a simple expression like '2 + 1' is internally compiled into a method invocation of the 2 objects + method with a parameter of 1.&lt;br /&gt;
&lt;br /&gt;
In a very controversial move the type system is unsound. Having an unsound type system means that the type system may allow for certain bugs to happen in production code. Time will show if this is a problem in practice. It may be you almost never hit the problem in practice and then this choice might end up being pretty sane. But if you can hit the unsoundness easily, this choice will end up being pretty bad.&lt;br /&gt;
&lt;br /&gt;
As in Java, constructing new types is had by making classes. To construct compound types, you need to use generics and parametrize the types as holes in the generic.&lt;br /&gt;
&lt;br /&gt;
&lt;hr /&gt;
&lt;br /&gt;
The most interesting part of the language, which is pretty conservative, is the choice of baking in both dynamic and static types into the same language. While the static type system is unsound, time will show if this unsoundness is troubling. C is also pretty bad type-wise, but that has not withheld people from writing software in it and using the type system to weed out bugs.&lt;br /&gt;
&lt;br /&gt;
The other interesting part is hidden in the library as a library extension and are called Isolates. An Isolate is, technically, an actor which processes by itself. There is a concept of message passing ports between actors so one can send and receive information. Naturally, futures also form part of this definition.&lt;br /&gt;
&lt;br /&gt;
&lt;hr /&gt;
&lt;br /&gt;
My primary critique of the language is that Dart provides nothing new to the table. It looks like a Java-for-the-web clone without providing something new. Granted, it may sway some Java programmers to move toward the Web in the long run. Granted, this is in the interest of Google because the reliance on Java is dangerous when Oracle controls it. As a language, Dart is considerably less innovative than Google Go. Rather it buys into existing ideas, and adds a gradual type system as the most innovative feature. I am not too worried about the unsoundness currently, but it is an inherent danger lurking until the static checker will warn about it.&lt;br /&gt;
&lt;br /&gt;
The secondary critique is the Isolate construction. First, there is a difference between a heavy and a light isolate. One provides a new thread of execution while the other provides an light-weight process in the current thread. There is no concept of migration so the programmer has to know beforehand how the program will run and execute to use isolates. It does provide pure isolation though, something not present in Go.&lt;br /&gt;
&lt;br /&gt;
There are problems with this though. Can I create 100000 heavy isolates? Can I create 100000 light isolates? Suppose one of the light isolates ties up the CPU for a long time. Will isolates then be preemptively scheduled out so others gets a chance, or will the system keep running the single isolate while all others wait in queue? I am asking because it hurts latency.&lt;br /&gt;
&lt;br /&gt;
Second, the notation is not built-in but provided as a library. This usually leads to code with heavier weight.&lt;br /&gt;
&lt;br /&gt;
Third, there is no way to scrutinize the mailbox. You get a callback whenever a message is delivered, but it is up to you to build the search infrastructure for the mailbox. This is in strong contrast with Erlang and it usually leads to more complex actors in the long run.&lt;br /&gt;
&lt;br /&gt;
Fourth, there is no concept of robustness. I can't link together Isolates so I can be told when other Isolates die and take care of it. Without links and monitors, it is cumbersome to build anything resembling OTP for Dart.&lt;br /&gt;
&lt;br /&gt;
Fifth, where is my selective receive? We can easily imagine a single isolate having access to multiple ReceivePorts.&lt;br /&gt;
&lt;br /&gt;
In conclusion, the current Isolate-implementation leaves much to be desired. I'd much rather want to hack Google Go in the browser than Dart to be honest. Go is a neater language, is more innovative, is farther ahead and has built-in-concurrency primitives. You just need to add a jQuery-like interface to Go and then it can substitute Dart as an imperative language.&lt;br /&gt;
&lt;br /&gt;
What Dart DOES provide however is the ability to run faster than Javascript. It is clear that some of the choices enables the language to be compiled to much faster executing code. Also, if all you know is Javascript, the language is probably pretty neat. To the Java programmer, proper closures will be a warm welcome.&lt;br /&gt;
&lt;br /&gt;
But for a guy who has seen things you wouldn't believe. Haskell ships off the shoulder of MultiCore CPUs. Watched OCaml glitter in the dark near TAPL. All those moments will be lost in time, like tears in rain. Time to die.&lt;br /&gt;
&lt;br /&gt;
Finally, a disclaimer: I may be wrong on several occasions. I've had some 1-2 hours to study the language, and you can't really grasp a programming language in less than 1-2 months. So I may be wrong. Wrong on all points. Like fine wine, languages need a bit of time to mature and bloom into what they are. Dart is pretty young and drafty in its nature. A lot of things can happen.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-4670047024813708084?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/4670047024813708084/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=4670047024813708084' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/4670047024813708084'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/4670047024813708084'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2011/10/musings-on-dart.html' title='Musings on Dart'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-8702260918155906277</id><published>2011-10-02T08:10:00.000-07:00</published><updated>2011-10-02T08:43:49.102-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rant'/><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><category scheme='http://www.blogger.com/atom/ns#' term='programming languages'/><category scheme='http://www.blogger.com/atom/ns#' term='zeromq'/><title type='text'>One major difference - ZeroMQ and Erlang.</title><content type='html'>When a dog owner wants to train his dog, the procedure is well-known and quite simple. The owner runs two loops: one of positive feedback and one of negative ditto. Whenever the dog does something right, the positive feedback loop is invoked and the dog is treated with a snack. Whenever the dog does something wrong, the dog is scolded and the negative feedback loop is used.&lt;br /&gt;
&lt;br /&gt;
The result is positive and negative&amp;nbsp;reinforcement&amp;nbsp;of the dogs behavior. The dog will over time automatically behave as the owner wants and never even think of misbehaving.&lt;br /&gt;
&lt;br /&gt;
When a programming language trains its leashed programmer, it likewise uses positive and negative feedback. Whenever a problem is easily solvable in the constructs and features of said language, it reinforces the use of those features and constructs. And also in the same vein, if something is hard to do in the language, the programmer will shy away from thinking the idea, since it may be too hard to do in the language. Another negative feedback loop is when resource usage of a program is bad. Either it will use too much memory of too many CPU resources to carry out its work. This discourages the programmer from using that solution again.&lt;br /&gt;
&lt;br /&gt;
The important point is that while all practical general purpose languages are Turing complete, the way they train programmers to behave as they want is quite different. In an Object Oriented language for instance, the programmer is trained to reframe most - if not all - questions as objects of bundled fields and methods. A functional programmer is trained to envision programs as transformations of data from the form X into the form Y through the application of a function. And so on.&lt;br /&gt;
&lt;br /&gt;
Which brings us to how ZeroMQ and Erlang will train its programmers into doing vastly different things:&lt;br /&gt;
&lt;br /&gt;
In ZeroMQ, the programmer will configure a messaging network. That network will probably be fairly static. It is not the case that there is &lt;i&gt;one &lt;/i&gt;configuration, invoked in the beginning of the system, which stays there for all of the systems execution, but chances are that the configuration is still fairly rigid and not subject to much change.&lt;br /&gt;
&lt;br /&gt;
Around this messaging network, we now add processes which operate on the network. We send and receive messages on the network, processing them in various different programming languages. A process is also fairly &lt;i&gt;static&lt;/i&gt;&amp;nbsp;in the sense that the process is started, and then tend to use the messaging network as a queue: It will pick off some work, look at the data, process the data and push it back into the messaging network again. Taken to the extreme, ZeroMQ applications are often queue processors like this.&lt;br /&gt;
&lt;br /&gt;
Incoming requests are transformed to a message and then sent into the messaging network of ZeroMQ. Then it will be processed by some vacant process in the other end and it will be moved from queue to queue until it finally completes. Note ZeroMQ is more complex than a simple point-to-point messaging framework, but the gist of the idea here is that many applications will have the above mentioned system design.&lt;br /&gt;
&lt;br /&gt;
In Erlang, the programmer will take the request and turn the request into a process. Erlang programmers are trained by the language to like having a large amount of small processes like this, because the language encourages that behaviour. ZeroMQ-solutions on the other hand will be discouraged to dequeue a message and create a process out of it - if the processing language uses a traditional heavyweight thread for a process.&lt;br /&gt;
&lt;br /&gt;
Now, given that the request is a process, an Erlang programmer will do the dual to the ZeroMQ programmer. Since the process is now the request, whenever the request needs to do some processing, it will do so itself. If it needs some external information, the request/process will ask for it. The preemptive scheduler will ensure that no request can stall the pipeline. Also, since the scheduler in Erlang is parallel, it is relatively easy to get all cores to work, but by having enough requests/processes in the run-queue.&lt;br /&gt;
&lt;br /&gt;
Note, also, how the messaging network in this solution is fairly &lt;i&gt;dynamic&lt;/i&gt;. Point-to-point exchanges are formed on demand when a request need some information.&lt;br /&gt;
&lt;br /&gt;
To the Erlang programmer, the representation of the request &lt;i&gt;is &lt;/i&gt;the process. There is no "message" living in a queue which is the representation of the request at any point. There are less need to tune fan-in/fan-out at the end of queues to make parallel work go through, since the schedulers will automatically&amp;nbsp;parallelize.&lt;br /&gt;
&lt;br /&gt;
Both styles have their advantages and disadvantages. But that is not the interesting point. The interesting point is how the ZeroMQ idea encourages one system design, whereas the Erlang solution encourages another. In Erlang a process is cheap, so it is totally feasible to turn each request into one. Furthermore, since there is no concept of a message channel, sending a message to a target is all about knowing or finding the name of the target (see for instance Ulf Wiger/Erlang Solutions &lt;b&gt;gproc&lt;/b&gt; framework for an efficient name registry). On the contrary, since ZeroMQ has the concept of a generalized &lt;i&gt;socket&lt;/i&gt;&amp;nbsp;as a channel endpoint and assuming the programming language we use for processing does not have cheap processes. Then the only feasible solution is to build a static channel network with processors.&lt;br /&gt;
&lt;br /&gt;
Another interesting point is that most languages with static type systems have latched onto the channel solution. It is easy because a channel can be annotated with the type traversing the channel. But it also trains programmers to think in that model. It would be fun to see a language where process Id's - that is names of processes - have a type of what that process receives.&lt;br /&gt;
&lt;br /&gt;
The concluding remark: ZeroMQ/Erlang above is just an example. You can find this kind of reinforcement with basically &lt;i&gt;any&lt;/i&gt;&amp;nbsp;language design choice. It is rarely that a feature is&amp;nbsp;ubiquitously good or bad. Rather, most choices are a trade-off. Haskells lazy evaluation enables some optimizations but disallow some other optimizations. Ocaml, being eager, can do the optimization that Haskell can't and can't do the ones that Haskell can. Similarly, for a programmer, getting easier access to some feature often means less control of something else, or that something else become much harder to pull off.&amp;nbsp;&amp;nbsp;The next time you enter in a discussion on the merits of a given language feature, make sure there is not a programming language holding your leash and telling you what is right or wrong!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-8702260918155906277?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/8702260918155906277/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=8702260918155906277' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/8702260918155906277'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/8702260918155906277'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2011/10/one-major-difference-zeromq-and-erlang.html' title='One major difference - ZeroMQ and Erlang.'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-8891898853662107229</id><published>2011-07-04T07:40:00.000-07:00</published><updated>2011-07-04T07:50:58.867-07:00</updated><title type='text'>Erlangs parallelism is not parallelism!</title><content type='html'>This post is all about parallel computation from a very high level&amp;nbsp;view. I claim Erlang is not a parallel language &lt;i&gt;in particular&lt;/i&gt;. It is&amp;nbsp;not created with the primary goal of speeding up computation and&amp;nbsp;harnessing multiple cores, your GPU and so on. If that is your goal,&amp;nbsp;there are other languages which will probably fare much better for&amp;nbsp;your needs (Haskell, for instance).&lt;br /&gt;
&lt;br /&gt;
Note however, while Erlang is not a parallel language, its runtime is&amp;nbsp;rather excellent at forcing out parallelism of existing &lt;i&gt;concurrent&amp;nbsp;&lt;/i&gt;programs. So when we say Erlang is parallel, we say that Erlang is&amp;nbsp;parallel in a specific way! The recent years have seen much work in&amp;nbsp;Erlang/OTP on making the runtime concurrently parallel and we are&amp;nbsp;reaping the benefits. The reason can be found in the simple&amp;nbsp;observation that a Erlang program has thousands of processes which&amp;nbsp;gives thousands of executable threads of control. Since you have more&amp;nbsp;than one thread of control, and communication between them is largely&amp;nbsp;asynchronous, you have all the opportunity for a parallel speedup.&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;Parallelism vs Concurrency&lt;/span&gt;&lt;br /&gt;
A fine point indeed, is that parallel computation and concurrency are&amp;nbsp;different entities when considering computation. Simon Marlow has a&amp;nbsp;&lt;a href="http://ghcmutterings.wordpress.com/2009/10/06/parallelism-concurrency/"&gt;blog post&lt;/a&gt;&amp;nbsp;in which he describes the details.&lt;br /&gt;
&lt;br /&gt;
The gist of it, however, is rather simple: computing parallel is to&amp;nbsp;hunt for a program &lt;i&gt;speedup&lt;/i&gt;&amp;nbsp;when adding more execution cores to the&amp;nbsp;system running the program. This is a property of the&amp;nbsp;machine. Computing concurrent is to write a program with multiple&amp;nbsp;threads of control such that it will non-deterministically execute&amp;nbsp;each thread. It is a property of the language.&lt;br /&gt;
&lt;br /&gt;
If you come with a view from the hardware and upwards toward to&amp;nbsp;computing logic, then surely you may fall into the trap of equating&amp;nbsp;the two terms. The reason is that to implement parallel computation in&amp;nbsp;current hardware and software, you use a concurrent semantics. The &lt;b&gt;pthread&amp;nbsp;&lt;/b&gt;library for instance is writing a concurrent program which&amp;nbsp;then takes advantage of multiple processors if they are available. To&lt;br /&gt;
program for the shared memory architecture, you use mutex'es and&amp;nbsp;locks. Most other methods build on top of these primitives. Deep down&amp;nbsp;at the hardware level, it is the presence of a Compare-and-swap&lt;br /&gt;
operation that is at the heart of the idea.&lt;br /&gt;
&lt;br /&gt;
One may then surmise: are we always going to use these primitives deep&amp;nbsp;down when we implement parallel programs. Are we always going to go&amp;nbsp;parallel from the concurrency primitives? If your opinion is largely&amp;nbsp;yes, then you may hold the view from below, from hardware and up.&lt;br /&gt;
&lt;br /&gt;
The view up from the logic and down, is that the &lt;i&gt;language&lt;/i&gt; has&amp;nbsp;certain constructs available to it, of which some are&amp;nbsp;parallel. How we are going to &lt;i&gt;implement&lt;/i&gt;&amp;nbsp;those features is postponed&amp;nbsp;until later. That is, we squint our eyes in a way such that we cannot&amp;nbsp;see the deeper down details - but can concentrate on the general&amp;nbsp;ideas. One could imagine different hardware on which another&amp;nbsp;implementation would be more beneficial, for instance by running on&amp;nbsp;special purpose hardware for the task, an FPGA or a GPU.&lt;br /&gt;
&lt;br /&gt;
The main point is that parallelism is a declarative notion in the&amp;nbsp;logic. If you want an array processed in parallel, you are not going&amp;nbsp;to explain how the underlying implementation should squeeze in more&amp;nbsp;computational work on multiple cores. You are just stating that the&amp;nbsp;semantics of your program is such that it is allowed to do so. Most&amp;nbsp;importantly, in parallel array processing you must be very specific&amp;nbsp;about the order in which elements are being processed. For some&amp;nbsp;computations it doesn't matter. For other computations, there is a&amp;nbsp;notion of order and you can't screw it up. The difference in semantics&amp;nbsp;here w.r.t. order is among what concerns a language designer with the&amp;nbsp;view from logic.&lt;br /&gt;
&lt;br /&gt;
So there are essentially two views: from hardware or from logic. From&amp;nbsp;the perspective of logic, if you have toyed with formal semantics, is&amp;nbsp;that we define concurrency-primitives in a different way than&amp;nbsp;parallelism-primitives formally. That is, they are different&amp;nbsp;entities. The perspective of hardware on the other hand, conflates the&amp;nbsp;ideas because the only way to achieve parallelism is to use&lt;br /&gt;
concurrency - especially in UNIX.&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;Erlang is not a parallel programming language!&lt;/span&gt;&lt;br /&gt;
Erlang is not a&amp;nbsp;&lt;a href="http://www.javalimit.com/2011/05/erlang-is-not-a-concurrent-functional-programming-language.html"&gt;concurrent functional programming language&lt;/a&gt;. It&amp;nbsp;is not concurrent in the sense that Erlang was built for robustness&amp;nbsp;and fault tolerance. To implement robustness and fault tolerance, it&amp;nbsp;was decided that concurrency was a good vehicle. Likewise for the&amp;nbsp;decision to make the language functional. These choices were merely&amp;nbsp;done in other to achieve the greater goal and had to be chosen along&amp;nbsp;the way.&lt;br /&gt;
&lt;br /&gt;
Erlang is not a parallel language either! The goal is to provide&amp;nbsp;robustness and fault tolerance. Going parallel does not directly&amp;nbsp;facilitate this goal, and hence from a perspective of language logic&amp;nbsp;there are very few primitives that has to do with the concept of&amp;nbsp;parallelism. Contrast with concurrency of which there are several&amp;nbsp;central primitives built into the language.&lt;br /&gt;
&lt;br /&gt;
From the view of the hardware and the actual implementation of Erlang/OTP,&amp;nbsp;much attention has been paid the recent years to make the Erlang VM be&amp;nbsp;able to execute processes in parallel. This has mainly been done&amp;nbsp;because you can then increase hardware utilization and hope to gain&amp;nbsp;a speedup in your programs. In other words, it is not a necessity, but&amp;nbsp;a nice-to-have feature.&lt;br /&gt;
&lt;br /&gt;
The main point to take away from this observation is that in Erlang,&amp;nbsp;parallel computation is implicit. If you write your program in an&amp;nbsp;idiomatic way, you will often find that there are automatic speedup&amp;nbsp;gains from going to multiple cores. But you have little direct&amp;nbsp;control of how things are going to be parallel. Rather, you design&amp;nbsp;your program such that it can implicitly take advantage of multiple&amp;nbsp;cores.&lt;br /&gt;
&lt;br /&gt;
There is an inherent want for many newfangled Erlang programmers to&amp;nbsp;harness the full potential of their new K-core machine (with K &amp;gt;&amp;nbsp;1). The idea is simply that by using Erlang, the program will run&amp;nbsp;faster because you will stand a chance at getting the utilization of&amp;nbsp;the cores up.&lt;br /&gt;
&lt;br /&gt;
But this is and has not been the primary focus of Erlang! And hence it is not a given&amp;nbsp;that your program will run faster. To make it go fast, the program has&amp;nbsp;to be written in a style that makes it possible for multiple cores to&amp;nbsp;work on the program at the same time, implicitly.&lt;br /&gt;
&lt;br /&gt;
That said, Erlang was designed in a way that makes automatic use of&amp;nbsp;multiple cores much simpler than some other languages out there. In&amp;nbsp;fact, a common case is that you should be able to speed up an&amp;nbsp;unaltered program in many cases just by adding more cores. Given the&amp;nbsp;focus on robustness and faul tolerance this sounds decision&amp;nbsp;logical. If you have a system that works and is relatively void of&amp;nbsp;bugs, then you should not have to go out and change the internals of&amp;nbsp;the program to make it run faster. The Danger is that your new altered&amp;nbsp;program is incorrect and then it does not matter at all if it runs&amp;nbsp;faster or not.&lt;br /&gt;
&lt;br /&gt;
One might take the goal of Erlangs parallel endeavours as: we hope to&amp;nbsp;achieve a relatively good amount of speedup when adding multiple cores&amp;nbsp;without you having to change the program. That is, if you add more&amp;nbsp;cores, we expect some speedup, but not necessarily a speedup which is&amp;nbsp;the best possible. It is an attempt at a best-effort solution rather than a&amp;nbsp;perfect one. Herein lies the gist of why Erlang is not a parallel&amp;nbsp;programming language. It is not about maximizing the throughput and&amp;nbsp;usage of the many cores, but to use them to automatically enhance an&amp;nbsp;already written program.&lt;br /&gt;
&lt;br /&gt;
Finally, if one looks at the Erlang history, parallelism only came to&amp;nbsp;the language fairly late. While some believe that the language is&amp;nbsp;excellent in a multi-core era because it is (relatively) easy to make&amp;nbsp;the runtime parallel this was not the goal initially. By sheer luck,&amp;nbsp;some of the design decisions made for Erlang makes the language&amp;nbsp;brilliant for running on multiple cores.&lt;br /&gt;
&lt;br /&gt;
Finally, a word has to be said on granularity of processes. What is&amp;nbsp;the smallest piece of computation that can be made to work on multiple&amp;nbsp;cores. In Erlang, the grain is finer than most other languages&amp;nbsp;concepts of "threads". And processes are so cheap that it is easy to&amp;nbsp;spawn a new one to do separate computation. But it is important to&amp;nbsp;note that the grain is coarser than the Haskell concept of a "spark"&amp;nbsp;(see&lt;br /&gt;
&lt;a href="http://community.haskell.org/~simonmar/papers/multicore-ghc.pdf"&gt;Runtime support for multicore Haskell (PDF)&lt;/a&gt;&amp;nbsp;for instance). And the spark concept is spot-on for squeezing out&amp;nbsp;parallelism at a much finer grain than what Erlang has. The essential&amp;nbsp;trick for sparks in Haskell is that they share the Thread-State-Object&amp;nbsp;(context). So you don't have to go start new threads to service&amp;nbsp;sparks, making them much cheaper to execute even if there are millions&amp;nbsp;of them. As an explicit method of gaining parallelism, sparks is a&amp;nbsp;very interesting concept.&lt;br /&gt;
&lt;br /&gt;
In conclusion: Erlang can do parallelism in the view of adding it on&amp;nbsp;top of concurrency. This means that parallelism is implicit rather&amp;nbsp;than explicit in the program and hence you want to program in a&amp;nbsp;certain style to make sure your program goes fast. The rest of this&amp;nbsp;post here are ideas for doing that.&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;Utilization vs Speedup&lt;/span&gt;&lt;br /&gt;
It is very easy to get full utilization of a 128 core machine: Let 1&amp;nbsp;core do the actual work, and let the remaining 127 cores run an infinite loop.&lt;br /&gt;
&lt;br /&gt;
All cores will now show that they utilize 100%, yet the program is not&amp;nbsp;running any faster than before. We would love to have the program run&amp;nbsp;128 times faster, now we had 128 times the computational &amp;nbsp;power&amp;nbsp;available. The actual *speedup* is what we are after.&lt;br /&gt;
&lt;br /&gt;
As a programmer, you have two goals. The first goal is to get the&amp;nbsp;utilization up. You can't hope for &amp;nbsp;speedup if cores are sitting&amp;nbsp;there, idling. *The utilization is an upper bound for speedup*. Next,&amp;nbsp;the goal is to make the additional cores do something better than the&amp;nbsp;endless loop above. That is, decrease the execution time of the&amp;nbsp;program.&lt;br /&gt;
&lt;br /&gt;
It is worth to look at&amp;nbsp;&lt;a href="http://en.wikipedia.org/wiki/Amdahl's_law"&gt;Amdahl's law&lt;/a&gt; in the&amp;nbsp;parallel variant. The central aspect of the law is *"serial parts in&amp;nbsp;program will slow your program down"*. That part can only be run on a&amp;nbsp;single core, and hence it will limit the other cores into idling if&amp;nbsp;they have to wait. And when we consider a parallel part, there is a&amp;nbsp;critical path, called the &lt;i&gt;span&lt;/i&gt; of the computation (see&amp;nbsp;&lt;a href="http://software.intel.com/sites/products/documentation/hpc/composerxe/en-us/cpp/mac/cref_cls/common/cilk_work_span.htm"&gt;Work &amp;amp; Span&lt;/a&gt;&amp;nbsp;for instance). Making the span smaller will also yield a faster&amp;nbsp;program - but when optimizing for the span, the critical path may jump&amp;nbsp;to another part of the computation.&lt;br /&gt;
&lt;br /&gt;
Also of importance is&amp;nbsp;&lt;a href="http://en.wikipedia.org/wiki/Gustafson%27s_Law"&gt;Gustafson's law&lt;/a&gt;. Amdahl&amp;nbsp;assumes a fixed workload size. If we can complete that workload in&amp;nbsp;half the time, we have a speedup of two. But as the number of cores&amp;nbsp;increases, so does the overhead of orchestrating their&amp;nbsp;communication. Gustafson (et. al) proposed that we instead make &amp;nbsp;workload size the scaling variable. That is, suppose the solve a&amp;nbsp;workload of size 1 in 1 minute on 1 core. Now, if we have 8 cores,&amp;nbsp;perfect speedup would be that we were able to solve a workload of size&amp;nbsp;8 in 1 minute on 8 cores. Contrast with Amdahl: workload 1, 1/8 minute&amp;nbsp;and 8 cores.&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;Erlang and speedup&lt;/span&gt;&lt;br /&gt;
While Erlang is not an explicit parallel language, it does not hurt&amp;nbsp;to write your Erlang programs in a style which invites multiple cores&amp;nbsp;to do work. In this section, we will try to give some general advice&amp;nbsp;on how to do exactly that. To make Erlang able to execute programs in&amp;nbsp;parallel, you must obviously structure your program as such.&lt;br /&gt;
&lt;br /&gt;
First, your process run-queue must have enough work that it can be&amp;nbsp;divided among several cores. If there is only ever a single process&amp;nbsp;that can run, that will limit the parallelism of your program.&lt;br /&gt;
&lt;br /&gt;
Second, be aware of serializing bottlenecks. A process executing is&amp;nbsp;the granularity. So if a large number of workers all go to the same&amp;nbsp;single process for their data, that single process is now the&amp;nbsp;contention point which is serial and for that part of the code there&amp;nbsp;will not be any speedup. If the query to the single process is&amp;nbsp;dominating in your program you are in a bad shape. The extension of&amp;nbsp;this is rather simple: if you have 4 workers processing a queue, then&amp;nbsp;your maximal speedup is 4. This may not be enough on a 16-core machine.&lt;br /&gt;
&lt;br /&gt;
Third, synchronous calls blocks more than asynchronous casts. If&amp;nbsp;possible, prefer asynchronously communicating processes over&amp;nbsp;synchronous ones. Long chains of synchronous calls following each&amp;nbsp;other are serialization in disguise. They block out other callers when&amp;nbsp;they are processing. They are also prone to creating deadlocks in&amp;nbsp;programs. Asynchronous calls will in addition tend to fill up&amp;nbsp;mailboxes with work. It is much more efficient to handle 8 messages in&amp;nbsp;a context switch time slot than it is handling 1 message and then&amp;nbsp;switch right away on an empty queue. In some cases you can go&amp;nbsp;pseudo-async by making 1 out of 100 calls synchronous for instance. This&amp;nbsp;is an effective way to ensure that you don't overflow a slow receiver&amp;nbsp;as it forces in some amount of flow control.&lt;br /&gt;
&lt;br /&gt;
In Erlang a process is very cheap. It is far cheaper than a `pthread`&amp;nbsp;thread in C. This leads to a programming methodology where you are not&amp;nbsp;afraid of creating processes. Much like you would be creating objects&amp;nbsp;in OOP. A million processes is not a limiting factor. A good design&amp;nbsp;choice in Erlang is simply to create a process per incoming request or&amp;nbsp;event. Take an HTTP server for instance. Each GET-request will &lt;i&gt;spawn&lt;/i&gt;&amp;nbsp;a new process to handle that GET. Had processes been heavy in weight,&amp;nbsp;this approach would not have been viable at all. The idea is that the&amp;nbsp;data you are going to be operating on is morphed into a&amp;nbsp;thread-of-control so the data itself can go ask other parties for&amp;nbsp;information, process on itself and so on. There is a strong similarity&amp;nbsp;to OOP here as each process plays the role of an living object (they&amp;nbsp;are "dead" in OOP only to be temporarily revived from their zombie&amp;nbsp;state when the current executioner of control comes by).&lt;br /&gt;
&lt;br /&gt;
The design effectively ensures our run-queue is always filled up well&amp;nbsp;with work to do. Had we opted for a queue-pipeline approach as is&amp;nbsp;common in many other languages, the amount of workers working on each&amp;nbsp;queue would have to be tuned to the number of cores. Furthermore, you&amp;nbsp;have to watch out for overloading a specific queue. In our&amp;nbsp;morph-data-into-process design it is the run-queue we have to watch&lt;br /&gt;
out for, but that is simpler and there are tools for doing it (see for&amp;nbsp;instance Erlang Solutions&amp;nbsp;&lt;a href="https://github.com/esl/jobs/blob/master/doc/README.md"&gt;esl/jobs&lt;/a&gt;&amp;nbsp;application).&lt;br /&gt;
&lt;br /&gt;
Note, however, that if these many small processes all request data&amp;nbsp;from the same server-like process, then performance will dwindle and&amp;nbsp;suffer. The server-like process is a serializer which we warned about&amp;nbsp;earlier.&lt;br /&gt;
&lt;br /&gt;
One idiom I commonly use is to have a protected ETS table with the option&amp;nbsp;&lt;b&gt;{read_concurrency, true}&lt;/b&gt;&amp;nbsp;set. When all the spawned processes want to&amp;nbsp;read data, they go directly into the ETS table and fetch what they&amp;nbsp;need. Writes are serialized through a central process. Of course this&amp;nbsp;scheme can be altered if you need a large amount of writes, or general&amp;nbsp;reader-writer access.&lt;br /&gt;
&lt;br /&gt;
In the newer Erlang/OTP releases (R14 and upwards, I believe) the&amp;nbsp;access to the ETS table is highly parallel in the runtime. Hence, your&amp;nbsp;million processes will not have to wait on each other to read data out&amp;nbsp;of the table.&lt;br /&gt;
&lt;br /&gt;
Another common trick is to increase the &lt;i&gt;independence&amp;nbsp;&lt;/i&gt;of&amp;nbsp;computations. Whenever you can eliminate some sharing, perhaps by&amp;nbsp;recalculating it or caching it somewhere, then you increase the&amp;nbsp;independence of the computation. In Erlang semantics, processes have&amp;nbsp;exclusive access to their own data. Hence, the independence of data is&amp;nbsp;already really good. What you want to avoid is having to partner with&amp;nbsp;other processes to solve a task -- if the partner is heavily&amp;nbsp;contended.&lt;br /&gt;
&lt;br /&gt;
The central point is to be aware where serialization might occur in&amp;nbsp;your code and then eliminate it. Otherwise, you may see a bad&amp;nbsp;utilization, and no speedup. There is a nice tool,&amp;nbsp;&lt;a href="http://www.erlang.org/doc/apps/percept/percept_ug.html"&gt;Percept&lt;/a&gt;,&amp;nbsp;which can profile the &lt;i&gt;runnability&lt;/i&gt;&amp;nbsp;of a process; when a process or&amp;nbsp;port can be run on a core.&lt;br /&gt;
&lt;br /&gt;
Also, you should be aware of the following interesting gotchas:&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;I disabled SMP and now my code runs faster!&lt;/b&gt;&lt;br /&gt;
Yes. This is a common thing. First, when you benchmark your code, a&amp;nbsp;very grave but all too common mistake is to use your code&amp;nbsp;optimized for parallel execution on the single core. Parallel code&amp;nbsp;often has some overhead due to communication and often, it also&amp;nbsp;impedes the execution speed if you run it on a single core only.&lt;br /&gt;
&lt;br /&gt;
You must benchmark the fastest possible &lt;i&gt;non-parallel&lt;/i&gt;&amp;nbsp;version of your&amp;nbsp;program and count the speedup against that. The other solution is&amp;nbsp;simply not fair. It is one way you can make your benchmark look better&amp;nbsp;by cheating.&lt;br /&gt;
&lt;br /&gt;
The overhead is also present when you take your program, written in&amp;nbsp;Erlang, and run it on the non-SMP variant of the Erlang VM. It can often go&amp;nbsp;faster for some work loads. The reason is that your program may not&amp;nbsp;exploit parallelism that well and thus the overhead of going truly&amp;nbsp;parallel is dominating the actual speedup gain. I have seen this with&amp;nbsp;some of my Haskell programs as well.&lt;br /&gt;
&lt;br /&gt;
There is a fairly high price for suddenly having multiple cores inside&amp;nbsp;the VM doing things. You will have to synchronize in the runtime and&amp;nbsp;even though your synchronization primitives are heavily optimized,&amp;nbsp;they have overhead. Now, if the problem you are looking at is not even&amp;nbsp;saturating a single core, then surely, it would have been better to run&amp;nbsp;in a single-threaded manner. It is only when you could benefit from a&amp;nbsp;second core that it will help you.&lt;br /&gt;
&lt;br /&gt;
If, on the other hand, your problem maxes out the core, then adding a&amp;nbsp;new core to the mix has some overhead, but it will make the&amp;nbsp;computation scale further and you may experience a better throughput&amp;nbsp;in the end.&lt;br /&gt;
&lt;br /&gt;
So if you are well below a single core in utilization, this is often a&amp;nbsp;way to lower the amount of work your system has to do. And make the&amp;nbsp;code run faster.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;My code has faster than perfect speedup!&lt;/b&gt;&lt;br /&gt;
Another common thing that can happen is super-linear speedup. That is,&amp;nbsp;you may have 8 cores and expect a speedup close to 8 -- but all of a&amp;nbsp;sudden you have a speedup of 12. This happens. The reason it happens&amp;nbsp;is usually that when you add cores to your computer, you also alter&amp;nbsp;other resources. Most notably, you often increase the amount of&amp;nbsp;available cache. If you distribute the computation over multiple&amp;nbsp;physical machines, you may also increase the amount of available RAM.&lt;br /&gt;
&lt;br /&gt;
These factors can improve your computational speed by quite a lot if&amp;nbsp;you can manage computations such that they become independent of each&amp;nbsp;other. It directly reaps the benefit of the added caches as there will&amp;nbsp;be no migration of data from one cache to another. If the computation&amp;nbsp;can suddenly fit into the caches, then the speed can be much&amp;nbsp;increased. Likewise, the same pattern can emerge if you add more RAM&amp;nbsp;to your cluster. Suddenly the central data can be kept mostly in&amp;nbsp;memory and you don't have to load data off the disk anymore.&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;Hiding latency - the secret weapon for fast parallel computation&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
If there is a single trick resulting in fast parallel speedups, it&amp;nbsp;has to be latency hiding. Note problems come in three varieties: The&amp;nbsp;simple, the impossible and the interesting.&lt;br /&gt;
&lt;br /&gt;
The simple problems are called the&amp;nbsp;&lt;a href="http://en.wikipedia.org/wiki/Embarrassingly_parallel"&gt;Embarrassingly parallel problems&lt;/a&gt;. They&amp;nbsp;are simple to solve: split them into equal sized chunks and solve each&amp;nbsp;part. Then reintegrate the individual solutions into a final&amp;nbsp;result. The idea of Map-Reduce leans itself to a solution method. It&amp;nbsp;is obvious if your problem is simple, then Map-Reduce solves it. The&amp;nbsp;impossible problems are the class of problems for which you have&amp;nbsp;little to no hope of speeding up the computation by having more&amp;nbsp;cores. A compiler, for instance, can compile multiple modules at&amp;nbsp;once. But the steps of lexing-parsing-code-gen-optimization-and-so-on&amp;nbsp;has to happen in that order and has to happen in a serial fashion - a&amp;nbsp;large span is dominating. Some numerical iterative computations&amp;nbsp;require a finished computed step N before they can tackle step&amp;nbsp;N+1. These problems are so data dependent that you have no hope of&amp;nbsp;making those parts parallel. Essentially the span of each iteration is&amp;nbsp;chained together in a way that makes it impossible to speed up.&lt;br /&gt;
&lt;br /&gt;
This leaves us with the interesting class of problems. In order to&amp;nbsp;compute these, you need to have some amount of sharing/dependence in between the&amp;nbsp;processes. And this is where the latency hiding trick comes into&amp;nbsp;play.&lt;br /&gt;
&lt;br /&gt;
When one process sends data to another process, there is latency&amp;nbsp;involved. We must copy data into another mailbox, or perhaps copy to&amp;nbsp;another computer. The bandwidth of the network and the size of the&amp;nbsp;data we have to copy puts us into a situation where there is a minimum&amp;nbsp;latency we can expect when we copy. Now, the naive solution is to&amp;nbsp;repeat a two step process: Compute this iteration. Then Exchange this&amp;nbsp;iteration with other processes. But every time we exchange data the&amp;nbsp;processes are waiting and are idle. If communication time&amp;nbsp;dominates, then our speedup will suffer.&lt;br /&gt;
&lt;br /&gt;
The latency hiding idea almost doesn't even warrant a name: "do&amp;nbsp;something else while the data transfers". That's it. Like an&amp;nbsp;operating system is doing something else while a process waits for&amp;nbsp;disk IO to complete, a process can do something else while waiting for&amp;nbsp;data to transfer.&lt;br /&gt;
&lt;br /&gt;
To Erlang programmers this means that the &lt;i&gt;order&lt;/i&gt;&amp;nbsp;in which you send&amp;nbsp;and receive matter. If you reorder the receives such that the&amp;nbsp;communication overhead is hidden, then your program will be able to&amp;nbsp;find the relevant message in its mailbox already there when it is&amp;nbsp;needed. The rule is &lt;i&gt;send early&lt;/i&gt; and &lt;i&gt;receive late&lt;/i&gt;. As soon as you&amp;nbsp;have data another process will need, you must make it available to&amp;nbsp;them. And when you need data make sure you get it as late in the&amp;nbsp;process as possible, just before you need it. That way, it may already&amp;nbsp;be there in the mailbox, ready for you to use.&lt;br /&gt;
&lt;br /&gt;
The conclusion is that one must take into consideration the impact of&amp;nbsp;latencies. In high performance &amp;nbsp;computing it is of primary&amp;nbsp;importance. A worthy bet is that on modern computers, moving data&amp;nbsp;around is often the bottleneck. Not the raw speed of the CPU core. If&amp;nbsp;we have a distributed system, then the latencies may be much higher&amp;nbsp;due to network copying - with a much higher impact on speed. The CPU&amp;nbsp;cache also plays a crucial role in limiting the speed by which your&amp;nbsp;computations will run.&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;Conclusion&lt;/span&gt;&lt;br /&gt;
We have given a brief overview of some of the parallel computation&amp;nbsp;basics. We have argued that concurrency and parallelism are different&amp;nbsp;beasts. We have argued that Erlang is not particularly parallel. We&amp;nbsp;have surmised on what one should do to increase parallelism in Erlang&amp;nbsp;programs. We have also hit on a small number of interesting gotchas&amp;nbsp;when computing parallel. And we have discussed about the concepts of&amp;nbsp;latency hiding.&lt;br /&gt;
&lt;br /&gt;
There is much more to be said about Erlang and parallel computation. I&amp;nbsp;particularly like that Erlang does not assume a cache-coherent&amp;nbsp;architecture for instance. But that will be a post for another time&amp;nbsp;since I am all out of blog space and this is already too large.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-8891898853662107229?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/8891898853662107229/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=8891898853662107229' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/8891898853662107229'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/8891898853662107229'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2011/07/erlangs-parallelism-is-not-parallelism.html' title='Erlangs parallelism is not parallelism!'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-4013543392013115647</id><published>2011-07-01T05:10:00.000-07:00</published><updated>2011-07-01T05:10:02.413-07:00</updated><title type='text'>Google+ - so what is different, technically?</title><content type='html'>Google released Google+. Everyone has now blogged about whether it will "rank or tank", but nobody has really looked into the concept of circles from a more technical viewpoint to my knowledge. Let us remedy that.&lt;br /&gt;
&lt;br /&gt;
Online communication services can all be classified according to different aspects. A chat IM message is, as an example, usually a one-to-one realtime communication. There is an assumption that I will answer a chat message rather quickly - even when I don't have to. IRC - Internet relay chat - is different: communication is &lt;i&gt;topical&lt;/i&gt;&amp;nbsp;as I join a channel discussing a certain topic. Communication is many-to-many and there is no assumption I answer the message right away. Likewise for emails - but there exchange of messages happen at a slower pace with larger bodies of text. The reason you use more than one service is essentially that different communication services cater to different kinds of communication. The collaborative benefits you gain when developing source code over IRC is not paralleled in any place currently for instance - not as a free open project at least.&lt;br /&gt;
&lt;br /&gt;
What kind of communication services disrupts your flow of thought by alerting you and requiring you to answer (phones, I am looking at you!)? How realtime/instant is a message? Can you post additional content like photos, images, urls? Can you split communication into topics of interest? Are topics invite-only or free-to-join by default? How is moderation done on topics? Is it easy to form groups of privacy to discuss something? Is the communication one-to-one-focused, or is it one-to-many or even perhaps many-to-many? Can you build robots to automate tasks for the service? And so, in the light of Google+:&lt;br /&gt;
&lt;br /&gt;
Google+ major point is to work like Facebook does in the core. This means that I am not the primary customer - as I don't use Facebook much. Hence, I am probably the wrong guy to judge if it will work out or not. By the core of Facebook, I mean that the primary goals of G+ and FB overlap very much. In the long run, the goal is to form a relation-&lt;a href="http://en.wikipedia.org/wiki/Graph_(mathematics)"&gt;graph&lt;/a&gt; between people and get access to it for Google.&lt;br /&gt;
&lt;br /&gt;
The major, essential, difference between Google+ and Facebook is the formation of connections. In Facebook, A &lt;i&gt;adds &lt;/i&gt;B and then B &lt;i&gt;confirms &lt;/i&gt;the relationship. The opposite of this is Twitter: you just follow people you are interested in. Facebook runs a 2-way handshake whereas Twitters is one-way. Since connections in Facebook is 2-way, then we trivially have: if A is connected to B, then B is also connected to A. In other words: the connection graph is undirected in Facebook. Contrast with Twitter: graphs in twitter are directed. There are numerous one-way connections in Twitter. Most notable are celebrity-figures with an extremely high amount of followers. The communication from such an account is essentially 1-to-many and public.&lt;br /&gt;
&lt;br /&gt;
So what does Google+ do? It chooses a variant of Twitter. In G+, the graph is directed like in Twitter, but you also &lt;i&gt;label&lt;/i&gt;&amp;nbsp;the edges with a name -- your &lt;i&gt;circle &lt;/i&gt;designation for the connection. You can have multiple edges to the same person/account, so in reality the graph is a multigraph where edges are discriminated by their circle-labels. Another representation is to deem that a graph edge is labeled with a set of circle-labels.&lt;br /&gt;
&lt;br /&gt;
When A adds B to the circles, A is adding an edge in the graph from A to B for each circle. So A builds a one-way path to the other end. If later B decides to add A to his circles, then there will be edges in the opposite direction. They may not be labeled the same at all. This means that A can have B in the circle of close friends while B has A in the circle ObnoxiousCatPhotoSubmitters. This is an interesting skew of connections which come into play. When you post something to a circle, the recipients can not see the message as if it is originating from that circle - in fact circles are exclusive to an account and can't be seen by others. This in effect makes a message a low-level value which is exchanged from a sharer to a list of people the sharer decides via circles. Upon receipt, the message is then cast into the light of the&amp;nbsp;recipients circles.&lt;br /&gt;
&lt;br /&gt;
So forming connections is like in Twitter, only that edges are labeled by Circles given by the source. This is a rather genius move. When A shares, he chooses the circles he want to share the message with. The system then searches all edges labeled with those circles, and posts on those edges only. If A wants to post Tech-related stuff, A can do so in the Tech-circle so only people that might care is hit by the sharing.&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;The sender, A, has complete control of who sees the message. This is what Google refers to as the ability of G+ to&amp;nbsp;accommodate different kinds of privacy levels on messages. Also, it is the sender, A, that defines his or her own levels of privacy with Circles as they are local to an account. It also blurs the definition of "follower", "friend", "connection", "add" and so on. Some edges are labeled as "close friends" and are thus &lt;i&gt;strong&lt;/i&gt;&amp;nbsp;edges from a privacy perspective. Other edges are &lt;i&gt;weak&lt;/i&gt;&amp;nbsp;in the sense that you have a connection, but there are limits to what you want to share with the other person.&lt;/li&gt;
&lt;li&gt;When data arrives at B, messages from A gets sorted according to the circles of B. So when B looks at streams from circles in which A is in, he sees the shared information from A.&lt;/li&gt;
&lt;li&gt;Consequence: A needs to moderate what he sends along the Tech-circle to B. If A begins sending Cat photos to his tech-friends, he will end up in the ObnoxiousCatPosters circle at B - and only that circle. B is free to replace him at any time if he wants. The assumption currently is that relations between people are formed one primary ground. "He is family". "She and I are always discussing cool graphics design". This may largely be true.&lt;/li&gt;
&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;One thing I have not figured out yet: Suppose I want to follow B for more than one interest. Cats and Dogs. I have a circle of Cats and one of Dogs. But when B posts in his public circle for all to see, his posts will end up at my place in both Cats and Dogs. To the best of my knowledge there is no way I can currently split this. My guess is that Google will have to solve it in the longer run. They have several options among of which is to use statistical analysis on the posts through machine learning. Or allow #tags as in Twitter.&lt;/li&gt;
&lt;li&gt;Another thing I have not figured out completely yet: I don't think G+ can substitute for the other communication tools I am already using. Since I am not much of a Facebook user I am not the right demographic, but I don't see G+ replacing Email, IRC or Twitter. Twitter is the thing it will have the best options at replacing in my opinion. Email and IRC needs a more wave'esque approach to the problem I am afraid. I would really like to see an "IRC for the masses" and I am not convinced that Huddle is it. Further, the locality of circles to an account makes them distinctively different from IRC channels. On the other hand, if you have a topical connection graph, you can use machine learning to suggest IRC-like topics later on - and it is not that hard to add proper IRC-like group chat features to Google Chat which is already integrated.&lt;/li&gt;
&lt;/ul&gt;I find the technical difference mentioned here quite interesting. It is definitely a generalization of the existing models of connection-forming, and it will be interesting to see if it takes off, and what people will get out of using it.&lt;br /&gt;
&lt;br /&gt;
So in conclusion: G+ is a funny hybrid between the style of Facebook and Twitter. The circle concept is central to how the connection-graph is formed. And thus, central to how G+ works. It will be interesting to see if Facebook will have a counter-solution. Currently, FB can create groups of friends and handle these in many ways like G+ can handle circles. We can only hope that this competition from Google will force Facebook to improve their system as well. But they probably can't get rid of the two-way connections easily.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-4013543392013115647?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/4013543392013115647/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=4013543392013115647' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/4013543392013115647'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/4013543392013115647'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2011/07/google-so-what-is-different-technically.html' title='Google+ - so what is different, technically?'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-1766946977663340448</id><published>2011-06-01T04:02:00.000-07:00</published><updated>2011-06-01T08:39:05.054-07:00</updated><title type='text'>Web Server Benchmarking, a rant.</title><content type='html'>When people carry out &amp;nbsp;benchmarks of web servers, their reporting of data is often inadequate. Apart from the trouble of&amp;nbsp;&lt;a href="http://www.mnot.net/blog/2011/05/18/http_benchmark_rules"&gt;http://www.mnot.net/blog/2011/05/18/http_benchmark_rules&lt;/a&gt;&amp;nbsp;and getting that right, I want to focus on the reported data. The main point is this: Don't maim the raw data by taking the mean - give us a link to the raw information so we can draw our own conclusions. And don't use benchmarking tools which destroy the raw data after test.&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;Overload:&lt;/span&gt;&lt;br /&gt;
The interesting situation is not the standard situation. What you want to know is not that server X is 30% faster than server Y - but rather what happens when the server gets a spike of incoming traffic. That is, the Poisson teams up against you and you hit serious load. In that case, you want the server able to sustain the load instead of the server which will degrade in performance.&lt;br /&gt;
&lt;br /&gt;
It is far better to dismiss some operations as errors quickly but do serve the requests you accepted, and serve them fast. The raw speed matters less as 30 or even 70% is just a constant factor deciding when you need to scale - either a faster machine or a new one next the the computer you already got. Of course, with 150% it begins to matter &lt;i&gt;a lot&lt;/i&gt;&amp;nbsp;which is faster, but for most servers, the speed is so good it doesn't matter. Stability and the overload situation is more important to optimize for.&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;Errors and latency:&lt;/span&gt;&lt;br /&gt;
In a benchmark, there is a bar which describes what is an error. In some benchmarks, the error will be a request which never completed. In other tests, it will be that a given request took too long. There is little reason to accept a request of 10 seconds as the poor user will almost always have reloaded or clicked again. Moderns users are &lt;i&gt;impatient&lt;/i&gt;&amp;nbsp;to the point of being painfully so.&lt;br /&gt;
&lt;br /&gt;
This leads to the idea we should regard requests which are too slow&lt;i&gt;&amp;nbsp;&lt;/i&gt;as &lt;i&gt;errors as well. &lt;/i&gt;If a request doesn't complete under 5 seconds, it is an error as well. But for a lot less, users may become bored on your site and not use it. Even a 100ms bump can mean a lot.&lt;br /&gt;
&lt;br /&gt;
This leads to the virtue of the benchmarker numero uno: &lt;b&gt;Record latencies for the measurements&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;&lt;br /&gt;
&lt;/b&gt;&lt;br /&gt;
You should, ideally, be recording each of your 250000 requests and their individual latency. But this is usually too much for the benchmark tool to handle. Rather, you want the tool to do random sampling and record, say, 2500 samples and store them in a file. The cool thing about this is that you can hand the data out when you present your information. It is like cake to a statistician, who will be able to use the raw data.&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;Beware the heretic: Average&lt;/span&gt;&lt;br /&gt;
Unfortunately, many benchmark tools report &lt;i&gt;statistics&lt;/i&gt;&amp;nbsp;rather than raw data. They will give you the &lt;i&gt;minimum, maximum, average, median, stddev&lt;/i&gt;&amp;nbsp;and so on. The very first thing you should do when you get raw data is to plot them. You want to see what the data looks like. Just a simple histogram plot can often tell you a lot about the data at hand:&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-sgHHlghbcY0/TeYO9LWHYWI/AAAAAAAAAJk/_Q2U4qrTuao/s1600/1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://1.bp.blogspot.com/-sgHHlghbcY0/TeYO9LWHYWI/AAAAAAAAAJk/_Q2U4qrTuao/s320/1.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;This looks fairly okay as a normal distribution of data with a mean of 7 and a standard deviation of 2. In fact it is, because it was randomly generated as such. Here is another one:&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-r1i0eRvd3Uw/TeYPzRwHGNI/AAAAAAAAAJo/Iy9eWlcu9fo/s1600/2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://1.bp.blogspot.com/-r1i0eRvd3Uw/TeYPzRwHGNI/AAAAAAAAAJo/Iy9eWlcu9fo/s320/2.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;And that one is very interesting. It has an odd latency spike around 25 as well! Again, the example is generated from two normal distributions whose observations we have plotted here as a histogram. For the first one it may be ok to use the stddev and average value because they make sense in that case. But for the second it is &lt;i&gt;most definitely not&lt;/i&gt;&amp;nbsp;acceptable. We ask R for the summary of the first:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;gt; summary(a)&lt;br /&gt;
&amp;nbsp; &amp;nbsp;Min. 1st Qu. &amp;nbsp;Median &amp;nbsp; &amp;nbsp;Mean 3rd Qu. &amp;nbsp; &amp;nbsp;Max.&lt;br /&gt;
&amp;nbsp;0.1309 &amp;nbsp;5.6200 &amp;nbsp;6.7750 &amp;nbsp;6.8090 &amp;nbsp;7.9960 13.3500&lt;br /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;For a web server the Min value would tell us something about the lower limit. If the server is 30ms away travelling at the speed of light, that is the minimum value we can ever hope for. The Maximum observation is interesting as well. If it is too high, the user will not hoover and is gone. The mean is the average value of the observations. We'll get back to the dreaded mean. The 1st quartile, &lt;a href="http://en.wikipedia.org/wiki/Median"&gt;Median&lt;/a&gt; and 3rd quartile is achieved by lining up all the observations in a sorted manner to get the distribution function:&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-gFzeHF9I7q4/TeYR5aGPfzI/AAAAAAAAAJs/fHaZPpcR1lU/s1600/3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="400" src="http://2.bp.blogspot.com/-gFzeHF9I7q4/TeYR5aGPfzI/AAAAAAAAAJs/fHaZPpcR1lU/s400/3.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;And then you pick the guy 25% in from the left of the X-axis as the 1st quartile. The guy at 50% as the median and finally the guy at 75% as the 3rd quartile. If there is no middle value (in the case of an even number of observations) you pick the mean between the two middle observations. For the first example plotted here, the median and mean is basically the same value. But what about example 2?&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&amp;gt; summary(example_2)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&amp;nbsp; &amp;nbsp;Min. 1st Qu. &amp;nbsp;Median &amp;nbsp; &amp;nbsp;Mean 3rd Qu. &amp;nbsp; &amp;nbsp;Max.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&amp;nbsp;0.1309 &amp;nbsp;5.8300 &amp;nbsp;7.1380 &amp;nbsp;9.4180 &amp;nbsp;8.9150 26.1900&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;This looks bad. The Median and Mean doesn't line up and this should normally be a warning sign you should plot the histogram. In fact, if you look at the above histogram plot you will find that the observations around 25 &lt;i&gt;skew &lt;/i&gt;the mean too much to the right. In fact 9.4 is not a very likely value. It is more likely to get either a 7 (in around 85% of the time) or a 25 (around 15% of the time). The median tells us that the most likely value is around 7. The distribution plot should tell us something as well:&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;a href="http://3.bp.blogspot.com/-LMuwkX5WKow/TeYTvhHMFEI/AAAAAAAAAJw/rWw6xUSnXSQ/s1600/4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="400" src="http://3.bp.blogspot.com/-LMuwkX5WKow/TeYTvhHMFEI/AAAAAAAAAJw/rWw6xUSnXSQ/s400/4.png" width="400" /&gt;&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;A value of 17 is highly unlikely. Yet, if I had constructed more observations in the 25 area, then the mean would have been 17. That is why the mean is a bad indicator for a data set. And it is why we want the raw data. If you report something, make it be the median. Or make whiskers on your values so we can see the development as you increase your load on the server:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.mnot.net/blog/apache-worker.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="315" src="http://www.mnot.net/blog/apache-worker.jpg" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;Notice how Mark Nottingham adds small vertical bars to each measurement so he can report the range in which most of the repsonses fall? That is a neat idea!&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;Even better is to use boxplots on each observation so you can see how it relates to the mean value:&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://addictedtor.free.fr/graphiques/graphiques/graph_140.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="316" src="http://addictedtor.free.fr/graphiques/graphiques/graph_140.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: inherit; font-size: large;"&gt;My hunch:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;I think there is a gem to be found but currently hidden from our scrutiny. I hypothesize some web servers are &lt;i&gt;far better&lt;/i&gt;&amp;nbsp;than others when it comes to harnessing the latency and keeping it stable, whereas other servers are more likely to skew the results a lot. It tells you a lot about the robustness of the server and it is another key factor on which to measure. I don't care that much about requests per second as I care about this number. It is like claiming your network is better because it has more bandwidth, blindly ignoring the question of latency (a rant for another time).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;Face it, if you measured two web servers correctly, you could do the statistics to figure out if one were significantly (in the statistical sense) better than the other. In Ostinellis work,&amp;nbsp;&lt;a href="http://www.ostinelli.net/a-comparison-between-misultin-mochiweb-cowboy-nodejs-and-tornadoweb/"&gt;http://www.ostinelli.net/a-comparison-between-misultin-mochiweb-cowboy-nodejs-and-tornadoweb/&lt;/a&gt;&amp;nbsp;for instance, we see that mochiweb is only 66% faster than Node.js, which isn't going to make a dent in practice. The 25% difference between Misultin and Cowboy reported is even less so. But the response time for Node.js is 6.6 &lt;i&gt;times as large &lt;/i&gt;compared to Mochiweb&lt;i&gt;.&lt;/i&gt;&amp;nbsp;(Around 600ms compared to around 90ms at 10000 in load). That is difference you should be worried about. And that is the reason for my plea:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Give us latency samples when you benchmark web servers!&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;i&gt;(Edit: Smaller changes to sentences in the beginning to get the narrative to flow better)&lt;/i&gt; &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-1766946977663340448?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/1766946977663340448/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=1766946977663340448' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/1766946977663340448'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/1766946977663340448'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2011/06/web-server-benchmarking-rant.html' title='Web Server Benchmarking, a rant.'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-sgHHlghbcY0/TeYO9LWHYWI/AAAAAAAAAJk/_Q2U4qrTuao/s72-c/1.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-8901061402285972882</id><published>2011-05-06T03:26:00.000-07:00</published><updated>2011-05-06T03:30:40.239-07:00</updated><title type='text'>Node.js vs Erlang is the wrong battle.</title><content type='html'>Every once in a while, we see the same discussion popping up again: "Should I concentrate on Node.js or Erlang for my needs?" Let me be clear: I think it is the wrong discussion. Fact is, if you have chosen a language which support a large number of concurrent tasks at the same time, you are probably going to be ready for the future.&lt;br /&gt;
&lt;br /&gt;
Divination is hard, but I am not sure we are going to see a fast multi-core revolution with thousands of processes. As per Moore's law, if transistor count increased as we would like, we would have had 2 cores in 2006 (Intel Core 2 Duo), 4 (physical) cores in 2008 (Core i7, Intel also) and 8 physical cores in 2010. Where is my 8 core laptop today? Even Sandy Bridge is not up there. I have a hunch a couple of things are happening: the market has seen a shift to low-power devices, which is more important to the consumer, notably by the ARM incursion. And people can't utilize a multi-core machine with 8 cores since their programs are not written to take advantage of several cores. Finally, it is cheaper to buy infrastructure on-demand at places like Heroku, Google, Amazon, Microsoft, Rackspace and so on.&lt;br /&gt;
&lt;br /&gt;
But if parallelism is not coming, distribution and concurrency is! Modern programs have to live on several devices at the same time. You check your mail on the mobile phone, on the tablet device, on your laptop and on the workstation, if you still use one. Likewise, a modern program will probably live on multiple devices at once and to harness that game, you need efficient distribution. Enter new languages with support.&lt;br /&gt;
&lt;br /&gt;
And this is why the battle must stop. Like a game of Chess the point of the languages are to be different. Haskell, Google Go, Erlang and Node.js all come with a given set of features for controlling the multi-core problem. But like in Chess the pieces are different and built for different purposes. And here we are only looking at current implementations. Theoretically, the ML family, with Standard ML, Ocaml and F# are really well suited for the concurrency and distribution revolution as well, even though the implementations lack in robustness.&lt;br /&gt;
&lt;br /&gt;
The enemy of the state, is a large set of old ways of programming. It is not so much the language chosen as it is the ideology. You can't rely on shared information when the RAM is physically split between two devices (and you have no fast reliable link in between). You can't rely on OOP in the Java sense to save you. And you can't usually get consistency across the distribution parts due to&amp;nbsp;unreliability.&lt;br /&gt;
&lt;br /&gt;
Rather, see the different languages as stakes in the future of computing. They are different for a reason and they gamble by being different. Personally, I like Erlang because it has what I see as a good view of the problem and hand, and a novel way at solving it. Yes, it can be made better in so many ways, but I think Erlang is at the right point on the "Worse is Better" scale. It actually solves a lot of my real-world gripes.&lt;br /&gt;
&lt;br /&gt;
Node.js plays different cards in the game. I really like the mix of continuations, lack of blocking, V8 and Javascript on the server side. Go plays it yet differently, taking a much more low-level approach to the problem at hand. Go feels like an updated C with channels, and it got substructural subtyping to boot. Haskell is just awesome because the language needed very little change to support concurrency. The semantics of Haskell are on a different level than most other, and with Haskell, it is the fabric of computation you are mangling to your desire.&lt;br /&gt;
&lt;br /&gt;
In the endgame of Chess, pieces like the knight become less efficient since its cunning ability to pass through other pieces is not as powerful. Time will tell what piece was the knight. But if you did not bet on every approach, you wouldn't know if you just hit a local optimum.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-8901061402285972882?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/8901061402285972882/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=8901061402285972882' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/8901061402285972882'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/8901061402285972882'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2011/05/nodejs-vs-erlang-is-wrong-battle.html' title='Node.js vs Erlang is the wrong battle.'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-5008016489931834440</id><published>2011-04-06T08:37:00.000-07:00</published><updated>2011-04-06T08:37:50.296-07:00</updated><title type='text'></title><content type='html'>&lt;h1 id="functions-and-one-view"&gt;4 Functions and one view&lt;/h1&gt;&lt;p&gt;Let us define an Agda module:&lt;/p&gt;&lt;pre class="sourceCode literate haskell"&gt;&lt;code&gt;&amp;gt;    module Partition where
&amp;gt; 
&amp;gt;    open import Data.Bool
&amp;gt;    open import Data.Nat
&amp;gt;    open import Data.Product
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In Agda, we can define the option-type as the following hybrid between Haskell and ML:&lt;/p&gt;&lt;pre class="sourceCode literate haskell"&gt;&lt;code&gt;&amp;gt;    data Option (A : Set) : Set where
&amp;gt;      Nothing : Option A
&amp;gt;      Just : (o : A) -&amp;gt; Option A
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That is, option types are formed by either being &lt;code&gt;Nothing&lt;/code&gt; or by being &lt;code&gt;Just A&lt;/code&gt; for some element type &lt;code&gt;A&lt;/code&gt;. Likewise, we can define Lists as:&lt;/p&gt;&lt;pre class="sourceCode literate haskell"&gt;&lt;code&gt;&amp;gt;    data List (A : Set) : Set where
&amp;gt;      [] : List A
&amp;gt;      _∷_ : (x : A) -&amp;gt; (xs : List A) -&amp;gt; List A
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That is, lists are either the empty list &lt;code&gt;[]&lt;/code&gt; or they are formed as a cons operator, where we have an element &lt;code&gt;x&lt;/code&gt; of type &lt;code&gt;A&lt;/code&gt;, the head, and a tail-list. Together this forms a list.&lt;/p&gt;&lt;p&gt;We now define a really simple function on lists. We will ask if there is an element of the list that satisfies a predicate &lt;code&gt;p&lt;/code&gt;. That is, we ask “Exists an element satisfying the predicate?”&lt;/p&gt;&lt;pre class="sourceCode literate haskell"&gt;&lt;code&gt;&amp;gt;    exists : {A : Set} -&amp;gt; (A -&amp;gt; Bool) -&amp;gt; List A -&amp;gt; Bool
&amp;gt;    exists p [] = false
&amp;gt;    exists p (x ∷ xs) with p x
&amp;gt;    ... | true = true
&amp;gt;    ... | false = exists p xs
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The function makes use of a &lt;code&gt;with&lt;/code&gt; statement of Agda. &lt;code&gt;with p x&lt;/code&gt; can in this case be seen as a &lt;code&gt;case p x of&lt;/code&gt; where the two possible variants are then handled to the left of the pipe bar &lt;code&gt;|&lt;/code&gt;. The three dots, &lt;code&gt;...&lt;/code&gt; signifies that nothing else change in the parameters. Generally, the match in Agda is dependent, so the output of &lt;code&gt;p x&lt;/code&gt; could have constrained the other parameters (that is the other parameters depend on the output of the match).&lt;/p&gt;&lt;p&gt;This function is very simple, but it does not yield us a lot of information, should we want to know which element that actually existed. Essentially, we have become &lt;em&gt;blind&lt;/em&gt; to some information. On the other hand, if we are only interested in the question of existence, then the function will not produce additional information, we later need to throw away.&lt;/p&gt;&lt;p&gt;Let us add a remedy to our alchemical formulae: We present the &lt;code&gt;find&lt;/code&gt; function:&lt;/p&gt;&lt;pre class="sourceCode literate haskell"&gt;&lt;code&gt;&amp;gt;    find : {A : Set} -&amp;gt; (A -&amp;gt; Bool) -&amp;gt; List A -&amp;gt; Option A
&amp;gt;    find f [] = Nothing
&amp;gt;    find f (x ∷ xs) with f x
&amp;gt;    ... | true = Just x
&amp;gt;    ... | false = find f xs
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This guy is &lt;code&gt;exists&lt;/code&gt;-one-step-up. Here, when our scrutineer finds a matching element, we return the element itself. Thus, if we need the element for further work, we have it at our disposal. In practice, it may seem more expensive than &lt;code&gt;exists&lt;/code&gt;, but it is not: first, &lt;code&gt;x&lt;/code&gt; we return is a reference, so it has a fixed size. Furthermore, if we don’t &lt;em&gt;use&lt;/em&gt; &lt;code&gt;x&lt;/code&gt;, then the compiler is free to declare all code involving producing &lt;code&gt;x&lt;/code&gt; as dead and remove it from the code. Essentially, a compiler like Haskell’s GHC will probably re-obtain the &lt;code&gt;exists&lt;/code&gt; version automatically by optimization.&lt;/p&gt;&lt;p&gt;But the sexiness of this function is still pretty low. We don’t know if there is only a single element matching, or if there are more elements matching. We add another ingredient, and present to you the &lt;code&gt;filter&lt;/code&gt; function:&lt;/p&gt;&lt;pre class="sourceCode literate haskell"&gt;&lt;code&gt;&amp;gt;    filter : {A : Set} -&amp;gt; (A -&amp;gt; Bool) -&amp;gt; List A -&amp;gt; List A
&amp;gt;    filter f [] = []
&amp;gt;    filter f (x ∷ xs) with f x
&amp;gt;    ... | true = x ∷ filter f xs
&amp;gt;    ... | false = filter f xs
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now, when the function return, we get back a list of all the guys matching the predicate. Thus, we can just pick up the head and in a lazy language, we would probably not make more work on the rest of the list if we chose to do so. It is yet a generalization in our stack. It provides a &lt;em&gt;view&lt;/em&gt; with a lot more information than from before. We can for instance easily detect the case where there are 3 elements satisfying the predicate by pattern matching, and then handle that case specially, should we want to do so.&lt;/p&gt;&lt;p&gt;But we are not done yet. Everything was merely foreplay. Add the next level of abstraction and generality:&lt;/p&gt;&lt;pre class="sourceCode literate haskell"&gt;&lt;code&gt;&amp;gt;    partition : {A : Set} -&amp;gt; (A -&amp;gt; Bool) -&amp;gt; List A
&amp;gt;              -&amp;gt; List A × List A
&amp;gt;    partition d xs = part d xs [] []
&amp;gt;      where
&amp;gt;        part : ∀ {A : Set} -&amp;gt; (A -&amp;gt; Bool)
&amp;gt;              -&amp;gt; List A -&amp;gt; List A -&amp;gt; List A
&amp;gt;              -&amp;gt; List A × List A
&amp;gt;        part d [] yes no = yes , no
&amp;gt;        part d (x ∷ xs') yes no with d x
&amp;gt;        ... | true  = part d xs' (x ∷ yes) no
&amp;gt;        ... | false = part d xs' yes (x ∷ no)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Partition use a discriminator function, &lt;code&gt;d&lt;/code&gt;, which splits the list into the &lt;code&gt;yes&lt;/code&gt;’s — those matching the predicate — and the &lt;code&gt;no&lt;/code&gt;’s; those that do not. It is interesting we can walk down back the chain easily:&lt;/p&gt;&lt;pre class="sourceCode literate haskell"&gt;&lt;code&gt;&amp;gt;    filter₁ : {A : Set} -&amp;gt; (A -&amp;gt; Bool) -&amp;gt; List A -&amp;gt; List A
&amp;gt;    filter₁ p xs = proj₁ (partition p xs)
&amp;gt; 
&amp;gt;    find₁ : {A : Set} -&amp;gt; (A -&amp;gt; Bool) -&amp;gt; List A -&amp;gt; Option A
&amp;gt;    find₁ p xs with filter₁ p xs
&amp;gt;    ... | [] = Nothing
&amp;gt;    ... | x ∷ xs' = Just x
&amp;gt; 
&amp;gt;    exists₁ : {A : Set} -&amp;gt; (A -&amp;gt; Bool) -&amp;gt; List A -&amp;gt; Bool
&amp;gt;    exists₁ p xs with find₁ p xs
&amp;gt;    ... | Nothing = false
&amp;gt;    ... | Just _  = true
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Which shows how &lt;code&gt;partition&lt;/code&gt; is an aggressive generalization of &lt;code&gt;exists&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;Essentially, this is a question of &lt;em&gt;information&lt;/em&gt; you have when using the different functions. With partition, you have the most information: you know exactly which elements matched, and which did not. Again, with enough optimization, it should be possible for a compiler to derive the faster versions if possible. The &lt;em&gt;view&lt;/em&gt; this function provides happen to be better than the views the other functions provide. It is, in some sense, the correct implementation.&lt;/p&gt;&lt;p&gt;In Agda, views mean something more specific. A &lt;em&gt;view&lt;/em&gt; there is a datatype, with the sole purpose of being evidence of some observation. If we compute some outcome, we shove the resulting information into a data type, the &lt;em&gt;view&lt;/em&gt; and then we can later ask the question “Why?” by matching on that type. The Agda tutorials has more details, but the general idea of using a data structure to carry information is what motivated this blog post initially. I also find the relationship between the four functions interesting by itself.&lt;/p&gt;&lt;p&gt;You may wonder: Why do we even bother to have the other definitions around? Mostly, it has to do with optimization hints to the compiler. An implementation like &lt;code&gt;find&lt;/code&gt; tell the compiler we are only interested in a single element, first match and it can throw away other parts of the computation. In other words, it can be seen as a guide to the compiler about our current intent. It is also an intent-hint to the human reader. We make it explicit we don’t need certain parts of the computation, so the reader is free to ignore those.&lt;/p&gt;&lt;p&gt;In some languages, the only discriminator is the boolean test. So you are essentially forced into a model where either you only have &lt;code&gt;exists&lt;/code&gt; or you are to write a specialized version of the above whenever you need access to them. If your language miss Algebraic Data Types or has no construct which can stand in for it easily, then you are doomed to reimplement lots of stuff all the time. Your modularity suffer deeply as a result.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-5008016489931834440?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/5008016489931834440/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=5008016489931834440' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/5008016489931834440'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/5008016489931834440'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2011/04/4-functions-and-one-view-let-us-define.html' title=''/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-2853517672681847466</id><published>2011-01-24T15:32:00.000-08:00</published><updated>2011-01-24T17:10:21.833-08:00</updated><title type='text'>Agda musings on huttons razor</title><content type='html'>&lt;div id="agda-musings-on-huttons-razor"
&gt;&lt;h1
  &gt;Agda musings on Huttons razor&lt;/h1&gt;&lt;p
  &gt;So Ralf Lämmel, also known as “Professor Fish”, defined a &lt;a href="http://professor-fish.blogspot.com/2011/01/tiny-bit-of-denotational-semantics.html"
    &gt;small language&lt;/a
    &gt; of which he took full copyright. The language was used as an assignment for students hacking Haskell and they were to carry out two alterations on the language in question. First, they were to give it a CPS style semantics and next, they were to define an analysis determining when expressions in the language were pure.&lt;/p&gt;&lt;p
  &gt;So far so good, but I am kind of tongue-in-cheek when I see tasks like these. And I wanted to play a bit with the idea. The first decision was to throw out Haskell as a tool. No, if we will have types, then let us get some real types. Dependent types. And let us require that all our programs terminate while we are at it. In other words, employ Agda2 to solve the task.&lt;/p&gt;&lt;p
  &gt;We begin by aptly naming the module as &lt;code
    &gt;fish&lt;/code
    &gt;&lt;/p&gt;&lt;pre
  &gt;&lt;code
    &gt;module fish where
&lt;/code
    &gt;&lt;/pre&gt;&lt;p
  &gt;in honor of the grand professor who devised this magnificent language we are to present shortly. To define the language, we will need to pull in some Agda libraries for our use. If there is anything I’ve missed in my Twelf-hacking, it is the ability to use libraries defined by others when I am writing code.&lt;/p&gt;&lt;pre
  &gt;&lt;code
    &gt;open import Function hiding (const)
open import Data.Bool
open import Data.Nat
open import Data.Product
open import Data.Sum
open import Relation.Binary.PropositionalEquality
&lt;/code
    &gt;&lt;/pre&gt;&lt;p
  &gt;At this point, we get to define the language in question. We begin with a simple definition of a local module in which to define the language:&lt;/p&gt;&lt;pre
  &gt;&lt;code
    &gt;module HRazor where
  data Exp : Set where
    Const : ℕ -&amp;gt; Exp
    Plus  : Exp -&amp;gt; Exp -&amp;gt; Exp
&lt;/code
    &gt;&lt;/pre&gt;&lt;p
  &gt;What is this? This language is in a &lt;code
    &gt;HRazor&lt;/code
    &gt; module. While it seems Professor Fish took copyright on the language, we know that Graham Hutton already took a patent on this language and dubbed it Hutton’s razor. We will shortly see that the language is different from the one which Ralf had in mind eventually - but the Razor is at the heart of it.&lt;/p&gt;&lt;p
  &gt;In Hutton’s Razor, we have &lt;em
    &gt;expressions&lt;/em
    &gt; defined by &lt;code
    &gt;Exp&lt;/code
    &gt; and these have exactly two constructors. The first constructor, &lt;code
    &gt;Const&lt;/code
    &gt; takes a natural number and returns an expression. Note how Agda is a Unicode-aware language. This is an idea that will slowly creep upon you until you begin liking it. It signifies constants in the language. The other constructor, &lt;code
    &gt;Plus&lt;/code
    &gt; adds together two expressions. This is the full language.&lt;/p&gt;&lt;p
  &gt;Is the language silly? Most decidedly not! Suppose you are researching some new idea in language theory. The Razor described above is about the smallest language you can define that does something meaningful. So your idea better work for the razor. Otherwise, you can as well ignore getting the idea working for harder problems.&lt;/p&gt;&lt;p
  &gt;Here is the function for (denotational) evaluation of the language:&lt;/p&gt;&lt;pre
  &gt;&lt;code
    &gt;  eval : Exp -&amp;gt; ℕ
  eval (Const y) = y
  eval (Plus y y') = (eval y) + (eval y')
&lt;/code
    &gt;&lt;/pre&gt;&lt;p
  &gt;which for most programmers of functional languages should be pretty straightforward. Essentially, we turn the expression tree into an evaluation in Agda.&lt;/p&gt;&lt;div id="ralf-adds-a-construct"
  &gt;&lt;h2
    &gt;Ralf adds a construct&lt;/h2&gt;&lt;p
    &gt;Ralf’s assignment does not revolve around Huttons Razor. After all, Hutton has a patent (which he graciously grants every language researcher free use of). Rather, Ralf augments the razor with a &lt;code
      &gt;Exit&lt;/code
      &gt; construction:&lt;/p&gt;&lt;pre
    &gt;&lt;code
      &gt;data Exp : Set where
  Const : ℕ -&amp;gt; Exp
  Plus  : Exp -&amp;gt; Exp -&amp;gt; Exp
  Exit  : Exp -&amp;gt; Exp
&lt;/code
      &gt;&lt;/pre&gt;&lt;p
    &gt;The informal meaning of &lt;code
      &gt;Exit&lt;/code
      &gt; is this: &lt;code
      &gt;Exit e&lt;/code
      &gt; will evaluate the computation &lt;code
      &gt;e&lt;/code
      &gt; and then abort the rest of the program, returning &lt;code
      &gt;e&lt;/code
      &gt; as its value. To reflect the idea that the program may be in two possible states now, either computing, or exiting, we need a way to tag what state we are in. Haskell people have the &lt;code
      &gt;Either a b&lt;/code
      &gt; type, but in Agda, this is a disjoint sum:&lt;/p&gt;&lt;pre
    &gt;&lt;code
      &gt;R = ℕ ⊎ ℕ
&lt;/code
      &gt;&lt;/pre&gt;&lt;p
    &gt;Ralf generously provided some helper functions defining an algebra for how to compute with the disjoint sum so we translate these to Agda. Constant expressions are injected to the left in the sum:&lt;/p&gt;&lt;pre
    &gt;&lt;code
      &gt;const : ℕ -&amp;gt; R
const i = inj₁ i
&lt;/code
      &gt;&lt;/pre&gt;&lt;p
    &gt;Addition compares the two sides. It propagates right injections up, but computes on left injections. This is as Ralf does in his post.&lt;/p&gt;&lt;pre
    &gt;&lt;code
      &gt;add : R -&amp;gt; R -&amp;gt; R
add (inj₁ x) (inj₁ x') = inj₁ (x + x')
add (inj₁ x) (inj₂ y) = inj₂ y
add (inj₂ y) y' = inj₂ y
&lt;/code
      &gt;&lt;/pre&gt;&lt;p
    &gt;Finally, if we want to &lt;em
      &gt;exit&lt;/em
      &gt;, we convert a left injection to a right one, and just pass on the right injection.&lt;/p&gt;&lt;pre
    &gt;&lt;code
      &gt;exit : R -&amp;gt; R
exit (inj₁ x) = inj₂ x
exit (inj₂ y) = inj₂ y
&lt;/code
      &gt;&lt;/pre&gt;&lt;p
    &gt;The neat thing about defining an algebra like this for &lt;code
      &gt;R&lt;/code
      &gt;-computations is that now the evaluation function is almost as simple as in the Razor:&lt;/p&gt;&lt;pre
    &gt;&lt;code
      &gt;eval : Exp -&amp;gt; R
eval (Const y) = const y
eval (Plus y y') = add (eval y) (eval y')
eval (Exit e) = exit (eval e)
&lt;/code
      &gt;&lt;/pre&gt;&lt;p
    &gt;The only new thing is the &lt;code
      &gt;Exit&lt;/code
      &gt; case which formalizes our informal definition above: compute &lt;code
      &gt;eval e&lt;/code
      &gt; and exit with it.&lt;/p&gt;&lt;div id="so-what-is-the-point"
    &gt;&lt;h3
      &gt;So what is the point?&lt;/h3&gt;&lt;p
      &gt;Well, this is Agda, so we can analyze the language we have defined for some very simple properties easily. Remember that I said that Agda programs are required to terminate. This comes in very handy when we want to prove that our language does, because we have a definition of it in Agda.&lt;/p&gt;&lt;p
      &gt;If Agda’s termination checker says that the Agda-program terminates, so does our Ralf augmented-Razor. In other words, we immediately have the property. Neat. In the same vein, our language must be deterministic. These properties can be formalized in Agda and proven as well, but they are immediate.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="task-1-continuations"
  &gt;&lt;h2
    &gt;Task 1, continuations&lt;/h2&gt;&lt;p
    &gt;Next, we CPS-transform our semantics. We could &lt;em
      &gt;naively&lt;/em
      &gt; transform the language, above into CPS and then provide that, but that is a boring solution. Nay, the cool thing about CPS is that it makes the control flow of the program explicit. We can exploit this explicit control-flow to optimize the case of &lt;code
      &gt;Exit&lt;/code
      &gt; expressions in the program.&lt;/p&gt;&lt;pre
    &gt;&lt;code
      &gt;module NotNaive where
&lt;/code
      &gt;&lt;/pre&gt;&lt;p
    &gt;Ok, so we throw everything into a submodule, &lt;code
      &gt;NotNaive&lt;/code
      &gt;, to limit what is in our scope at any point in time so naming is not going to trip us up later.&lt;/p&gt;&lt;pre
    &gt;&lt;code
      &gt;  constK : ℕ -&amp;gt; (ℕ -&amp;gt; ℕ) -&amp;gt; ℕ
  constK i k = k i
&lt;/code
      &gt;&lt;/pre&gt;&lt;p
    &gt;This is part of our algebra as before. If we have a constant, how do we handle it? We add another parameter, the &lt;code
      &gt;k&lt;/code
      &gt; above which is the &lt;em
      &gt;kontinuation&lt;/em
      &gt;. In the case of the Razor-extension, we can regard &lt;code
      &gt;k&lt;/code
      &gt; as “the rest of the program”. It has type &lt;code
      &gt;(&amp;#8469; -&amp;gt; &amp;#8469;)&lt;/code
      &gt; which sort-of makes it a transformer on natural numbers. So if we are to &lt;em
      &gt;deliver&lt;/em
      &gt; the natural number &lt;code
      &gt;i&lt;/code
      &gt; to the kontinuation, we apply &lt;code
      &gt;k i&lt;/code
      &gt;.&lt;/p&gt;&lt;p
    &gt;Additions take two values and &lt;em
      &gt;delivers&lt;/em
      &gt; the addition to the kontinuation (which still is, intuitively, the rest of the program):&lt;/p&gt;&lt;pre
    &gt;&lt;code
      &gt;  addK : ℕ -&amp;gt; ℕ -&amp;gt; (ℕ -&amp;gt; ℕ) -&amp;gt; ℕ
  addK v1 v2 k = k (v1 + v2)
&lt;/code
      &gt;&lt;/pre&gt;&lt;p
    &gt;In the &lt;code
      &gt;Exit&lt;/code
      &gt; case comes the trick. We do the following&lt;/p&gt;&lt;pre
    &gt;&lt;code
      &gt;  exitK : ℕ -&amp;gt; (ℕ -&amp;gt; ℕ) -&amp;gt; ℕ
  exitK i k = i
&lt;/code
      &gt;&lt;/pre&gt;&lt;p
    &gt;which is to &lt;em
      &gt;not&lt;/em
      &gt; deliver the value to &lt;code
      &gt;k&lt;/code
      &gt; but just return it straight away. This means that we will &lt;em
      &gt;abort&lt;/em
      &gt; the evaluation of “the rest of the program” and just return the exit value straight away.&lt;/p&gt;&lt;p
    &gt;We now turn our attention in this language towards the evaluation function in the language. Constants are handled in the obvious way by using the algebra directly, but the two other cases are handled differently:&lt;/p&gt;&lt;pre
    &gt;&lt;code
      &gt;  evalK : Exp -&amp;gt; (ℕ -&amp;gt; ℕ) -&amp;gt; ℕ
  evalK (Const y) k = constK y k
  evalK (Plus y y') k = evalK y (\v1 -&amp;gt; evalK y' (\v2 -&amp;gt; addK v1 v2 k))
  evalK (Exit y) k = evalK y (\v1 -&amp;gt; exitK v1 k)
&lt;/code
      &gt;&lt;/pre&gt;&lt;p
    &gt;Take the &lt;code
      &gt;Exit&lt;/code
      &gt;-case first. We evaluate the &lt;code
      &gt;y&lt;/code
      &gt; like in the direct case. But then, we need to supply a continuation which says what the rest of the program does. Our continuation assumes it gets passed a value &lt;code
      &gt;v1&lt;/code
      &gt; which is the result of the &lt;code
      &gt;y&lt;/code
      &gt; computation. It then exits with this value. The &lt;code
      &gt;Plus&lt;/code
      &gt; case is similar, but there are two continuations to juggle. We evaluate &lt;code
      &gt;y&lt;/code
      &gt; and deliver it to a continuation that first evaluates &lt;code
      &gt;y'&lt;/code
      &gt; and then delivers to the final continuation, using our &lt;code
      &gt;addK&lt;/code
      &gt; function from above.&lt;/p&gt;&lt;p
    &gt;To run the program:&lt;/p&gt;&lt;pre
    &gt;&lt;code
      &gt;run2 : Exp -&amp;gt; ℕ
run2 e = NotNaive.evalK e id
&lt;/code
      &gt;&lt;/pre&gt;&lt;p
    &gt;note we pass in the &lt;code
      &gt;id&lt;/code
      &gt; identity function to “start up” the evaluation. This is in balance with what Ralf did. Again, Agda’s termination checker immediately provides termination guarantees for program.&lt;/p&gt;&lt;/div&gt;&lt;div id="task-2:-a-taste-of-dependent-types"
  &gt;&lt;h2
    &gt;Task 2: A Taste of dependent types&lt;/h2&gt;&lt;p
    &gt;The main reason I set out to do this however, was to utilize the dependent types Agda has built-in. There are something eternally pleasing in defining programs which do not need to compute to answer questions, and here we will see an example of it.&lt;/p&gt;&lt;p
    &gt;The task is to create a function &lt;code
      &gt;pure&lt;/code
      &gt; taking an expression and returning &lt;code
      &gt;true&lt;/code
      &gt; if the expression is &lt;em
      &gt;pure&lt;/em
      &gt; and false otherwise. Purity is defined as absence of an &lt;code
      &gt;Exit&lt;/code
      &gt; expression. New module:&lt;/p&gt;&lt;pre
    &gt;&lt;code
      &gt;module DepAnalysis where
&lt;/code
      &gt;&lt;/pre&gt;&lt;p
    &gt;Now, dependent types are more than what the following claims it to be, I am aware. But as a first foray, it is quite mind-boggling in itself and serves as a great simple introduction. If we define&lt;/p&gt;&lt;pre
    &gt;&lt;code
      &gt;  data Exp' : Bool -&amp;gt; Set where
&lt;/code
      &gt;&lt;/pre&gt;&lt;p
    &gt;we have declared a dependent datatype &lt;code
      &gt;Exp'&lt;/code
      &gt; which has a &lt;code
      &gt;Bool&lt;/code
      &gt; value attached to it. This means we have two types of expressions: &lt;code
      &gt;Exp' true&lt;/code
      &gt; and &lt;code
      &gt;Exp' false&lt;/code
      &gt;. These are &lt;em
      &gt;different&lt;/em
      &gt; types from the view of the type checker. You can read &lt;code
      &gt;Bool -&amp;gt; Set&lt;/code
      &gt; as “if we supply a boolean value to an &lt;code
      &gt;Exp'&lt;/code
      &gt;, then it will yield a &lt;code
      &gt;Set&lt;/code
      &gt; - &lt;code
      &gt;Set&lt;/code
      &gt; being the elements of the Agda”world&amp;quot; we are working in. So we can just assume in our world, that if an expression is pure, it is &lt;code
      &gt;Exp' true&lt;/code
      &gt; and otherwise, it is &lt;code
      &gt;Exp' false&lt;/code
      &gt;.&lt;/p&gt;&lt;pre
    &gt;&lt;code
      &gt;    Const : ℕ -&amp;gt; Exp' true
&lt;/code
      &gt;&lt;/pre&gt;&lt;p
    &gt;This constructor tells Agda that if we supply the &lt;code
      &gt;Const&lt;/code
      &gt; constructor with a natural number, it will hand us a pure expression. Seems in order, sir! Next constructor:&lt;/p&gt;&lt;pre
    &gt;&lt;code
      &gt;    Exit  : ∀ {c} -&amp;gt; Exp' c -&amp;gt; Exp' false
&lt;/code
      &gt;&lt;/pre&gt;&lt;p
    &gt;This can be read as “if you give my any expression, pure or not - I don’t care - then I will give you a non-pure expresssion”. This makes sense. There is an &lt;code
      &gt;Exit&lt;/code
      &gt; in the expression, so it better not be pure. It doesn’t matter what the internal expression is.&lt;/p&gt;&lt;pre
    &gt;&lt;code
      &gt;    Plus  : ∀ {c1 c2} -&amp;gt; Exp' c1 -&amp;gt; Exp' c2 -&amp;gt; Exp' (c1 ∧ c2)
&lt;/code
      &gt;&lt;/pre&gt;&lt;p
    &gt;In the final case, &lt;code
      &gt;Plus&lt;/code
      &gt; we get to supply two expressions. These two expressions have &lt;code
      &gt;c1&lt;/code
      &gt; and &lt;code
      &gt;c2&lt;/code
      &gt; as their purity-values. Agda will hand us back an expression which is pure if and only if both subexpressions are - due to the conjunction (logical and) in the returned expression.&lt;/p&gt;&lt;p
    &gt;What have we done here? We have created a dependent data type which will itself track if an expression is pure or not. As we build up the abstract syntax tree, the system will make the calculations necessary. Notice, that if the whole AST is known at compile time, then so is the purity of the expression - right away.&lt;/p&gt;&lt;p
    &gt;For completeness, we supply the required function &lt;code
      &gt;pure&lt;/code
      &gt;. Here is the type:&lt;/p&gt;&lt;pre
    &gt;&lt;code
      &gt;  pure : {b : Bool} -&amp;gt; Exp' b -&amp;gt; Bool
&lt;/code
      &gt;&lt;/pre&gt;&lt;p
    &gt;It introduces a new concept, namely &lt;em
      &gt;implicit parameters&lt;/em
      &gt;. The type &lt;code
      &gt;{b : Bool}&lt;/code
      &gt; names a parameter which is implicit. We can normally omit implicit parameters when writing functions because it can be extracted from another type in the specification (in this case from &lt;code
      &gt;Exp' b&lt;/code
      &gt; which contains the &lt;code
      &gt;b&lt;/code
      &gt;). However, if we &lt;em
      &gt;need&lt;/em
      &gt; access to the implicit parameter, we can positionally match it by wrapping it in brackets like this:&lt;/p&gt;&lt;pre
    &gt;&lt;code
      &gt;  pure {x} e = x
&lt;/code
      &gt;&lt;/pre&gt;&lt;p
    &gt;So the purity of the expression is already there, we just need to return it! I personally think this is awfully neat.&lt;/p&gt;&lt;/div&gt;&lt;div id="i-want-to-play-more"
  &gt;&lt;h2
    &gt;I want to play more&lt;/h2&gt;&lt;p
    &gt;The &lt;a href="http://wiki.portal.chalmers.se/agda/pmwiki.php"
      &gt;Agda wiki&lt;/a
      &gt; contains tutorials, the Agda implementation, and all the other cool information on how to play with Agda. The development here is in a &lt;a href="https://gist.github.com/4d2bdfb2d59116d641e6"
      &gt;gist on github&lt;/a
      &gt; should you want to play with. Note that the development I made hardly qualifies to show off the really cool features of Agda but only scratches (barely) the surface of what is possible. My intuition is, however, that we will see much more dependently typed programming in the future, when everyone is programming functionally :)&lt;/p&gt;&lt;p
    &gt;Commentary is as always welcome.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-2853517672681847466?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/2853517672681847466/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=2853517672681847466' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/2853517672681847466'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/2853517672681847466'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2011/01/agda-musings-on-huttons-razor.html' title='Agda musings on huttons razor'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-1675737231943260007</id><published>2011-01-07T15:43:00.000-08:00</published><updated>2011-01-07T15:43:23.071-08:00</updated><title type='text'>Errlxperimentation: Clustering of Erlang Error Reports.</title><content type='html'>&lt;div id="errlxperimentation:-clustering-of-erlang-error-reports."&gt;&lt;h1&gt;Errlxperimentation: Clustering of Erlang Error Reports.&lt;/h1&gt;&lt;i&gt;If anyone wonders what I hacked over the holidays, this is it :)&lt;/i&gt;&lt;br /&gt;
&lt;i&gt;&lt;br /&gt;
&lt;/i&gt;&lt;br /&gt;
In the Erlang/OTP system, there is a registered process with the name of &lt;code&gt;error_logger&lt;/code&gt;. Whenever an error happens in the Erlang system by a correctly configured OTP process, it will send reports to the &lt;code&gt;error_logger&lt;/code&gt;. The logger is then responsible for taking the report and in a pub-sub manner send it to any error handler currently configured.&lt;br /&gt;
&lt;br /&gt;
One of these error handlers, &lt;code&gt;log_mf_h&lt;/code&gt;, is a &lt;em&gt;multi file&lt;/em&gt; log handler. It writes reports in binary term format to a set of files. Whenever a file reaches a certain size, it is &lt;em&gt;rotated&lt;/em&gt; and a new file is written. The result is that we essentially have ring-buffer of all errors that occur in a running Erlang system.&lt;br /&gt;
&lt;br /&gt;
A tool named &lt;code&gt;rb&lt;/code&gt; the “Report Browser” allows us to read in the binary logs and process them. We can list certain errors, “grep” among them, apply filters to the reports and so on. It gives us a system for looking into a running Erlang system for errors — and handling them if we deem them to be problematic. This tool is very neat when you have a running system to inspect. You can basically leave it on for some time and then go look into the log-mf files for errors and crashes. Since the file is rotated on size the only worry is that important errors get rotated out of the log. But if you have enough log space, this won’t happen. In a modern world, you can easily leave 100 Megabytes of error logs. I have taken the leisure of having a modified log_mf_h which can compress term that goes to disk on the fly. This of course improves the size of error report sizes even more.&lt;/div&gt;&lt;div id="the-experiment"&gt;&lt;h1&gt;&lt;br /&gt;
&lt;/h1&gt;&lt;h1&gt;The experiment&lt;/h1&gt;An experiment that has been on my mind for some time was &lt;em&gt;can I possibly do automatic clustering of similar error reports so like reports are clustered together?&lt;/em&gt; If this is possible, I could then just pick a representative for each error cluster and use that as a basis for handling like errors. Even if you have thousands of reports, it may be that there are only a few of them which are really different and a lot of them which are redundant.&lt;br /&gt;
&lt;br /&gt;
I know nothing about clustering. But a question later on &lt;a href="http://www.stackoverflow.com/"&gt;StackOverflow&lt;/a&gt; and after a kind soul on the #erlang IRC channel hinted me in the direction of the paper &lt;a href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.59.131"&gt;Ephemeral Document Clustering for Web Applications (2000) DOI: 10.1.1.59.131&lt;/a&gt; I was set for an experiment with this. The algorithm implemented here is a variant though, mostly due to getting something fast. So it does not implement the full paper. We implement the ideas from there and the paper can be consulted if anything below is unclear (or comment, I'll try to explain).&lt;br /&gt;
&lt;br /&gt;
I altered &lt;code&gt;rb&lt;/code&gt; to &lt;code&gt;rerb&lt;/code&gt;, short for the &lt;code&gt;riak_err&lt;/code&gt; report browser. The Basho guys have this excellent alternative to the &lt;code&gt;sasl&lt;/code&gt; application built into OTP, see &lt;a href="http://github.com/basho/riak_err"&gt;riak_err&lt;/a&gt; and I used that as a starting point. I am not even sure &lt;code&gt;riak_err&lt;/code&gt; is the right place for this, but at least this is what I did for now.&lt;br /&gt;
&lt;div id="processing"&gt;&lt;h2&gt;&lt;br /&gt;
&lt;/h2&gt;&lt;h2&gt;Processing&lt;/h2&gt;The first part is now to convert an error report. They usually look something along the lines of &lt;code&gt;[{badarg, MFA1}, MFa2, ..., MFaN]&lt;/code&gt; where each &lt;code&gt;MFA&lt;/code&gt; is a tuple &lt;code&gt;{Module, Function, [Arg1, ..., ArgN]}&lt;/code&gt; — and each &lt;code&gt;MFa&lt;/code&gt; is a tuple &lt;code&gt;{Module, Function, Arity}&lt;/code&gt; (arity being the number of parameters of the function). Note that Erlang errors are Erlang terms, so they are easily manipulated by our code. It does make them harder to read for newcomers however.&lt;br /&gt;
&lt;br /&gt;
First, we linearize and canonicalize the input. We change the tuple to &lt;code&gt;[badarg, {Module, Function, length([Arg1, ..., ArgN])}, MFa2, ..., MFaN]&lt;/code&gt;. In other words we flatten the error term and we change the occurrence of &lt;code&gt;MFA&lt;/code&gt; to &lt;code&gt;MFa&lt;/code&gt;. As an example we may have an &lt;code&gt;MFA&lt;/code&gt; &lt;code&gt;[{badarg, {ets, insert, [table_foo, {123, something}]}}]&lt;/code&gt; and this is changed into &lt;code&gt;[badarg, {ets, insert, 2}]&lt;/code&gt;. This ensures that we don’t care about the difference of arguments, but only care about the arity of the function and the call stack.&lt;br /&gt;
&lt;br /&gt;
Next, suppose an error report has the structure &lt;code&gt;[A, B, C]&lt;/code&gt; for arbitrary terms A, B and C. We now form &lt;em&gt;bigrams&lt;/em&gt; &lt;code&gt;['#', A], [A, B], [B, C]&lt;/code&gt; and &lt;code&gt;[C, '#']&lt;/code&gt;. The &lt;code&gt;'#'&lt;/code&gt; is just an atom we use as padding for the boundary terms. For each of these we now run the &lt;code&gt;erlang:phash2/2&lt;/code&gt; function to obtain a hash of each bigram: &lt;code&gt;[{phash2(Bg), 1} || Bg &amp;lt;- Bigrams]&lt;/code&gt;. Note we also smacked the hash into a tuple with a value of 1. This list of &lt;code&gt;{Bigram, 1}&lt;/code&gt; pairs forms a vector in an (euclidian) vector space where the bigram part names a dimension in the space. If we form bigrams like this for all error reports, and take the union over all bigrams we have a set of bigrams defining the basis of the space.&lt;br /&gt;
&lt;br /&gt;
Now we define a metric called &lt;em&gt;similarity&lt;/em&gt; on two vectors, &lt;code&gt;A&lt;/code&gt; and &lt;code&gt;B,&lt;/code&gt; of the space by&amp;nbsp;&lt;span class="Apple-style-span" style="font-family: monospace;"&gt;(&lt;/span&gt;&lt;code&gt;A . B) / (||A|| * ||B||) = cos(t)&lt;/code&gt; where &lt;code&gt;.&lt;/code&gt; is the dot-product and &lt;code&gt;||x||&lt;/code&gt; is the norm of the vector &lt;code&gt;x&lt;/code&gt;. This is equivalent to the cosine of the angle &lt;code&gt;t&lt;/code&gt; (theta) between the two vectors &lt;code&gt;A&lt;/code&gt; and &lt;code&gt;B&lt;/code&gt;. Now, if two vectors point in the exact same direction, the angle is 0 and the cosine is 1, i.e., perfect similarity. If the two vectors are orthogonal to each other, the similarity will be 0.&lt;br /&gt;
&lt;br /&gt;
The similarity of a &lt;em&gt;set&lt;/em&gt; of vectors is had by taking the &lt;em&gt;minimum&lt;/em&gt; of any two vectors from the set. It to a certain extent measures how “different” the cluster is because the minimum suggest the most dissimilar result is chosen.&lt;/div&gt;&lt;div id="clustering"&gt;&lt;h2&gt;&lt;br /&gt;
&lt;/h2&gt;&lt;h2&gt;Clustering&lt;/h2&gt;We form a forest of singleton clusters, and place each vector/error-report in its own cluster. Then we consider similarity of each pair of clusters. The two clusters with the highest similarity are joined. The joining also forms a binary-tree, a dendogram, of the two clusters. Whenever we join two clusters, the original clusters are removed. So whenever a join is executed, we are left with one less clusters. Recursively repeat this until we have a binary tree. This forms the cluster dendogram.&lt;br /&gt;
&lt;br /&gt;
Listing the clusters is done by choosing a similarity, 0.5 say and then walking the tree until a similarity of 0.5 is reached. The subtree is then flattened into a cluster of like error reports.&lt;/div&gt;&lt;div id="looking-forward"&gt;&lt;h2&gt;&lt;br /&gt;
&lt;/h2&gt;&lt;h2&gt;Looking forward&lt;/h2&gt;The code is in an experimental branch of my github repo, &lt;a href="https://github.com/jlouis/riak_err/tree/n-gram-analyzer"&gt;jlouis/riak_err/n-gram-analyzer&lt;/a&gt;. Note I currently make no guarantees of its stability currently. I may rebase it still, so poke me if you want to base something on it. Currently you can only configure the &lt;code&gt;riak_err&lt;/code&gt; config tree like:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;{riak_err,
 [{log_mf, true},
  {error_logger_mf_dir, "log/mf"},
  {error_logger_mf_maxbytes, 10240000},
  {error_logger_mf_maxfiles, 10}
 ]},
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
and then run &lt;code&gt;rerb:start().&lt;/code&gt; followed by &lt;code&gt;rerb:analyze()&lt;/code&gt; to analyze the reports. Listing the clusters are done by &lt;code&gt;rerb:list({clusters, Similarity})&lt;/code&gt; where the similarity is between 0.0 and 1.0.&lt;br /&gt;
The code not seen many wars yet, so it is probably quite unstable.&lt;br /&gt;
&lt;br /&gt;
Another important point is that the algorithm used is a simplification of what the above linked paper does. In particular the algorithm is at &lt;em&gt;least&lt;/em&gt; O(n^3) though I think one can pretty easily lower that to O(n^2 lg n). Also, there are some constants that can be shaved down to improve the clustering speed (It is not that fast at the moment since it walks lists all the way). Finally, it is not parallel though some parts of it lends itself to a fork/join style speedup.&lt;br /&gt;
&lt;br /&gt;
I’d also want to provide the clustering tree in a raw way, so you can run arbitrary functions over it. I’ll probably implement a variant that for each cluster tells the size of it and picks three random representatives for it.&lt;/div&gt;&lt;div id="final-words"&gt;&lt;h2&gt;&lt;br /&gt;
&lt;/h2&gt;&lt;h2&gt;Final words&lt;/h2&gt;The clustering used here seems to work wonderfully well for the error reports I tried it on. It happily clusters up like error reports and different clusters contain different error reports. The Bigrams ensure that we grab the call-path rather than just a presence in a function. We only operate on the stack trace, but we could be operating on more of the error-report.&lt;br /&gt;
&lt;br /&gt;
Also, I am not too sure riak_err is the right place for this. I did some alterations to &lt;code&gt;log_mf_h&lt;/code&gt; and &lt;code&gt;rb&lt;/code&gt; which&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Enables error reports above 16Kb in size. No limit-function is employed yet, though it would be preferable. I could imagine a report with the state of a large heap being pushed.&lt;/li&gt;
&lt;li&gt;Use compression on terms. Disk IO is slow compared to in-memory compression.&lt;/li&gt;
&lt;li&gt;Fixes some redundancy in the rb grep code by making the code into a match compiler. This patch can probably flow into OTP after some more testing.&lt;/li&gt;
&lt;li&gt;Use binary notation. The &lt;code&gt;rb&lt;/code&gt; and &lt;code&gt;log_mf_h&lt;/code&gt; code is probably so old Erlang did not have binaries at that time.&lt;/li&gt;
&lt;/ul&gt;Some of the ideas here are inspired by analysis of stack traces in other languages, Java in particular. But perhaps some of these ideas are applicable to log files in general.&lt;br /&gt;
&lt;br /&gt;
Finally, any comments, positive/negative are welcome. Suggestions for improving the ideas here are also much appreciated.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-1675737231943260007?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/1675737231943260007/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=1675737231943260007' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/1675737231943260007'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/1675737231943260007'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2011/01/errlxperimentation-clustering-of-erlang.html' title='Errlxperimentation: Clustering of Erlang Error Reports.'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-94128600604980725</id><published>2010-12-25T08:31:00.000-08:00</published><updated>2010-12-25T16:18:26.460-08:00</updated><title type='text'>A response to "Erlang - overhyped or underestimated"</title><content type='html'>&lt;div id="a-response-to-erlang---overhyped-or-underestimated"&gt;&lt;h1&gt;A response to “Erlang - overhyped or underestimated”&lt;/h1&gt;There is a blog post about &lt;a href="http://sacharya.com/erlang-overhyped-or-underestimated/"&gt;Erlang&lt;/a&gt; which recently cropped up. It is well written and puts forth some critique of the Erlang/OTP language. Naturally, I have a bias. I write a lot of Erlang and I like the language - and anything less then a blog post myself would not be fair: There is much to discuss and a fleeting Twitter comment or a comment below the original post can’t convey the information needed.&lt;br /&gt;
&lt;br /&gt;
&lt;em&gt;Erlang is like an exotic beautiful woman with no dressing sense.&lt;/em&gt;&lt;br /&gt;
&lt;em&gt;&lt;br /&gt;
&lt;/em&gt;&lt;br /&gt;
I Love this comment from the article. There is truth in it: underneath the clothes of Erlang, beauty is hiding. Yet, I feel that one might have misunderstood the dress code in the exotic world, which is why I sat down, &lt;strong&gt;C-x C-f’ed&lt;/strong&gt; a new buffer and began writing.&lt;br /&gt;
&lt;br /&gt;
&lt;em&gt;1. Today’s mainstream developers who are used to C or Java like syntax wont find its Prolog-like syntax too friendly.&lt;/em&gt;&lt;br /&gt;
&lt;em&gt;&lt;br /&gt;
&lt;/em&gt;&lt;br /&gt;
This point, the syntax point, comes up all the time. The claim is that Erlangs syntax is too far away from “mainstream” languages, whatever that means. I don’t think the critique is warranted, but since we have alternative languages like &lt;a href="http://www.marianoguerra.com.ar/efene/"&gt;Efene&lt;/a&gt; and &lt;a href="http://reia-lang.org/"&gt;Reia&lt;/a&gt; there are a least &lt;em&gt;some&lt;/em&gt; people who think Erlang has a syntax problem, so it warrants discussion.&lt;br /&gt;
&lt;br /&gt;
Perhaps, one should be nuanced and hammer through the difference between &lt;a href="http://en.wikipedia.org/wiki/Syntax"&gt;syntax&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/Semantics"&gt;semantics&lt;/a&gt;. Syntax is, roughly, the rules for forming valid sentences in the programming languages. Whereas semantics roughly is the meaning of the language, what it denotes. In other words, syntax are rules for transforming a valid input text into an internal parse tree — semantics the rules for executing that parse tree, running the program.&lt;br /&gt;
&lt;br /&gt;
There is a tendency to focus more on Erlangs syntax than its semantics. I think this is partially wrong: the semantics shape the syntax and vice versa. I also have a hunch that people may claim a problem with the syntax of Erlang, where the point is really a misunderstanding of its semantics.&lt;br /&gt;
&lt;br /&gt;
Is Erlangs Prolog-like syntax unfriendly? I don’t think so! Erlang has extremely few syntax rules and they are quite consistent. The &lt;a href="https://github.com/erlang/otp/blob/dev/lib/stdlib/src/erl_parse.yrl"&gt;grammar&lt;/a&gt; is less than 500 lines. Contrast with the Ocaml parser 3 times as large. The Go programming language has a parser which is well above in size as well - I cannot imagine the parser for Java nor C be any smaller.&lt;br /&gt;
&lt;br /&gt;
The main objection is familiarity: “It doesn’t look like Java!” I think the point is somewhat moot. Python doesn’t look like Java. Neither does Ruby or Perl. Still programmers have no trouble picking up those languages. Before the C-style languages became dominant, programmers wrote Pascal, COBOL and Algol whose syntax is far from what we expect.&lt;br /&gt;
&lt;br /&gt;
I expect far more people have trouble with the unfamiliarity of the semantics. If you come from an imperative setting, you need time to wrap your head around functional programming styles and idioms. Yet, unfamiliar semantics should pose no problem either: Python, Javascript, PHP and Java all execute very differently if you look at them modulo imperative execution.&lt;br /&gt;
&lt;br /&gt;
&lt;em&gt;2. While the core language itself is small and easy to learn, the libraries within the language are inconsistent, incomplete and poorly documented.&lt;/em&gt;&lt;br /&gt;
&lt;em&gt;&lt;br /&gt;
&lt;/em&gt;&lt;br /&gt;
The Erlang/OTP libraries suffer from inconsistency having been built over time whenever there was a need for a new function. This is indeed unfortunate, but note this: apart from a few libraries which implement their functionality directly in the Erlang VM kernel, most libraries are written in pure Erlang and can be replaced easily. If you hate the &lt;code&gt;list&lt;/code&gt; module, you can write your own &lt;code&gt;lst&lt;/code&gt;.&lt;br /&gt;
&lt;br /&gt;
Some libraries are &lt;em&gt;de-facto deprecated&lt;/em&gt; as it is known they have certain limitations. The way Erlang tend to work however is that older modules known to have trouble are removed fairly slowly from the language - there may be a user out there, however poor that module is.&lt;br /&gt;
&lt;br /&gt;
I cannot agree with the bad documentation. Erlang has &lt;em&gt;excellent&lt;/em&gt; documentation. There a man-pages for every module, accessible with &lt;code&gt;erl -man lists&lt;/code&gt; for instance (provided your distribution of Erlang is correctly built) and we have &lt;a href="http://www.erlang.org/doc/apps/stdlib/index.html"&gt;several&lt;/a&gt; &lt;a href="http://erldocs.com/"&gt;online&lt;/a&gt; &lt;a href="http://www.gotapi.com/html"&gt;places&lt;/a&gt; where you can look up function definitions. In addition many modules have &lt;a href="http://www.erlang.org/doc/apps/mnesia/users_guide.html"&gt;users guides&lt;/a&gt; which you can use to get started quickly. There even is an &lt;a href="http://www.erlang.org/doc/efficiency_guide/users_guide.html"&gt;efficiency guide&lt;/a&gt; so you know how to write efficient code and there is a &lt;a href="http://erlang.se/doc/programming_rules.shtml"&gt;set of programming conventions&lt;/a&gt; with good advice on how to structure your programs.&lt;br /&gt;
&lt;br /&gt;
Usually the documentation of functions are rather good I think. If you find something which you think is poorly documented, I’d advice you to make a patch against the documentation and discuss the change with others. Improving documentation is more important than ranting on its inadequacy.&lt;br /&gt;
&lt;br /&gt;
&lt;em&gt;3. Only a few people have written production level codes and you rarely get to hear from them.&lt;/em&gt;&lt;br /&gt;
&lt;em&gt;&lt;br /&gt;
&lt;/em&gt;&lt;br /&gt;
I have written production level code in Erlang, namely a BitTorrent client good enough for everyday use. Our performance is currently as good as most other BitTorrent clients, CPU and memory-wise, despite we are writing the client in a “slow” language. I have also written programs professionally in Erlang - for the Web, but I am getting ahead of myself.&lt;br /&gt;
&lt;br /&gt;
I try to write about my experiences - in part to tell stories, in part to educate and encourage others to pick up the language. No programming language is a silver-bullet. But when your task is to write highly concurrent programs Erlang shines. And if you look at the usual protocols for distributed computing on the web, http-servers, xmpp-servers, ad-serving frameworks, payment processing systems, BitTorrent-clients, video-servers, and so on — you find that many of them are highly concurrent.&lt;br /&gt;
&lt;br /&gt;
Successful systems that just work will not catch headlines. A system that is shock-full of errors will. Many Erlang programs are running in companies with no open-source policy as well - don’t expect the programmers of those systems to &lt;em&gt;even be able&lt;/em&gt; to talk about what they do. It is a competitive advantage to keep the mouth shut.&lt;br /&gt;
&lt;br /&gt;
&lt;em&gt;4. I can’t imagine how you can organize large code-bases in Erlang or even work as team, and this doesn’t feel right to any OO programmer.&lt;/em&gt;&lt;br /&gt;
&lt;em&gt;&lt;br /&gt;
&lt;/em&gt;&lt;br /&gt;
Large Erlang programs are structured around the concepts of &lt;em&gt;applications&lt;/em&gt; and &lt;em&gt;releases&lt;/em&gt;. You write several isolated functional units, applications. Then you bundle these into a release which you can ship to the production environment. A typical application will provide an abstraction for something, be it running an HTTP server, talking to a database, controlling an external CPU-centered numerical program and so on.&lt;br /&gt;
&lt;br /&gt;
The organization of large programs hinges on API-design. You want to design your program such that each application has a small API used by the other parts of the program. There may thousands of code lines behind the wall of the API, yet the interface to the rest of the world is small.&lt;br /&gt;
&lt;br /&gt;
The trick of OO-languages is “abstraction is had by introducing another object”. If you take a look at the OO-design patterns, you will find that often a new object is introduced to mediate and solve an abstraction problem. This because the only way to abstract in those languages are to construct new objects (or classes, depending on lanuage).&lt;br /&gt;
&lt;br /&gt;
In Erlang, the mantra is “abstraction is had by introducing another process”. In other words, you can usually solve abstraction-problems by introducing a middle-man mediating process, store state in a separate process, split a computation between several processes and so on. The OO-property of &lt;em&gt;isolation&lt;/em&gt;, much important to structuring large programs, is present in the isolation of processes: you can’t go rummaging around inside the memory heap space of another process, you must ask it gently and nicely.&lt;br /&gt;
Naturally, this model has a design-pattern language as well and I know of several such. Remember this: “&lt;em&gt;In OO-languages state is kept in objects; in Erlang, state is kept in processes&lt;/em&gt;”.&lt;br /&gt;
&lt;br /&gt;
&lt;em&gt;5. Most of the performance matrices are one-sided, and are performed by people who have an interest in Erlang. I would love to see some independent analysis.&lt;/em&gt;&lt;br /&gt;
&lt;em&gt;&lt;br /&gt;
&lt;/em&gt;&lt;br /&gt;
In general, you should be wary of performance measurements where one does not fully understand the platforms they are working with. It is hard to make a program perform &lt;em&gt;better&lt;/em&gt; but it is extremely easy to make a program perform &lt;em&gt;worse&lt;/em&gt;. To improve a program you must understand the rules of the game you are playing. The rules used to speed up, e.g.&amp;nbsp;&lt;code&gt;node.js&lt;/code&gt; are much different from the rules used in Erlang. And that is different again from Ocaml, Scala, Java, Python, …&lt;br /&gt;
&lt;br /&gt;
Also, workarounds for problems tend to be vastly different. A recent blog post of mine lays bare a curious property of &lt;code&gt;node.js&lt;/code&gt; but the seasoned Node programmer understands how to work around it. He or she may deploy the &lt;a href="https://github.com/kriszyp/multi-node"&gt;multi-node&lt;/a&gt; for instance and it fixes a lot of the problems by using a single &lt;code&gt;accept()&lt;/code&gt; queue for several workers. This is a nice way to break the rules of the game to avoid a problem.&lt;br /&gt;
&lt;br /&gt;
Rather than thinking in terms of performance, I would argue you should think in terms of what your problem is. Erlang shines when a fully-preemptive, heavily concurrent process model is a good solution to your problem. It is powerful in that respect and it has the advantage it is a very mature system.&lt;br /&gt;
&lt;br /&gt;
&lt;em&gt;6. Its support for web-development is very primitive. With web frameworks like rails and grails, there is a lot of serious work for Erlang if it ever intends to go to that market.&lt;/em&gt;&lt;br /&gt;
&lt;em&gt;&lt;br /&gt;
&lt;/em&gt;&lt;br /&gt;
I don’t think this is true. Web frameworks like Rails or Grails only talk about half of the web world. Clients in modern systems tend to be Javascript-heavy and only go to the server for their RPC Ajax-like requests. In this world, you need a lot less tooling at the side of the server. There are many web framworks popping up for Erlang currently, but let me plug the &lt;a href="http://nitrogenproject.com/"&gt;nitrogen&lt;/a&gt; project.&lt;br /&gt;
&lt;br /&gt;
Yet, I think we will see much less need for web-frameworks as they were. We will need a new kind of framework which is much easier to work with server-side. And I think &lt;code&gt;node.js&lt;/code&gt; shows the server doesn’t need a lot of stuff to be effective.&lt;br /&gt;
&lt;br /&gt;
You should also think about the emerging alternatives to RDBMs data storage. There are systems such as &lt;a href="http://couchdb.apache.org/"&gt;couchdb&lt;/a&gt; and &lt;a href="http://www.basho.com/Riak.html"&gt;riak&lt;/a&gt;, which can cleverly bypass some of the usual Model-View-Controller pattern. I think we are in for a change in the way we do web development for the better and that Grails and Rails are a thing of the past if they don’t adapt to the new world (I am sure Rails will - but have to little experience with Grails to know if they stagnate or not).&lt;br /&gt;
&lt;br /&gt;
&lt;em&gt;7. Did I talk about Strings in Erlang? IO speed?&lt;/em&gt;&lt;br /&gt;
&lt;em&gt;&lt;br /&gt;
&lt;/em&gt;&lt;br /&gt;
This single item is a blog post worthy in itself. First the strings.&lt;br /&gt;
&lt;br /&gt;
A string in most languages is a sequence of bytes, pointed to by reference. In some languages the string is the central data you pass around and in some, it is the &lt;em&gt;only kind of data&lt;/em&gt; you could pass around. Haskell and Erlang most notably defines a string to be a list of characters and integers respectively. There is much good and bad to be said about this choice - but it hurts people who don’t understand the difference.&lt;br /&gt;
&lt;br /&gt;
Most web systems manipulate strings. The string is the ubiquitous data format: it stores integers, it stores floats, it stores XML documents, JSON, and such. The string is easy to transfer over a TCP/IP stream. It is no surprise that many languages center around string manipulation and are very effective at it. Perl is perhaps the ultimate string processor (apart from &lt;a href="http://crm114.sourceforge.net/"&gt;crm114&lt;/a&gt;, naturally).&lt;br /&gt;
&lt;br /&gt;
The ubiquity of strings are also their Achilles-heel. The type information they carry is &lt;em&gt;weak&lt;/em&gt; — &lt;em&gt;nonexistent&lt;/em&gt; to be precise. To manipulate a string in any statically typed language, Java, Ocaml, Haskell, etc., you need to transform it into an internal format. You process the string to an Object-hierarchy or an algebraic data type — and then you throw the string away! The new representation has all the advantages: it is typed, it can carry additional information in object state, and it can make &lt;a href="http://vimeo.com/14313378"&gt;illegal states unrepresentable&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
You should never ever work directly with strings if performance matter. Even simple things like string comparisons may be fairly expensive (if the pointer comparison says different), whereas an atom comparison is not. The world of programming is more complex than just shoving every piece of data into a string.&lt;br /&gt;
&lt;br /&gt;
Another weakness of the string is that the representation only answers to query by regular expression, recursive descent or LALR(1)-parsing. Some languages are very good at the former, regex query, but Erlang is not one of them since regular expressions are not built into the syntax and semantics.&lt;br /&gt;
&lt;br /&gt;
So the &lt;strong&gt;first virtue of the Erlang programmer&lt;/strong&gt;: Convert a string as fast as possible into an erlang-&lt;code&gt;term()&lt;/code&gt; and then manipulate the term. Only work with crappy weakly-typed strings at the border of your application. An Erlang application should not constrain itself to work with only a single data type, namely strings!&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;The second virtue&lt;/strong&gt; follow fast: If your string is large, use a &lt;code&gt;binary()&lt;/code&gt; for effective storage and sharing. The binary representation, like the &lt;code&gt;ByteString&lt;/code&gt; in Haskell, is as space efficient as C and it can be pattern matched if needed.&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;The third virtue&lt;/strong&gt; is: Know thine &lt;a href="http://prog21.dadgum.com/70.html"&gt;iolists&lt;/a&gt;. When you construct strings in Erlang, you are &lt;em&gt;not&lt;/em&gt; to build a sequence of characters! You should be building a tree of small string-like fragments, binaries, other trees, lists and so on. The output functions know how to effectively walk the tree and stream it to the output device.&lt;br /&gt;
&lt;br /&gt;
The IO performance of Erlang is pretty good. I easily had some early tests in Etorrent moving 700 megabit on a single 1.2Ghz Pentium M CPU. Without any optimization at all.&lt;br /&gt;
&lt;br /&gt;
Yet, it is important to notice that IO in Erlang is abstracted by default and this makes it a tad slower than what it can to be. The abstraction is rather nice and has to do with distribution. You can access a socket or file on another machine as if it is locally accessed. But this neat abstraction naturally has an overhead. Of course it is easy to build a primitive which throws away that abstraction if needed. And that will definitely run as fast as any other language.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-94128600604980725?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/94128600604980725/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=94128600604980725' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/94128600604980725'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/94128600604980725'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2010/12/response-to-erlang-overhyped-or.html' title='A response to &quot;Erlang - overhyped or underestimated&quot;'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-5154591010245091297</id><published>2010-12-14T08:45:00.001-08:00</published><updated>2010-12-15T16:28:27.428-08:00</updated><title type='text'>Differences between Node.js and Erlang</title><content type='html'>&lt;div id="differences-between-node.js-and-erlang"&gt;&lt;h1&gt;Differences between Node.js and Erlang&lt;/h1&gt;Suppose we have a canonical ping/pong server written in Node,&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;var sys = require("sys");
var http = require("http");
http.createServer(function (req, res) {
  res.writeHead(200, {"Content-Type": "text/plain"});
  res.end("Hello, World\n");
}).listen(8124, "127.0.0.1");
sys.puts("Server running at http://localhost:8124");
&lt;/code&gt;&lt;/pre&gt;We can run this server easily and test it from the command line:&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;jlouis@illithid:~$ curl http://localhost:8124
Hello, World
&lt;/code&gt;&lt;/pre&gt;And it does what we expect. Now suppose we do something &lt;em&gt;silly&lt;/em&gt;. We make a tiny change to the Javascript code:&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;var sys = require("sys");
var http = require("http");
http.createServer(function (req, res) {
  res.writeHead(200, {"Content-Type": "text/plain"});
  res.end("Hello, World\n");
  while(true) { // Do nothing
  }
}).listen(8124, "127.0.0.1");
sys.puts("Server running at http://localhost:8124");
&lt;/code&gt;&lt;/pre&gt;Now, the first invocation of our test works, but the second hangs:&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;jlouis@illithid:~$ curl -m 10 http://localhost:8124
Hello, World
jlouis@illithid:~$ curl -m 10 http://localhost:8124
curl: (28) Operation timed out after 10001 milliseconds with 0 bytes received
&lt;/code&gt;&lt;/pre&gt;This should not surprise anybody. What we have here illustrated should be a common knowledge. Namely that Node is not &lt;em&gt;preemptively multitasking&lt;/em&gt; but is asking each event to &lt;em&gt;cooperate&lt;/em&gt; by yielding to the next one in turn.&lt;br /&gt;
The example was silly. Now, suppose we have a more realistic example where we do work, but it completes:&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;var sys = require("sys");
var http = require("http");
http.createServer(function (req, res) {
res.writeHead(200, {"Content-Type": "text/plain"});
  x = 0;
  while(x &amp;lt; 100000000) { // Do nothing
    x++;
  }
res.end("Hello, World " + x + "\n");
}).listen(8124, "127.0.0.1");
sys.puts("Server running at http://localhost:8124");
&lt;/code&gt;&lt;/pre&gt;We introduce a loop which does some real work. And then we arrange for it to be non-dead by requiring it in the output. Our server will now still return, but it will take some time before it does so.&lt;br /&gt;
Let us siege the server:&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;jlouis@illithid:~$ siege -l -t3M http://localhost:8124 
** SIEGE 2.69
** Preparing 15 concurrent users for battle.
The server is now under siege...
[..]
&lt;/code&gt;&lt;/pre&gt;For three minutes, we hammer the server and get a CSV file, which we can then load into &lt;code&gt;R&lt;/code&gt; and process.&lt;br /&gt;
&lt;div id="erlang-enters..."&gt;&lt;h2&gt;&lt;br /&gt;
&lt;/h2&gt;&lt;h2&gt;Erlang enters…&lt;/h2&gt;For comparison, we take &lt;code&gt;Mochiweb&lt;/code&gt;, an Erlang webserver. We do not choose it specifically for its speed or its behaviour. We choose it simply because it is written in Erlang and it will context switch preemptively.&lt;br /&gt;
The relevant part of the Mochiweb internals are this:&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;count(X, 0) -&amp;gt; X;
count(X, N) -&amp;gt; count(X+1, N-1).

loop(Req, _DocRoot) -&amp;gt;
  "/" ++ Path = Req:get(path),
  try
    case Req:get(method) of
      Method when Method =:= 'GET' -&amp;gt;
    X = count(0, 100000000),
    Req:respond({200, [], ["Hello, World ", integer_to_list(X), "\n"]});
      [..]
&lt;/code&gt;&lt;/pre&gt;It should be pretty straightforward. We implement the counter as a tail-recursive loop and we force its calculation by requesting it to be part of the output.&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;erl -pa deps/mochiweb/ebin -pa ebin
Erlang R14B02 (erts-5.8.3) [source] [64-bit] [smp:2:2]
[rq:2] [async-threads:0] [hipe] [kernel-poll:false]
1&amp;gt; application:start(erlang_test).
{error,{not_started,crypto}}
2&amp;gt; application:start(crypto).     
ok
3&amp;gt; application:start(erlang_test).
** Found 0 name clashes in code paths 
ok
4&amp;gt; 
&lt;/code&gt;&lt;/pre&gt;Notice that we get both my CPUs to work here automatically. But performance is not the point I want to make.&lt;br /&gt;
Again, we lay siege to this system:&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;jlouis@illithid:~$ siege -l -t3M http://localhost:8080 | tee erlang.log
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div id="enter-r"&gt;&lt;h2&gt;Enter R&lt;/h2&gt;We can take these data and load them into R for visualization:&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; a &amp;lt;- read.csv("erlang.log", header=FALSE);
&amp;gt; b &amp;lt;- read.csv("node.js.log", header=FALSE);
&amp;gt; png(file="density.png")
&amp;gt; plot(density(b$V3), col="blue", xlim=c(0,40), ylim=c(0, 0.35));
lines(density(a$V3), col="green")
&amp;gt; dev.off()
&amp;gt; png("boxplot.png")
&amp;gt; boxplot(cbind(a$V3, b$V3))
&amp;gt; dev.off()
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div id="discussion"&gt;&lt;h2&gt;Discussion&lt;/h2&gt;What have we seen here? We have a situation where Node.js has a much more erratic response time than Erlang. We see that while some Node.js responses complete very fast (a little more than one second) there are also responses which take 29.5 seconds to complete. The summary of the data is here for Node.js:&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; summary(b$V3)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  1.040   6.328  13.580  13.940  20.940  29.590 
&lt;/code&gt;&lt;/pre&gt;And for Erlang:&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; summary(a$V3)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
   9.87   11.21   12.24   12.21   13.16   15.32 
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
The densities are (green is Erlang, blue is Node.js)&lt;br /&gt;
&lt;div class="figure"&gt;&lt;img alt="density plot" src="http://posterous.com/getfile/files.posterous.com/jlouis/UKDivs7qIjak8q2hvTUNXOHlq05lxmR8gzQUjG6fZSvtQEkpHLo2HYq3ncf5/density.png" title="Density" /&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;/div&gt;And for completion, a boxplot:&lt;br /&gt;
&lt;div class="figure"&gt;&lt;img alt="boxplot" src="http://posterous.com/getfile/files.posterous.com/jlouis/oLBIz4iGetc2LIIYxRO2oDVzJhY5xx6pYnH63BUs3MWdPmDU8DJ8ktmHjfTS/boxplot.png" title="Boxplot" /&gt;&lt;br /&gt;
&lt;div class="caption"&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;/div&gt;&lt;/div&gt;This is a result of Erlang preemptively multitasking the different processes so its responses all come around the same time. You can’t really use the &lt;em&gt;mean&lt;/em&gt; for anything: Erlang ran 2 CPUs whereas Node.js only ran one. But the kernel density plot clearly shows how Erlang stably responds while the response times of Node.js is erratic.&lt;br /&gt;
Does this mean Node.js is bad? No! Most node.js programs will not blindly loop like this. They will call into a database, make another web request or the like. When they do this, they will allow other requests to be processed in the event loop and the thing we have seen here is nonexistent. It does however show that if a Node.js request is expensive in the processing, it will block other requests from getting served. Contrast this with Erlang, where cheap requests will get through instantly as soon we switch context preemptively.&lt;br /&gt;
It also hints you need to carry out histogram plots for your services (kernel density plots are especially nice for showing how the observations spread out). You may be serving all requests, but how long time does it take to serve the slowest one? A user might not want to wait 30 seconds on a result, but he may accept 10 seconds.&lt;/div&gt;&lt;div id="conclusion"&gt;&lt;h2&gt;&lt;br /&gt;
&lt;/h2&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;My main goal was to set out and exemplify a major difference in how a system like Node.js handles requests compared to Erlang. I think I have succeeded. It underpins the idea that you need to solve problems depending on platform. In Node.js, you will need to break up long-running jobs manually to give others a chance at the CPU (this is essentially cooperative multitasking). In Erlang, this is not a problem — and a single bad process can’t hose the system as a whole. On the other hand, I am sure there are problems for which Node.js shines and it will have to be worked around in Erlang.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;EDIT: &lt;/b&gt;Minor spelling correction.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-5154591010245091297?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/5154591010245091297/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=5154591010245091297' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/5154591010245091297'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/5154591010245091297'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2010/12/differences-between-nodejs-and-erlang_14.html' title='Differences between Node.js and Erlang'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-948295377971955934</id><published>2010-11-20T14:33:00.000-08:00</published><updated>2010-11-20T14:41:12.972-08:00</updated><title type='text'></title><content type='html'>&lt;div id="tracing-erlang-programs-for-fun-and-profit"&gt;&lt;h1&gt;Tracing Erlang programs for fun and profit&lt;/h1&gt;&lt;p&gt;One of the neat things about Erlang is its &lt;em&gt;instrumentation&lt;/em&gt; capability. You can instrument programs to tell you interesting things about what is happening in the program. This blog post is about a tool by Mats Cronqvist, &lt;strong&gt;redbug&lt;/strong&gt;.&lt;/p&gt;&lt;p&gt;Redbug can be downloaded from &lt;a href="https://github.com/massemanet/eper"&gt;github&lt;/a&gt; and is part of Mats’ &lt;em&gt;eper&lt;/em&gt; suite of tools. Installing the tool is easy. I recommend to set the &lt;em&gt;$ERL_LIBS&lt;/em&gt; environment to something. Mine is set at:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;   jlouis@illithid:~$ env | grep ERL_LIBS
  ERL_LIBS=:/home/jlouis/lib/erlang/lib
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;so I can just drop Erlang libraries I use on-and-off into that directory and they will be picked up by any Erlang I run. It is not a good solution when you are building software with dependencies, but for smaller tools used by you, like eper or Erlang QuickCheck, this mechanism is really good.&lt;/p&gt;&lt;p&gt;Installing &lt;em&gt;eper&lt;/em&gt; should be fairly simple.&lt;/p&gt;&lt;div id="redbug-invocation"&gt;&lt;h2&gt;Redbug invocation&lt;/h2&gt;&lt;p&gt;Redbug can either be called from the command line. There is a &lt;code&gt;redbug&lt;/code&gt; shell script you can call or you can call it from the Erlang shell. The main invocation is like this,&lt;/p&gt;&lt;pre&gt;&lt;code&gt;   redbug:start(TimeOut, MessageCount, MS)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;where &lt;code&gt;TimeOut&lt;/code&gt; is a timeout in milliseconds at which redbug ceases to operate, &lt;code&gt;MessageCount&lt;/code&gt; sets a limit to how many reports redbug is going to make, and &lt;code&gt;MS&lt;/code&gt; is a match-spec matching trace points in the program. There are several possible ways to write &lt;code&gt;MS&lt;/code&gt; and I am only going to give some simple examples to get you started. The tool is self-documenting and you can call&lt;/p&gt;&lt;pre&gt;&lt;code&gt;   redbug:help().
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;from a shell and get the whole story.&lt;/p&gt;&lt;p&gt;The timeout and messagecount limitation is very useful. Erlang has a built-in tracer on which redbug is built. But contrary to the built-in tracer, redbug protects the running system by the limitations. You can’t hose the system by accidentally set a specification which hoards all of the resources on the Erlang node.&lt;/p&gt;&lt;p&gt;A typical MS is written like &lt;code&gt;{erlang,now,[return,stack]}&lt;/code&gt;. This states we are tracing for the &lt;code&gt;erlang:now&lt;/code&gt; call of &lt;em&gt;any&lt;/em&gt; arity. When we match, we want the current stack printed and we want the return value of the call:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;  22&gt; redbug:start(100000, 2, {erlang,now,[return,stack]}).
 ok
 23&gt; erlang:now().

 22:40:12 &lt;{erlang,apply,2}&gt; {erlang,now,[]}
 {1290,289212,474520}
  shell:eval_loop/3
  shell:eval_exprs/7
  shell:exprs/7

 22:40:12 &lt;{erlang,apply,2}&gt; {erlang,now,0} -&gt; {1290,289212,474520}
 quitting: msg_count
 24&gt; erlang:now().
 {1290,289219,57040}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Notice the &lt;code&gt;quitting: msg_count&lt;/code&gt; which states after two messages from redbug, it will cease to do any further tracing. In general, the MS can also be written like, e.g., &lt;code&gt;{module,function,[return,{'_', 42}]}&lt;/code&gt; stating that we accept any call matching &lt;code&gt;module:function(_, 42)&lt;/code&gt; and gets its return stack.&lt;/p&gt;&lt;/div&gt;&lt;div id="a-real-world-bug-hunt"&gt;&lt;h2&gt;A real-world bug hunt&lt;/h2&gt;&lt;p&gt;Redbug means you don’t in general have to add a lot of debug-printing to your Erlang code. Rather, it is easier to probe systematically with redbug on a running system. I was wondering why a recent patch in etorrent seemed to work incorrectly, so we go hunting:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;(etorrent@127.0.0.1)26&gt; redbug:start(10000, 2, {etorrent_choker, split_preferred, [return]}).
ok
22:47:32 &lt;etorrent_choker&gt; {etorrent_choker,split_preferred,[[]]}
22:47:32 &lt;etorrent_choker&gt; {etorrent_choker,split_preferred,1} -&gt; {[],[]}
quitting: msg_count
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This choker call should not be passed the empty list, so we look into the code and find that the rechoke_info builder right before it is odd:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;(etorrent@127.0.0.1)29&amp;gt; redbug:start(10000, 30, {etorrent_choker, build_rechoke_info, [return]}).
[..]
22:49:22 &lt;etorrent_choker&gt; {etorrent_choker,build_rechoke_info,2} -&gt; []
22:49:22 &lt;etorrent_choker&gt; {etorrent_choker,build_rechoke_info,1} -&gt; []
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So - both &lt;code&gt;build_rechoke_info/1&lt;/code&gt; and &lt;code&gt;build_rechoke_info/2&lt;/code&gt; return the empty list. Something is wrong inside that function. Since the function is looking up data in other modules, we trace each of the module lookups:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;(etorrent@127.0.0.1)29&gt; redbug:start(10000, 10, {etorrent_table, get_peer_info, [return]}).
[..]
22:51:42 &lt;etorrent_choker&gt; {etorrent_table,get_peer_info,[&lt;0.5759.0&gt;]}
22:51:42 &lt;etorrent_choker&gt; {etorrent_table,get_peer_info,1} -&gt; {peer_info,
                                                              leeching,17}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Nope, that looks right, on to the next:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;(etorrent@127.0.0.1)30&gt; redbug:start(10000, 15, {etorrent_rate_mgr, fetch_send_rate, [return]}).
ok
22:53:12 &lt;etorrent_choker&gt; {etorrent_rate_mgr,fetch_send_rate,[4,&lt;0.3919.0&gt;]}
22:53:12 &lt;etorrent_choker&gt; {etorrent_rate_mgr,fetch_send_rate,2} -&gt; none
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Oh, a return of &lt;code&gt;none&lt;/code&gt; is wrong here! Why does it return &lt;code&gt;none&lt;/code&gt;? The call looks fine, but we are looking up data in an ETS table…&lt;/p&gt;&lt;p&gt;At this point, we can use another nice little Erlang tool, &lt;code&gt;tv&lt;/code&gt; or the &lt;em&gt;Table Viewer&lt;/em&gt;. We run:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;tv:start().
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;find the problematic table and inspect an element, which turned out to contain the wrong information. Thus, the hunt is all about figuring out why the wrong information is entered into the table in the first place.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;(etorrent@127.0.0.1)35&gt; redbug:start(10000, 5, {ets,insert,[stack,{etorrent_send_state, {rate_mgr, {'_', undefined}, '_', '_'}}]}).
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Basically, we have now constricted the output to exactly the wrong types of calls. And the culprit function is easily found in the callers stack.&lt;/p&gt;&lt;p&gt;Further digging shows the problem to be a race at the &lt;em&gt;gproc&lt;/em&gt; process table which can be fixed by asking &lt;em&gt;gproc&lt;/em&gt; to await the appearance of a given key.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-948295377971955934?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/948295377971955934/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=948295377971955934' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/948295377971955934'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/948295377971955934'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2010/11/tracing-erlang-programs-for-fun-and.html' title=''/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-3678705858299088809</id><published>2010-11-13T13:49:00.000-08:00</published><updated>2010-11-13T16:12:09.752-08:00</updated><title type='text'>On Erlang, State and Crashes</title><content type='html'>&lt;div id="on-erlang-state-and-crashes"&gt;&lt;h1&gt;On Erlang, State and Crashes&lt;/h1&gt;&lt;p&gt;There are two things which are ubiquitous in Erlang:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;A Process has an internal state.&lt;/li&gt;&lt;li&gt;When the process crashes, that internal state is gone.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;These two facts pose some problems for new Erlang programmers. If my state is gone, then what should I then do? The short answer to the question is that some other process must have the state and provide the backup, but this is hardly a fulfilling answer: It is turtles all the way down. Now, that other process might die, and then &lt;em&gt;another&lt;/em&gt; beast of a process must have the state. And this observation continues ad infinitum. So what is the Erlang programmer to do? This is my attempt at answering the question.&lt;/p&gt;&lt;div id="state-classification"&gt;&lt;h2&gt;State Classification&lt;/h2&gt;&lt;p&gt;The internal state of an Erlang process can naturally be classified. First, state has different value. State related to the current computation residing on the stack may not be important at all after a process crash. It crashed for a reason and chance are that the exact same state will bring down the process again with the same error. The same observation might apply to some internal state: It is like a scratchpad or a blackboard: when the next lecture starts, it can be erased because it has served its purpose.&lt;/p&gt;&lt;p&gt;Next is static state. If a process is governing a TCP/IP connection that process should probably connect to the same TCP/IP Address/Port pair if it crashes and is restarted. We call that kind of data configuration or &lt;em&gt;static&lt;/em&gt; data. It is there, but it is not meant to change over the course of the application, or only change rarely.&lt;/p&gt;&lt;p&gt;Finally our crude classification of state has &lt;em&gt;dynamic&lt;/em&gt; data. This class is the data we generate over the course of the running program, get from user input, create because other programs communicate with us and so on. The class can be split into two major components: State we can compute from other data and state we cannot compute. The computable state is somewhat less of a problem. We can basically just recompute it after a crash, so the real problem is the other kind of user/program-supplied information.&lt;/p&gt;&lt;p&gt;In other words, we have three major kinds of state: &lt;em&gt;scratchpad, static and dynamic&lt;/em&gt;.&lt;/p&gt;&lt;/div&gt;&lt;div id="the-error-kernel"&gt;&lt;h2&gt;The Error Kernel&lt;/h2&gt;&lt;p&gt;Erlang programs have a concept called the &lt;em&gt;error kernel&lt;/em&gt;. The kernel is the part of the program which &lt;em&gt;must&lt;/em&gt; be correct for its correct operation. Good Erlang design begins with identifying the error kernel of the system: What part &lt;em&gt;must&lt;/em&gt; not fail or it will bring down the whole system? Once you have the kernel identified, you seek to make it minimal. Whenever the kernel is about to do an operation which is dangerous and might crash, you "outsource" that computation to another process, a dumb slave worker. If he crashes and is killed, nothing really bad has happened - since the kernel keeps going.&lt;/p&gt;&lt;p&gt;Identifying the kernel plugs the "turtles all the way down" hole. As soon as the kernel is hit, we assume correctness. But since the kernel is small, the &lt;em&gt;trusted computing base&lt;/em&gt; of our program is likewise. We only need to trust a small part of the program, and that part is also fairly simple.&lt;/p&gt;&lt;p&gt;A visualization is this: A program is a patchwork of small squares. Some of the squares are red, and these are the "error kernel". Most (naively implemented) imperative programs are mostly red, save for a few squares. These are the squares where exceptions are handled explicitly and the error is correctly mitigated. The kernel is thus fairly large. In contrast, robustness-aware Erlang programs have few red squares - most of the patchwork is white. It is a design-goal to get as few red squares as possible. It is achieved by delegating dangerous work to the white areas so a crash does not affect the kernel.&lt;/p&gt;&lt;/div&gt;&lt;div id="handling-the-state-classes"&gt;&lt;h2&gt;Handling the state classes&lt;/h2&gt;&lt;p&gt;Each class must be handled differently. First there is the scratchpad/blackboard class. If a process crashes, the class is interesting because it contains the stack trace and usually the data which tells a story - namely &lt;em&gt;how&lt;/em&gt; and &lt;em&gt;why&lt;/em&gt; the process crashed. We usually export this data via SASLs error logger, so we can look at a crash report and understand what went wrong. After all, the internal state is gone after the crash report is done and logged.&lt;/p&gt;&lt;p&gt;Next, there is the static class. The simplest thing is to have another process feed in the static data. This can be done by, among others, the supervisor, by asking an ETS table, by asking GProc (if you use gproc in your system), by asking another process or by discovery through the call &lt;code&gt;application:get_env/2&lt;/code&gt;. It is important to note just how static the data is - you have few options with differing advantages and disadvantages. Which one to choose depends on how much the data is going to change.&lt;/p&gt;&lt;p&gt;Finally, the fully dynamic data is the nasty culprit. If you can recompute the data, you are lucky. As an example from my etorrent application, each peer has a dynamic table of what parts of a torrent file the given peer has. So the controlling process has an internal table of this information. But if we crash and reconnect to the peer, the virtue of the bittorrent protocol will send us this information again. So that information is hardly worth keeping around. Other times, you can simply recalculate the information when your process restarts, and that is almost never a problem either.&lt;/p&gt;&lt;p&gt;So what about the user supplied data? This is where the error kernel comes in. You need to &lt;em&gt;protect&lt;/em&gt; data which you can not reconstruct. You protect it by shoving it into the error kernel and keep some simple state maintenance processes there to handle the state. A word of warning though: If your state is corrupted, it means that processes basing their work on the state will do something wrong. To mitigate this, it is important to make some general sanity checking of your data. Make it a priority to check your data for invariants if you find them. And don't blindly trust non-error-kernel parts of the system.&lt;/p&gt;&lt;p&gt;If a process crashes, you should definitely think how much of its internal state you want to recycle. If you recycle everything you risk hitting the exact same bug again and crash. Rather, there may be a benefit to only recycling parts of the internal state.&lt;/p&gt;&lt;/div&gt;&lt;div id="the-next-step:-onion-layered-error-kernels"&gt;&lt;h2&gt;The next step: Onion-layered Error kernels&lt;/h2&gt;&lt;p&gt;The next logical step up, is to recognize that the error kernel is not discrete. You want to regard the error kernel as an onion. Whenever you peel off a layer, you get a step closer to the trusted computing base of the application. Then your system design is to push down state maintenance to the outermost layer in the onion where it still makes sense. This in effect protects one part of the application from others. In Etorrent, we can download multiple torrent files at the same time. If one such torrent download fails, there is no reason it should affect the other torrent downloads. We can add a layer to the onion: Some state which is local to the torrent is kept in a separate supervisor tree - to mitigate the error if that part fails.&lt;/p&gt;&lt;p&gt;The net effect is program robustness: A bug in the program will suddenly need perseverance. It has to penetrate several layers in the onion before it can take the full program down. And if the Erlang system is well designed, even the most grave bugs can only penetrate so far before the stopping power of the onion layers brings it to a halt.&lt;/p&gt;&lt;p&gt;Furthermore, it underpins a mantra of Erlang programs: Small bugs have small impact. They won't even penetrate the first layer. And they will hardly be a scratch in the fabric of computing.&lt;/p&gt;&lt;p&gt;(Aside: Good computer security engineering use the same onion-layered model. There are strong similarities between protecting a computer system against a well-armed intruder and protecting a program against an aggressive, persistent, dangerous and maiming bug. End of Aside)&lt;/p&gt;&lt;p&gt;&lt;b&gt;EDIT: &lt;/b&gt;smaller language changes where my first post was a bit drafty.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-3678705858299088809?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/3678705858299088809/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=3678705858299088809' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/3678705858299088809'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/3678705858299088809'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2010/11/on-erlang-state-and-crashes.html' title='On Erlang, State and Crashes'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-1026884908242971296</id><published>2010-10-10T12:08:00.000-07:00</published><updated>2010-10-10T13:10:17.170-07:00</updated><title type='text'>On being obsessed with concurrency</title><content type='html'>Grace Hopper on multiple occasions explained the length of a nanosecond with a piece of wire. The length of the wire was exactly the distance light would travel in a nanosecond. See [1] for one such occasion.&lt;div&gt;
&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;While Grace was using the method to describe the delay in satellite communication and why computers need to get smaller, it turns out it is more relevant than ever today.  We are officially over the era of computing where people glued together libraries to form programs. Today, virtually every new application built is &lt;i&gt;distributed.&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;
&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;
&lt;/i&gt;&lt;/div&gt;&lt;div&gt;The problem is that if you think latency due to disk seeks are slow, then imagine reaching a machine at the other end of the world - the delay is high. From here, my delay to yahoo.com is around 200ms, much more than the average seek time on an old harddisk. There is a common trick in the high-performance computing world to battle latency: &lt;i&gt;latency hiding. &lt;/i&gt;While waiting for a message to pass through the slow network, you do something else. And then when data from the message &lt;i&gt;is &lt;/i&gt;in grave need to continue the program, you gamble that it already arrived. The same trick has been used in operating systems for years while waiting on the disk to return data: run another program in the meantime.&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;&lt;div&gt;And this is why any modern programming language &lt;i&gt;must &lt;/i&gt;tackle concurrent operations. From now on, most programs will be distributed. The client program will be because they live on mobile phone-sized systems and they have to pull in data from multiple sources. The server program will be because distribution is key to scaling and redundancy. In short, any program will have a situation where getting data amounts to asking another system for them -- and then handling the inherent latency present in the communication. The limit of a computer from here on out will not be in the amount of instructions it can retire successfully on its cores. Rather, it will be the amount of communication it can perform and how well it deals with it. On the memory bus. On the network. To the satellite.&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;I am making a bet: Distribution will be &lt;i&gt;huge&lt;/i&gt; and will be &lt;i&gt;solved&lt;/i&gt; by message passing concurrency. That is, I claim we already have the necessary tools in the toolbox to tackle the problem. There is not going to be the concurrent doomsday where the world curls up in a corner and deadlocks. There is not going to be a parallel doomsday revolution either. If the internet has told us anything it should be that we can handle the problems which will come forth to rear their ugly heads (and breath fire). The reason I am betting on message passing concurrency is that it is easy to program and fast enough for a 200ms round trip in most cases. The amount of nanosecond wires utterly dwarfs the price we pay to pass a message.&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;I am making another bet as well: &lt;i&gt;parallellism &lt;/i&gt;is not going to be as &lt;i&gt;huge &lt;/i&gt;as we think it is. We have relied for years on our computing technology to be faster every other year -- and this low hanging fruit is not there anymore. But it disguised another trend with even greater consequences: computers keep getting smaller and smaller. My mobile phone has the computing power of a State-of-the-art computer in 2001-2002. Imagine that in 8 years! It is not about splitting the computation up so it can run on a single machine with many cores anymore. It is about splitting the computation so it can run on many machines with many cores.&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;Today is the 10/10/10 but the day is only special in the calendar. The change did not happen overnight. There has been a slow crawl towards a more distributed world for some years. But undoubtedly, the mobile devices will propel us with full force into the new world order.&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;-- All Hail! Think concurrently!&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;[1] &lt;a href="http://www.youtube.com/watch?v=57bfxsiVTd4"&gt;http://www.youtube.com/watch?v=57bfxsiVTd4&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-1026884908242971296?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/1026884908242971296/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=1026884908242971296' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/1026884908242971296'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/1026884908242971296'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2010/10/on-being-obsessed-with-concurrency.html' title='On being obsessed with concurrency'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-9098078301257594636</id><published>2010-05-23T05:55:00.000-07:00</published><updated>2010-05-23T06:15:23.617-07:00</updated><title type='text'>Adding support for more than 1024 files to etorrent.</title><content type='html'>Some torrent files contain a humongous amount of files. Thousands. This is one of the problems you have to cope with as a client-writer and I plan to take care of both etorrent and combinatorrent. However, the solution I've adopted for etorrent is sinisterly beautiful, so I decided to write it down.&lt;div&gt;
&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;The Problem&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;Open files are limited on UNIX systems. This is to protect different applications against each other and to circumvent an eventual resource exhaustion on the system. A typical limit is 1024 files, or fewer in some cases. In etorrent, a file is governed by a process which plays the role of that file. Whenever you want to do a file operation on that file, you get hold of the process Pid and send it a message. Simple.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;Resources are limited by a timeout in these file processes. When a file has not been in use in 60 seconds, the process governing it terminates and frees up the resources on that file. It works reasonably well. The problem, however, is that some torrents have more files than the file descriptor limit. When we check the file upon starting up, we unfortunately open more than 1024 and then hit the limit.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;The Solution&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;The solution is deceptively simple. We add a janitor process to the game. Whenever a new file is opened the janitor gets informed and the file process enters itself into an ETS table. Whenever we do an operation on the file a timestamp is bumped in the ETS table. This goes on and on; if a process dies, a monitor in the janitor cleans out the entry from the ETS table.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;Now, whenever a new file is opened we check the size of the table against a high watermark, 128 by default. If more processes are opened, we extract the full table and order it by last bump. Thus, the first elements in the resulting list are the processes which have been used the farthest back in time. We then ask enough of these to terminate to bring ourselves back under a low watermark - ensuring we won't be hitting the resource collection all the time we add a new file system process to the game.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;Updating the ETS table is expected to be rather cheap. The table is public, so each file governing process maintains its own entry. I don't think they will spend much time waiting for each other on the table. And if they do, there is always {write_concurrency, true} we can set on the table.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-9098078301257594636?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/9098078301257594636/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=9098078301257594636' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/9098078301257594636'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/9098078301257594636'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2010/05/adding-support-for-more-than-1024-files.html' title='Adding support for more than 1024 files to etorrent.'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-2438846119259619420</id><published>2010-04-26T15:01:00.000-07:00</published><updated>2010-04-26T16:51:01.800-07:00</updated><title type='text'>Haskell vs. Erlang for bittorent clients</title><content type='html'>&lt;div id="haskell-vs.erlang"&gt;&lt;h1&gt;Haskell vs. Erlang&lt;/h1&gt;&lt;p&gt;Since I wrote a bittorrent client in both Erlang and Haskell, etorrent and combinatorrent respectively, I decided to put up some bait. This might erupt in a language war and “My language is better than yours”, but I feel I am obligated to write something subjective. Here is to woes of programming in Haskell and Erlang.&lt;/p&gt;&lt;p&gt;Neither Haskell, nor Erlang was a first language for me. I have programmed serious programs in C, Standard ML, Ocaml, Python, Java and Perl; tasted the cake of Go, Javascript, Scheme and Ruby; and has written substantial stuff in Coq and Twelf. I love static type systems, a bias that will rear its ugly head and breathe fire.&lt;/p&gt;&lt;p&gt;I have written Haskell code seriously since 2005 and Erlang code seriously since 2007. I have programmed functionally since 1997 or so. My toilet reading currently is “Categories for the working mathematician” by Mac Lane. Ten years ago it was “ML for the working programmer” by Paulson.&lt;/p&gt;&lt;p&gt;Enough about me.&lt;/p&gt;&lt;div id="caveats:"&gt;&lt;h2&gt;Caveats:&lt;/h2&gt;&lt;p&gt;With any language war material follows a disclaimer and a healthy dose of caveats. This is subjective. You have to live with it being subjective. My writing can’t be objective and colorful at the same time. And I like colors in my life. Also, it is no fun reading a table listing the comparison. Rather, I will try to make it into a good foil duel with attacks, parries, guards, pierces, bananas, and barbed wire.&lt;/p&gt;&lt;p&gt;I built etorrent in Erlang first and combinatorrent in Haskell second. Hence, the 2nd time around, with the sole goal of redoing the functionality of etorrent was much easier and could proceed much faster. The Erlang code is slightly fattier at 4.2K lines versus 3.6K lines of Haskell (SLOCs). The performance of the two clients is roughly equal, but more time was spent at optimizing the Haskell code.&lt;/p&gt;&lt;p&gt;My hypothesis is this: The Erlang VM is much more optimized at the IO layer than the current IO layer I use in GHC (specifically, the way incoming data is handled allocates more memory. This might change in the future do to a new IO layer). GHC kills the Erlang VM for everything else though, perhaps including message passing.&lt;/p&gt;&lt;p&gt;Also, the quality of the Erlang code could be better, relatively compared to the Haskell code.&lt;/p&gt;&lt;p&gt;Enough!&lt;/p&gt;&lt;p&gt;Enough with the caveats!&lt;/p&gt;&lt;/div&gt;&lt;div id="haskell-cons:"&gt;&lt;h2&gt;Haskell cons:&lt;/h2&gt;&lt;p&gt;What weighs against using Haskell for the project? First is laziness. Sometimes you want your code to be strict and sometimes lazy. In combinatorrent, we do some statistics which we don’t really need to calculate unless we want to present them. Stuff like bytes uploaded and downloaded for instance. Since you do not necessarily ask for these statistics, the compiler is free to build up thunks of the calculation and you have a neat little space leak. This is a recurring problem until you learn how to harness the strictness annotations of Haskell. Then the problem disappears.&lt;/p&gt;&lt;p&gt;IO in Haskell is somewhat weak if you naively assume a String is fast. But there is help from Bytestrings, attoparsec and low-level Socket networking. Combinatorrent could use more help with getting the speed up here. I have substituted the IO layers lowest level some 2–3 times in combinatorrent. Contrast this with Erlang, where the original protocol parser and IO is the one still standing. If you want fast network IO in Haskell, you should be using bytestrings and network-bytestring. It is not worth the simplicity going over String in my experience.&lt;/p&gt;&lt;p&gt;The GHC compiler has, comparatively, more performance regressions compared to the Erlang VM. It should come as no surprise: GHC is acting as both a research vehicle and a compiler implementation. I want to stress however, that this has not worried me a lot. When asking the GHC developers for help, the response has been fast and helpful, and in every case it was easy to fix or work around. Also, change is a necessary thing if you want to improve.&lt;/p&gt;&lt;/div&gt;&lt;div id="haskell-pros:"&gt;&lt;h2&gt;Haskell pros:&lt;/h2&gt;&lt;p&gt;Haskell has one very cool thing: Static typing (remember the bias!). The type system of Haskell is the most advanced type system for a general purpose language in existence. The only systems which can beat it are theorem provers like Coq, and they are not general purpose programming languages (Morriset and the YNot team might disagree though!). Static typing has some really cool merits. Bugs are caught fast and early; types ensure few corner cases in the programs (why check for null when it can’t be represented). The types is my program skeleton and the program inhabiting the type is the flesh. Getting the skeleton right yields small and succinct programs. The abstraction possibilities from this is unparalleled in any language I have seen (and I’ve seen a few).&lt;/p&gt;&lt;p&gt;The GHC compiler provides programs which have excellent execution speed. You don’t need to worry a lot about speed when the compiler simply fixes most of the problems for you. This in turn means that you can write abstract code without worrying too much about the result. This yields vastly more general and simpler programs.&lt;/p&gt;&lt;p&gt;One very big difference in the implementations is that of STM channels versus Erlangs message passing. In Erlang, each process has a mailbox of unbounded size. You send messages to the mailbox, identified by the process ID of the mailbox owner. In Haskell, we use STM Channels for most communication. Thus, you send messages not to the PID of a process, but to a specific channel. This effectively changes some rules in channel network configuration. In Erlang you must either globally register a process or propagate PIDs. In Haskell, channels are created and then propagated to communicating parties. I find the Haskell approach considerably easier - but also note that in a statically typed language, channels is the way to go. The sum type for a PID mailbox would be cumbersome in comparison.&lt;/p&gt;&lt;p&gt;Haskell has excellent library and data structure support. For instance you have access to priority search queues via Hackage. PSQueues are useful for implementing the piece histogram in a bittorrent client: knowing how rare a given piece is so you can seek to fetch the rarest first.&lt;/p&gt;&lt;p&gt;Haskell can create (im-)mutable (un-)boxed arrays. These are useful in a bittorrent client in several places. Immutable arrays for storing knowledge about pieces is an example. Or bit-arrays for storing knowledge about the pieces a given peer has. Erlang has no easy access to these and no guarantee of the data representation.&lt;/p&gt;&lt;p&gt;Bryan O’Sullivans attoparsec library allows for incremental parsing. When you get a new chunk of data from the network, you feed it to attoparsec. It will either give you a parsed message and the remaining bytes, or it will hand you back a continuation. This continuation, if invoked with more food, will continue the parsing. For network sockets the incrementality is pure win.&lt;/p&gt;&lt;p&gt;The GHC compiler has some awesome profiling tools, including a powerful heap profiler. Using this, the run-time and memory usage of combinatorrent was brought down.&lt;/p&gt;&lt;p&gt;Finally, testing in Haskell is easy. QuickCheck and Test.Framework provides a —tests target built into the combinatorrent binary itself. Self tests are easy.&lt;/p&gt;&lt;/div&gt;&lt;div id="haskell-mistakes:"&gt;&lt;h2&gt;Haskell mistakes:&lt;/h2&gt;&lt;p&gt;I made some mistakes when writing the Haskell client. For one I relied on the CML library until I realized STM would do an equal or better job. The amount of Haskell developers with STM experience compared to the CML head-count made the decision to change easy.&lt;/p&gt;&lt;p&gt;Furthermore, I should have focused on laziness earlier in the process. The first combinatorrent releases leak memory because of lazy thunk buildup. The latter versions, after I understood it intuitively, does not leak.&lt;/p&gt;&lt;/div&gt;&lt;div id="erlang-cons:"&gt;&lt;h2&gt;Erlang cons:&lt;/h2&gt;&lt;p&gt;In Erlang, dynamic typing is the norm. Rather than enforce typing, you can get warnings by a type analyzer tool, the dialyzer, if need be. Running this on the code is a good idea to weed out some problems quickly. When building etorrent I had much use of the dialyzer and used a at that time experimental extension: spec() specifications. Yet, I think that 19/20 errors in my erlang programs were errors which a type system would have caught easily. This means you spend more time actually running the program and observing its behavior. Also note that dynamic typing hurts less in Erlang compared to other languages. A process is comprehensible in its own right and that reduces the interface to the process communication - a much simpler task.&lt;/p&gt;&lt;p&gt;Etorrent has less stability than combinatorrent and has erred more. Yet, this is no problem for a bittorrent client since the supervisor-tree in Erlang/OTP will automatically restart broken parts of the system. For a bittorrent client we can live with a death once a week or once a day without any troubles.&lt;/p&gt;&lt;p&gt;You have no mutability in Erlang and you have far less options for data representation. This in turn make certain algorithms rather hard to express or you have to opt for variant with a larger space usage. There were no Cabal-equivalent at the time I wrote the code and thus fewer libraries to choose from.&lt;/p&gt;&lt;p&gt;For the built-in libraries, the HTTP library was more strict with respect to correctness. In turn, many trackers would not communicate with it and I had to provide a wrapper around the library. Today, this might have changed though. Haskells HTTP library worked out of the box with no changes.&lt;/p&gt;&lt;p&gt;Erlangs syntax, compared to Haskell, is ugly, clunky and cumbersome. Make no mistake though: Tanks are ugly, clunky and cumbersome. It does not make tanks less menacing.&lt;/p&gt;&lt;/div&gt;&lt;div id="erlang-pros:"&gt;&lt;h2&gt;Erlang pros:&lt;/h2&gt;&lt;p&gt;One application SASL. SASL is a system logger which will record in a ring-buffer any kind of process death and process restart. I used this a lot when developing. I would load a couple of torrents in the client and go to bed. Next morning I would check the SASL log for any error that might have occurred and fix those bugs. This way of developing is good for a bittorrent client: utmost stability is not needed. We just to get the number of errors below a certain threshold. Rather than waste time fixing a bug which only occurs once every year, we can concentrate on the things that matter.&lt;/p&gt;&lt;p&gt;The IO layer in Erlangs VM is FAST! It is written in C, and it is optimized heavily because this is what Erlang does best. For file IO it uses asynchronous threads to circumvent having to wait on the kernel. For the network, it plugs into epoll() getting good performance in turn.&lt;/p&gt;&lt;p&gt;The Beam VM of Erlang is a beast of stability. Basically, it doesn’t quit unless you nuke it from orbit. One of the smaller things I learned some weeks ago was the rudimentary flow control trick. Erlang schedules by counting reductions in an Erlang process and then switching process context when it has no more reductions in its time share. Sending a message never fails but it costs reductions proportional to the queue size of the receiving process. Hence, many senders have a harder time overloading a single receiver. The trick is simple, easily implementable and provides some simple flow control. While not fail-safe, it ups the ante for when communication overload happens.&lt;/p&gt;&lt;p&gt;Erlang has OTP, the Open Telecom Platform, which is a callback-framework for processes. You implement a set of callbacks and hand over control to the OTP-portion of your process. OTP then handles a lot of the ugly, gritty details leaving your part simple. OTP also provides the supervision of processes, restarting them if they err. Supervisor-processes form trees so &lt;em&gt;they&lt;/em&gt; are in turn supervised. It isn’t turtles all the way down in an Erlang VM…&lt;/p&gt;&lt;p&gt;Erlang executes fast enough for most things. Haskell gives you faster execution, but Erlang was more than adequate for a bittorrent client in the speed department. As an example of how this plays together with the IO layer, an early version of etorrent could sustain 700 megabit network load on a local network of 1 gigabit when seeding. The current version of etorrent can do the same as a seeder I suspect. Also, message passing in Erlang is blazing fast. It feels like a function call - a key to good Erlang I think.&lt;/p&gt;&lt;p&gt;The Erlang shell can easily be used as a poor mans user interface. Etorrent simply responds to some functions in the shell, showing status of the running system. I suspect GHCi can do the same, but I never got around to doing it and it doesn’t seem as easy to pull off.&lt;/p&gt;&lt;p&gt;I love the Erlang way of programming. You assume your code does the right thing and let it crash otherwise. If it crashes too often you handle that case. Code is not lingered with error handling for things that never happen and should it happen occasionally, the supervisor tree saves the day.&lt;/p&gt;&lt;/div&gt;&lt;div id="erlang-mistakes:"&gt;&lt;h2&gt;Erlang mistakes:&lt;/h2&gt;&lt;p&gt;Unfortunately, I made a number of mistakes in Etorrent. Most of these has to do with being the first version. Fred P. Brooks hinted that you want to throw away things when building the first version. And I did. I used ETS tables in places where they are not good. ETS is a table in which you can store any erlang term and later retrieve it. They give you a way to circumvent the representation limitation in Erlang. But they are no silver bullet: When you pull out a term, you copy it to the process pulling it. When your terms are 4–8 megabyte in size, that hurts a lot.&lt;/p&gt;&lt;p&gt;I relied far too much on mnesia, the database in Erlang. Mnesia is basically using software-transactional-memory so locking is optimistic. When you have something like 80 writers wanting access to the same row in a table, then the system starves. Also, there is no need for a bittorrent application to require a mnesia store. A simple serialization of key data to a file based on a timer is more than adequate.&lt;/p&gt;&lt;p&gt;I made several mistakes in the process model. I thought that choking was local to a torrent while in reality it is a global thing for all torrents currently being downloaded. These reorganizations require quite some refactoring - and missing in the static typing department these are somewhat more expensive compared to Haskell refactorings.&lt;/p&gt;&lt;p&gt;I thought autotools were a good idea. It is not. Autotools is the Maven of C programming.&lt;/p&gt;&lt;p&gt;Finally, I shedded unit-tests. In a dynamically typed environment you need lots and lots of these. But I decided against them early on. In hindsight this was probably a mistake. While unit-testing Erlang code is hard, it is by no means impossible.&lt;/p&gt;&lt;/div&gt;&lt;div id="future:"&gt;&lt;h2&gt;Future:&lt;/h2&gt;&lt;p&gt;The future brings exciting things with it. I will continue Combinatorrent development. I am almost finished with the Fast-extension (BEP 0006) for combinatorrent and have some more optimization branches ready as well. I still follow Erlang in general because it is an interesting language with a lot of cool uses. I do check that etorrent compiles on new releases of Erlang. If anyone shows interest in any of the client implementations, feel free to contact me. I will happily answer questions.&lt;/p&gt;&lt;p&gt;There is no clear winner in the duel. I &lt;em&gt;prefer&lt;/em&gt; Haskell, but I am biased and believe in static typing. Yet I &lt;em&gt;like&lt;/em&gt; programming in Erlang - both languages are good from different perspectives.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-2438846119259619420?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/2438846119259619420/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=2438846119259619420' title='15 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/2438846119259619420'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/2438846119259619420'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2010/04/haskell-vs-erlang-for-bittorent-clients.html' title='Haskell vs. Erlang for bittorent clients'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>15</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-2938670017687453137</id><published>2010-03-15T08:03:00.000-07:00</published><updated>2010-03-15T08:06:12.715-07:00</updated><title type='text'>Want to hack Haskell? Bittorrent?</title><content type='html'>&lt;div id="helping-with-haskelltorrent"&gt;&lt;h1&gt;Helping with HaskellTorrent&lt;/h1&gt;&lt;p&gt;I have a ideology in which an Open Source project must be easy to hack for other people than the original author. Thus, I am trying to make this possible with HaskellTorrent. In particular, I keep several things in unsolved so others might join the fray, should they want to. This is a list, in no particular order, in which I put forth some things there are left to be done.&lt;/p&gt;&lt;p&gt;Do note that I tend to keep bugs off this list. Many projects use the bug tracker as a way to track what needs doing. I have a TODO.md file in the top-level dir which contains things. Some of these things are taken from this list.&lt;/p&gt;&lt;div id="have-message-pruning"&gt;&lt;h2&gt;HAVE message pruning&lt;/h2&gt;&lt;p&gt;Torrent files work by splitting a file into &lt;em&gt;pieces&lt;/em&gt; and then breaking pieces into &lt;em&gt;blocks&lt;/em&gt;. The blocks are then exchanged between peers until every block in a piece is downloaded. At that point, the SHA1 checksum of the piece can be used to verify the piece got downloaded correctly. If this is the case, a &lt;strong&gt;HAVE&lt;/strong&gt; message is broadcasted to all peers we are connected to. This notifies other peers of the newly available piece so they can begin requesting it.&lt;/p&gt;&lt;p&gt;However, there is an optimization oppurtunity. If the peer already has told us (usually by a &lt;strong&gt;HAVE&lt;/strong&gt; message) that it got the piece already, there is no reason to tell it about the availability. Thus, we can prune the sending of the &lt;strong&gt;HAVE&lt;/strong&gt; for those clients. There is already an IntSet with the necessary information inside the PeerP process with the information, so the change is fairly simple.&lt;/p&gt;&lt;/div&gt;&lt;div id="optimize-peerpiecemgr-communication"&gt;&lt;h2&gt;Optimize Peer/PieceMgr communication&lt;/h2&gt;&lt;p&gt;Profiling shows we spend a considerable amount of time in the communication between the Peer and the Piece Manager. The Peer will, when downloading, try to keep a pipeline of block &lt;strong&gt;REQUEST&lt;/strong&gt; messages going towards the other end. It mitigates the delay on the internet doing so. Hence, it periodically asks the PieceManager for new blocks to request. It does so by sending a number of blocks it wants together with an IntSet of what pieces the peer at the other end has.&lt;/p&gt;&lt;p&gt;The Piece Manager is responsible for giving exclusive access to blocks to peers. There is no reason to download the same blocks at multiple peers, so it keeps track of what blocks where requested. Also, it must only serve blocks that the given peer can download. Another goal is that we would like to complete a piece as early as possible so we will try to complete from pieces that are in progress first.&lt;/p&gt;&lt;p&gt;Currently, the system works by looking at the pieces in progress and then try to serve from these. If all blocks have been taken on pieces in progress, we find one that is pending (randomly) and available at the peer. This one is then promoted to being in progress and the algorithm runs again.&lt;/p&gt;&lt;p&gt;There are a couple of nice optimizations possible. First, if the peer is a seeder, it effectively has every piece. Thus, there are no reason to keep the IntSet around for those, nor is there any reason to carry out expensive IntSet intersections. Second, if the peer is not a seeder, it would be better to keep a bit array around rather than an IntSet. It does count for a good amount of live memory in the Peer processes, and we expect there to be quite many of those. Third, we could benefit from keeping a cache of the last piece the peer requested blocks from. Trying this cache element blindly in the Piece Manager is advantageous to us: we spend less time in the Piece Manager code. It is also nice for the peer: if a piece is cached at the other end, we might help by requesting as many blocks as possible from that piece. Disk IO is a point of contention in modern bittorrent client implementations.&lt;/p&gt;&lt;/div&gt;&lt;div id="always-pick-the-rarest-piece-first"&gt;&lt;h2&gt;Always pick the rarest piece first&lt;/h2&gt;&lt;p&gt;We currently pick pending pieces at random. A better scheme is to know about their availability and then pick them rarest first. The rarest piece is the easiest for us to spread, so it maximizes our ability to give back, which in turn maximizes our ability to download fast. The right Haskell cabal library for this is &lt;strong&gt;Data.PSQueue &lt;/strong&gt;in the package &lt;b&gt;PSQueue&lt;/b&gt;. If there are more pieces eligible at the same rarity, we will pick one at random. This gives an excellent use of View Types in Haskell, should one be interested.&lt;/p&gt;&lt;p&gt;To do this, there is a milestone you need to reach beforehand. When we receive knowledge of piece availability, either through a &lt;strong&gt;BITFIELD&lt;/strong&gt; or a &lt;strong&gt;HAVE&lt;/strong&gt; message, we should propagate that information to the Piece Manager. In the beginning, we can just do nothing with it, and throw it away. It will pave the way for a &lt;strong&gt;PSQueue&lt;/strong&gt; implementation however.&lt;/p&gt;&lt;/div&gt;&lt;div id="increase-code-quality"&gt;&lt;h2&gt;Increase code quality&lt;/h2&gt;&lt;p&gt;Run &lt;em&gt;hlint&lt;/em&gt; on the code. There is a target in the Makefile, which has recently been fixed. Find a GHC warning which is not yet enabled in the &lt;em&gt;.cabal&lt;/em&gt; file and enable it, fixing the bugs that turn up. I guess some of these are more evil to fix than others, so start with the easier ones.&lt;/p&gt;&lt;p&gt;Another area are tests. Running &lt;em&gt;HaskellTorrent —tests&lt;/em&gt; will run the embedded test suite. This one fails on 64bit architectures at the moment (I think, this is the narrowing-down I’ve done). If you spot any area which you can figure out how to test, I would really like to discuss it with you. The code can do with a lot more testing than it use right now.&lt;/p&gt;&lt;/div&gt;&lt;div id="discuss-use-of-attoparsec-attoparsec-iteratee-and-the-event-library"&gt;&lt;h2&gt;Discuss use of attoparsec, attoparsec-iteratee and the event library&lt;/h2&gt;&lt;p&gt;I am seriously contemplating impaling all network performance bottlenecks once and for all by using this triple. If you are interested in hacking these, I’ll be happy to talk to you about it. It would push the bottleneck to the Disk layer once and for all, I think. The cool thing is that there are code to gain inspiration from.&lt;/p&gt;&lt;p&gt;Another nail to the coffin is to support the FAST-extension in the new parser right away. It would pave the way for the rest of the client to understand this extension, so we would be able to get better and faster communication. It also plugs a bug in the original bittorrent specification.&lt;/p&gt;&lt;/div&gt;&lt;div id="use-mmap-for-disk-io"&gt;&lt;h2&gt;Use mmap() for Disk IO&lt;/h2&gt;&lt;p&gt;The right way to do disk IO is by use of mmap() on the files. Reading and writing files are not going to be hard, but we also need to get the hopenssl library to talk to the mmap()’ed backend so we get fast checksum calculations.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-2938670017687453137?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/2938670017687453137/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=2938670017687453137' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/2938670017687453137'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/2938670017687453137'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2010/03/want-to-hack-haskell-bittorrent.html' title='Want to hack Haskell? Bittorrent?'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-2035521980656183257</id><published>2010-03-08T04:02:00.001-08:00</published><updated>2010-03-08T04:02:53.510-08:00</updated><title type='text'>On Computer games and Tufte</title><content type='html'>&lt;div id="tufte-applied-to-games"&gt;&lt;h1&gt;Tufte applied to games&lt;/h1&gt;&lt;p&gt;I played a small bit of the old Infocom game “Wishbringer” the other day. And somehting struck me. This game is &lt;strong&gt;small&lt;/strong&gt;. It has something like 50 locations, with miniscule text at each location. Of course this is because of the limitations of the hardware from the day the game was released, but it also made me think. There is so much game crammed into those 50 locations. Clever location reuse makes the game seem larger than it is. In fact, the majority of locations change considerably over the course of the game.&lt;/p&gt;&lt;p&gt;Now contrast this with newer sandbox games of enormous size: Morrowind, Oblivion, Fallout 3, all by Bethesda. These games are absolutely huge, but in contrast, the world is a mostly static one with very few changes over the course of the game. Tufte, who just got appointed by the US government to visualize government spending, had this notion of “ink carrying meaning” and “ink”. The ratio between these gives you a number of how much ink is wasted and how tightly information is packed on a piece of paper.&lt;/p&gt;&lt;p&gt;Applying Tuftes observation to game worlds is interesting and fun. Games like Morrowind and Oblivion has a very low ratio of value, whereas an old game like Wishbringer has a very high value. Surprisingly, the game Arx Fatalis from 2002 will have a rather high ratio. In Arx Fatalis, the game world is pretty small. But the game uses several tricks to circumvent this. The game world is reusing locations for more than one thing. Also, the game world is opened up to you gradually along with the game unfolding. The same idea is applied in the game “The Witcher” where the majority of the game is going on inside a city. New major areas of the city opens up in later acts, but the old areas are kept and changes.&lt;/p&gt;&lt;p&gt;Today, building huge worlds is not hard. You procedurally generate most of the content in the game through different technologies like SpeedTree for instance. Oblivion has hand-crafted dungeons it would seem, but usually they are just there for being there and not for moving the story ahead. Contrast that with random dungeon in Diablo 2. Usually, there is a chest at the end of those with good levelled loot. Being a loot-game, Diablo 2 encourages you to walk the dungeon.&lt;/p&gt;&lt;p&gt;I sincerely hope that in the future, more games will be like “Wishbringer”. Mass Effect 1 (Have not played the 2nd game) shows some of the way, but it also adds a lot of randomly generated open spaces driven by a car. These are boring. Kill.&lt;/p&gt;&lt;p&gt;Luck has it, that small flash-games and similar platforms will make the game logic be central again. I expect there to be some really interesting games with good “Tufte ratios” in the coming years. But the platform will be Web, mobile phone, Javascript or Flash.&lt;/p&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-2035521980656183257?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/2035521980656183257/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=2035521980656183257' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/2035521980656183257'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/2035521980656183257'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2010/03/on-computer-games-and-tufte.html' title='On Computer games and Tufte'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-7617648515785200117</id><published>2010-02-25T10:57:00.000-08:00</published><updated>2010-02-25T10:58:42.299-08:00</updated><title type='text'>HaskellTorrent v0.0 and further developments</title><content type='html'>&lt;div id="haskelltorrent-v0.0-released"&gt;&lt;h1&gt;HaskellTorrent v0.0 released!&lt;/h1&gt;&lt;p&gt;Last weekend I released version 0.0 of the HaskellTorrent project. However, as modern development will have it, the interesting things happen on the main integration branch, &lt;em&gt;master&lt;/em&gt;, on github: &lt;a href="http://github.com/jlouis/haskell-torrent"&gt;haskell-torrent&lt;/a&gt;. From the point where the 0.0 release was done and till today, three main things happened in the client.&lt;/p&gt;&lt;div id="cpu-optimizations"&gt;&lt;h2&gt;CPU optimizations&lt;/h2&gt;&lt;p&gt;A little bit of work with the profiler has shaved the use of the CPU down by a fairly large amount. I optimized the assertions on the piece database by using &lt;strong&gt;Data.IntSet&lt;/strong&gt; rather than plain old lists. Right now the cost centres are the piece database assertions (still) and deciding which blocks to download. The former of these is simple to get rid of. We don’t need to assert the database at each message, but can do so with a rarer frequency. As for the latter, I have a couple of ideas to shave off CPU cycles on that one as well.&lt;/p&gt;&lt;/div&gt;&lt;div id="listen-sockets"&gt;&lt;h2&gt;Listen sockets&lt;/h2&gt;&lt;p&gt;HaskellTorrent now accepts incoming connections! It does this on port 1579 that has no special connotation apart from being one of the fairly low prime numbers. The etorrent project uses &lt;a href="http://en.wikipedia.org/wiki/1729_(number)"&gt;1729&lt;/a&gt; which has a more interesting history associated with it. Of course, one has to open the eventual NAT/PAT or Firewall to get connections flowing in, should you want to test it.&lt;/p&gt;&lt;/div&gt;&lt;div id="test-framework"&gt;&lt;h2&gt;test-framework&lt;/h2&gt;&lt;p&gt;Finally, we now use the excellent &lt;a href="http://batterseapower.github.com/test-framework/"&gt;test-framework&lt;/a&gt; by Max Bolingbroke. The test inclusion was inspired a lot by Eric Koweys blog post on &lt;a href="http://koweycode.blogspot.com/2009/07/some-ideas-for-practical-quickcheck.html"&gt;the subject&lt;/a&gt;, and it also used bits and pieces from &lt;a href="http://book.realworldhaskell.org/read/testing-and-quality-assurance.html"&gt;Real World Haskell&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;The bottom line is that now you can execute tests directly:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;jlouis@illithid:~/Projects/haskell-torrent$ make test
runghc Setup.lhs build
Preprocessing executables for HaskellTorrent-0.0...
Building HaskellTorrent-0.0...
runghc Setup.lhs test
Test test-framework:
reverse-reverse/id: [OK, passed 100 tests]
Protocol/BCode:
QC encode-decode/id: [OK, passed 100 tests]
HUnit encode-decode/id: [OK]
Protocol/Wire:
Piece (-1) 1 ""
QC encode-decode/id: [Failed]
Falsifiable with seed 2776559770653812966, after 1 tests. Reason: Falsifiable

       Properties  Test Cases  Total
Passed  2           1           3
Failed  1           0           1
Total   3           1           4
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;though it does seem we need to do some work in order to correct the software :)&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-7617648515785200117?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/7617648515785200117/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=7617648515785200117' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/7617648515785200117'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/7617648515785200117'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2010/02/haskelltorrent-v00-and-further.html' title='HaskellTorrent v0.0 and further developments'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-678119203397978708</id><published>2010-02-03T16:10:00.000-08:00</published><updated>2010-02-03T16:56:15.321-08:00</updated><title type='text'></title><content type='html'>&lt;div id="how-logging-is-performed-in-haskell-torrent"&gt;&lt;h1&gt;How logging is performed in Haskell-Torrent&lt;/h1&gt;&lt;p&gt;First an update: Haskell-torrent has downloaded its first torrent file “from the wild”. Unfortunately, this behaviour is not deterministic yet, and sometimes the download fails in spectacular ways.&lt;/p&gt;&lt;p&gt;For a bittorrent client, which is heavily concurrent, we have a few obvious tools at our disposal to ensure correctness. We can use QuickCheck to generate test cases and test properties. This is best done with the parts of the code relating to encoding and decoding of data in the client. Second, and I think this is important, we can pose invariants on the various processes and check that these invariants hold periodically. Third, we can trace the execution.&lt;/p&gt;&lt;p&gt;In order to trace the execution, we need a logging framework. Several exist for Haskell, but none of these really suits our purpose.&lt;/p&gt;&lt;div id="logging"&gt;&lt;h2&gt;Logging&lt;/h2&gt;&lt;p&gt;The first thing we have done is to create a process with a channel. This process is the logger and the only task is to drain the channel and send out log messages on stdout. All other processes log by synchronization on an event where a log message is sent to this process.&lt;/p&gt;&lt;p&gt;Log messages have three components: A /name/ of the logging process, a /message/ to log, and a priority:&lt;/p&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code&gt;&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Keyword"&gt;data&lt;/span&gt;&lt;span class="Normal NormalText"&gt; LogPriority = Debug &lt;/span&gt;&lt;span class="Comment"&gt;-- ^ Fine grained debug info&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;         | Warn  &lt;/span&gt;&lt;span class="Comment"&gt;-- ^ Potentially harmful situations&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;         | Info  &lt;/span&gt;&lt;span class="Comment"&gt;-- ^ Informational messages, progress reports&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;         | Error &lt;/span&gt;&lt;span class="Comment"&gt;-- ^ Errors that are continuable&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;         | Fatal &lt;/span&gt;&lt;span class="Comment"&gt;-- ^ Severe errors. Will probably make the application abort&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;         | None  &lt;/span&gt;&lt;span class="Comment"&gt;-- ^ No logging at all&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;             &lt;/span&gt;&lt;span class="Keyword"&gt;deriving&lt;/span&gt;&lt;span class="Normal NormalText"&gt; (&lt;/span&gt;&lt;span class="Keyword Class"&gt;Show&lt;/span&gt;&lt;span class="Normal NormalText"&gt;, &lt;/span&gt;&lt;span class="Keyword Class"&gt;Eq&lt;/span&gt;&lt;span class="Normal NormalText"&gt;, &lt;/span&gt;&lt;span class="Keyword Class"&gt;Ord&lt;/span&gt;&lt;span class="Normal NormalText"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Since the log channel is part of so many process configurations, it is beneficial to create a type class of those configurations which can log:&lt;/p&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code&gt;&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Keyword"&gt;class&lt;/span&gt;&lt;span class="Normal NormalText"&gt; Logging a &lt;/span&gt;&lt;span class="Keyword"&gt;where&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;   &lt;/span&gt;&lt;span class="Function FunctionDefinition"&gt;getLogger ::&lt;/span&gt;&lt;span class="Normal NormalText"&gt; a -&amp;gt; (&lt;/span&gt;&lt;span class="DataType TypeConstructor"&gt;String&lt;/span&gt;&lt;span class="Normal NormalText"&gt;, LogChannel)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;For example, the Piece Manager has a configuration&lt;/p&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code&gt;&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Keyword"&gt;data&lt;/span&gt;&lt;span class="Normal NormalText"&gt; PieceMgrCfg = PieceMgrCfg&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;    { &lt;/span&gt;&lt;span class="Function FunctionDefinition"&gt;logCh ::&lt;/span&gt;&lt;span class="Normal NormalText"&gt; LogChannel&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;    , &lt;/span&gt;&lt;span class="Function FunctionDefinition"&gt;pieceMgrCh ::&lt;/span&gt;&lt;span class="Normal NormalText"&gt; PieceMgrChannel&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;    , &lt;/span&gt;&lt;span class="Function FunctionDefinition"&gt;fspCh ::&lt;/span&gt;&lt;span class="Normal NormalText"&gt; FSPChannel&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;    , &lt;/span&gt;&lt;span class="Function FunctionDefinition"&gt;chokeCh ::&lt;/span&gt;&lt;span class="Normal NormalText"&gt; ChokeInfoChannel&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;    , &lt;/span&gt;&lt;span class="Function FunctionDefinition"&gt;statusCh ::&lt;/span&gt;&lt;span class="Normal NormalText"&gt; StatusChan&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;    }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;so to make it possible to log, we instance this&lt;/p&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code&gt;&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Keyword"&gt;instance&lt;/span&gt;&lt;span class="Normal NormalText"&gt; Logging PieceMgrCfg &lt;/span&gt;&lt;span class="Keyword"&gt;where&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;  getLogger cf = (&lt;/span&gt;&lt;span class="String"&gt;"PieceMgrP"&lt;/span&gt;&lt;span class="Normal NormalText"&gt;, logCh cf)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And to formalize what a log message and channel are:&lt;/p&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code&gt;&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Keyword"&gt;data&lt;/span&gt;&lt;span class="Normal NormalText"&gt; LogMsg = Mes LogPriority &lt;/span&gt;&lt;span class="DataType TypeConstructor"&gt;String&lt;/span&gt;&lt;span class="Normal NormalText"&gt; &lt;/span&gt;&lt;span class="DataType TypeConstructor"&gt;String&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Keyword"&gt;type&lt;/span&gt;&lt;span class="Normal NormalText"&gt; LogChannel = Channel LogMsg&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code&gt;&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Keyword"&gt;instance&lt;/span&gt;&lt;span class="Normal NormalText"&gt; &lt;/span&gt;&lt;span class="Keyword Class"&gt;Show&lt;/span&gt;&lt;span class="Normal NormalText"&gt; LogMsg &lt;/span&gt;&lt;span class="Keyword"&gt;where&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;    &lt;/span&gt;&lt;span class="Function"&gt;show&lt;/span&gt;&lt;span class="Normal NormalText"&gt; (Mes pri name str) = &lt;/span&gt;&lt;span class="Function"&gt;show&lt;/span&gt;&lt;span class="Normal NormalText"&gt; name ++ &lt;/span&gt;&lt;span class="String"&gt;"("&lt;/span&gt;&lt;span class="Normal NormalText"&gt; ++ &lt;/span&gt;&lt;span class="Function"&gt;show&lt;/span&gt;&lt;span class="Normal NormalText"&gt; pri ++ &lt;/span&gt;&lt;span class="String"&gt;"):\t"&lt;/span&gt;&lt;span class="Normal NormalText"&gt; ++ str&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The logging itself is done by a logger function. Here is its type:&lt;/p&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code&gt;&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Function"&gt;log&lt;/span&gt;&lt;span class="Normal NormalText"&gt; :: Logging a =&amp;gt; LogPriority -&amp;gt; &lt;/span&gt;&lt;span class="DataType TypeConstructor"&gt;String&lt;/span&gt;&lt;span class="Normal NormalText"&gt; -&amp;gt; Process a b ()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It designates that it takes a Priority and a Message to log (the String). It then logs in a Process monad where the configuration is of type a and the state is of type b. Note that the configuration must be an instance of the Logging class.&lt;/p&gt;&lt;p&gt;The code itself is rather straightforward, save for the call to the logLevel function:&lt;/p&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code&gt;&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Function"&gt;log&lt;/span&gt;&lt;span class="Normal NormalText"&gt; prio msg = &lt;/span&gt;&lt;span class="Keyword"&gt;do&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;  (name, logC) &amp;lt;- asks getLogger&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;  when (prio &amp;gt;= logLevel name)&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;      (liftIO $ logMsg' logC name prio msg)&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;  &lt;/span&gt;&lt;span class="Keyword"&gt;where&lt;/span&gt;&lt;span class="Normal NormalText"&gt; logMsg' c name pri = sync . transmit c . Mes pri name&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;For the sake of convenience, we want it simpler for most uses, so without much further ado:&lt;/p&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code&gt;&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;logInfo, logDebug, logFatal, logWarn, &lt;/span&gt;&lt;span class="Function FunctionDefinition"&gt;logError ::&lt;/span&gt;&lt;span class="Normal NormalText"&gt; Logging a =&amp;gt; &lt;/span&gt;&lt;span class="DataType TypeConstructor"&gt;String&lt;/span&gt;&lt;span class="Normal NormalText"&gt; -&amp;gt; Process a b ()&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;logInfo  = &lt;/span&gt;&lt;span class="Function"&gt;log&lt;/span&gt;&lt;span class="Normal NormalText"&gt; Info&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;logDebug = &lt;/span&gt;&lt;span class="Function"&gt;log&lt;/span&gt;&lt;span class="Normal NormalText"&gt; Debug&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;logFatal = &lt;/span&gt;&lt;span class="Function"&gt;log&lt;/span&gt;&lt;span class="Normal NormalText"&gt; Fatal&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;logWarn  = &lt;/span&gt;&lt;span class="Function"&gt;log&lt;/span&gt;&lt;span class="Normal NormalText"&gt; Warn&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;logError = &lt;/span&gt;&lt;span class="Function"&gt;log&lt;/span&gt;&lt;span class="Normal NormalText"&gt; Error&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div id="filtering"&gt;&lt;h2&gt;Filtering&lt;/h2&gt;&lt;p&gt;The missing piece of the puzzle is now the “logLevel” function. In the function above, we only log messages which has a priority higher than the current log-level. The log-level is discriminated by the process name in question that tries to log.&lt;/p&gt;&lt;p&gt;Basically, what we want is a simple way to filter log messages. Rather than log all messages, we want to selectively log only part of these, depending on what we are currently debugging or tracing. A log filter is:&lt;/p&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code&gt;&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Keyword"&gt;type&lt;/span&gt;&lt;span class="Normal NormalText"&gt; LogFilter = &lt;/span&gt;&lt;span class="DataType TypeConstructor"&gt;String&lt;/span&gt;&lt;span class="Normal NormalText"&gt; -&amp;gt; LogPriority&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That is, given a process name, they return a minimum priority for that name. The log function then filters the message if it is not above this priority. Here are a couple of simple combinators:&lt;/p&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code&gt;&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Function FunctionDefinition"&gt;matchP ::&lt;/span&gt;&lt;span class="Normal NormalText"&gt; &lt;/span&gt;&lt;span class="DataType TypeConstructor"&gt;String&lt;/span&gt;&lt;span class="Normal NormalText"&gt; -&amp;gt; LogPriority -&amp;gt; LogFilter&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;matchP process prio = \s -&amp;gt; &lt;/span&gt;&lt;span class="Keyword"&gt;if&lt;/span&gt;&lt;span class="Normal NormalText"&gt; s == process &lt;/span&gt;&lt;span class="Keyword"&gt;then&lt;/span&gt;&lt;span class="Normal NormalText"&gt; prio &lt;/span&gt;&lt;span class="Keyword"&gt;else&lt;/span&gt;&lt;span class="Normal NormalText"&gt; None&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Function FunctionDefinition"&gt;matchAny ::&lt;/span&gt;&lt;span class="Normal NormalText"&gt; LogPriority -&amp;gt; LogFilter&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;matchAny prio = &lt;/span&gt;&lt;span class="Function"&gt;const&lt;/span&gt;&lt;span class="Normal NormalText"&gt; prio&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The first of those matches a process by name. If there is a match it sets a specific priority. Otherwise it punts by returning the highest priority possible. The second is a simple wrapper for always matching at a given level.&lt;/p&gt;&lt;p&gt;With this down, we get to action. Log priorities are Monoids in the sense that None is the neutral element and composition ignores None by “eating” it:&lt;/p&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code&gt;&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Keyword"&gt;instance&lt;/span&gt;&lt;span class="Normal NormalText"&gt; Monoid LogPriority &lt;/span&gt;&lt;span class="Keyword"&gt;where&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;    mempty = None&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;    mappend None g = g&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;    mappend f g    = f&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Since there is already an instance:&lt;/p&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code&gt;&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Keyword"&gt;instance&lt;/span&gt;&lt;span class="Normal NormalText"&gt; Monoid b =&amp;gt; Monoid (a -&amp;gt; b) &lt;/span&gt;&lt;span class="Keyword"&gt;where&lt;/span&gt;&lt;span class="Normal NormalText"&gt; ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Log filters are now monoids. So we can write:&lt;/p&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code&gt;&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Function FunctionDefinition"&gt;logLevel ::&lt;/span&gt;&lt;span class="Normal NormalText"&gt; LogFilter&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;#ifdef DEBUG&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;logLevel = mconcat [matchP &lt;/span&gt;&lt;span class="String"&gt;"SendQueueP"&lt;/span&gt;&lt;span class="Normal NormalText"&gt; Fatal,&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;            matchP &lt;/span&gt;&lt;span class="String"&gt;"ReceiverP"&lt;/span&gt;&lt;span class="Normal NormalText"&gt; Fatal,&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;            matchAny Debug]&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;#else&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;logLevel = matchAny Info&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;#endif&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Which means that we do not care much for log messages from the processes “SendQueueP” and “ReceiverP” unless they are fatal. Otherwise we want Debug messages or above. The only restriction is that the first match in the monoid chain is the one that steers the level.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-678119203397978708?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/678119203397978708/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=678119203397978708' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/678119203397978708'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/678119203397978708'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2010/02/how-logging-is-performed-in-haskell.html' title=''/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-3680780316586421141</id><published>2010-01-27T12:01:00.000-08:00</published><updated>2010-01-27T12:36:11.793-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><category scheme='http://www.blogger.com/atom/ns#' term='bittorrent'/><category scheme='http://www.blogger.com/atom/ns#' term='code'/><title type='text'>Haskell Torrent is nearing a preview release</title><content type='html'>Since the last blog post, a number of new things have been developed for Haskell Torrent. Here is a list of the highlights:&lt;div&gt;&lt;ul&gt;&lt;li&gt;John Gunderman documented a queue interface and helped me with haddock.&lt;/li&gt;&lt;li&gt;The code doing SHA1 Digests have been abstracted into its own module.&lt;/li&gt;&lt;li&gt;We now handle interest as intended in the bittorrent protocol. We update interest based on what peers tells us they have available.&lt;/li&gt;&lt;li&gt;We now pick pieces in Random order rather than linearly.&lt;/li&gt;&lt;li&gt;We correctly inform peers when we have retrieved a full message by sending them HAVE messages.&lt;/li&gt;&lt;li&gt;We can now track how many bytes are left on a torrent. This is needed for the tracker.&lt;/li&gt;&lt;li&gt;We have some preliminary rate calculation code, based on a 20 second window and running averages. It ensures a somewhat fair treatment of the rates of different peers.&lt;/li&gt;&lt;li&gt;The Choke Manager now uses the rate calculation code to choke peers based on their current speed.&lt;/li&gt;&lt;li&gt;The Readme file has been updated with what extensions and protocol-parts we support.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:x-large;"&gt;The current goal:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;We currently aim for two things: BEP-003 support and a preview release (version 0.1). The BEP-003 is the support for the basic bittorrent protocol with no extensions at all present. This is the bare minimum needed to be able to call ourselves a bittorrent client. The list of missing items for BEP-003 is as follows:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;When the torrent file is initializing it needs to calculate how many bytes there are left to download before completion. This number is reported to the tracker.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;We need to make sure that the tracker is informed of Torrent completion in the right way.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;The client will have to handle multi-file torrents. That is, torrents where there are more than one file. We can punt this to after the preview release if needed, because it is not that important for a preview of the client.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;We must correctly change to a seeder mode when the torrent file in question completes. This is currently not happening.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;We use a Pure Haskell SHA1 checksum code. Rather than doing this, we should outsource our digest calculation to OpenSSL through the hsopenssl package. The abstraction should make this easier. This is not strictly needed for BEP-003, but it is nice to have.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;The client will currently not handle the endgame in any special way. This means that a torrent will take considerably more time to complete. On one hand this would be nice to have before the preview release. On the other hand, I think it is better to bump it.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:x-large;"&gt;On the Preview:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;The preview is not a working client. The purpose is to get the client tested in different environments by different people so we can find some bugs and get them sacked. I would like to have a client which has shown itself able to download files in non-lab environments, but perhaps with many bugs still left. This is also to get a test of the release engineering involved in the process. The release will also mark a milestone in the development: we can use it as a stepping stone and a breathing space while we decide what to work on next.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;The plan is to use hackage for the release. I am using the Haskell Platform here - but that means GHC6.10.4. We could use a couple of compilation tests on what will become the next Haskell Platform. I am afraid we use some stuff which changed. A quick heads up would be nice.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;Also, before the release, I would like some janitorial code work done. I have not enabled -Wall while developing, but around now might be the time that someone enables it and begins cleaning up dead code, limit module exports and similar janitor-work.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;Watch this blog. The moment the client has downloaded its first non-lab torrent will be worthy of an announce. I can't predict the future, but my gut feeling says it is going to be soon.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;(Note: The layout of this post is miserable. This is what you get in return for using blogspots built-in editor :)&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-3680780316586421141?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/3680780316586421141/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=3680780316586421141' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/3680780316586421141'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/3680780316586421141'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2010/01/haskell-torrent-is-nearing-preview.html' title='Haskell Torrent is nearing a preview release'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-1770211370099302589</id><published>2010-01-16T10:25:00.000-08:00</published><updated>2010-01-16T10:31:46.348-08:00</updated><title type='text'>The state of Haskell-Torrent</title><content type='html'>&lt;div id="implementing-processes"&gt;&lt;h1&gt;Implementing processes&lt;/h1&gt;&lt;p&gt;The Haskell Bittorrent project is evolving at a steady state these days. In the last couple of days, we have implemented most of the code relevant for carrying out choking of peers. Choking is the process by which you only communicate to a few peers at a time. Thus TCP/IP congestion can be avoided which drives up the download and upload rates. This post is not on this part however, which must wait a bit.&lt;/p&gt;&lt;p&gt;A fellow dane, Thomas Christensen, heeded my call and did some hlint runs over the code. Hopefully, we’ll see more work from him (&lt;a href="http://github.com/thomaschrstnsn"&gt;github&lt;/a&gt;). Alex Mason has added even more parsing stuff through Cereal to the code, fixed a number of bugs in the parser and improved its general state. His venture is described on his blog (&lt;a href="http://random.axman6.com/blog/"&gt;here&lt;/a&gt;).&lt;/p&gt;&lt;div id="processes"&gt;&lt;h2&gt;Processes&lt;/h2&gt;&lt;p&gt;I will be talking about processes in this post. When haskell-torrent started, our processes were simply “things spawned in the IO monad”. The approach works, but it quickly becomes inadequate for several reasons. In Haskell and FP in general, a lot of power stems from the idea that we can write a large set of small building blocks and then compose them together to form increasingly larger and larger blocks as we go. When composing, we use a fairly small number of helpers — readily present in the standard libraries.&lt;/p&gt;&lt;p&gt;When running in IO, we quickly end up with a lot of state. This can of course be passed around by “hand” and tail-calls. Unfortunately, this means we will end up using a lot of our precious coding time doing just exactly that. To optimize, we need a way to reflect away configuration and state when we don’t need it, and reify the information at certain points in the program where it is necessary to know the state.&lt;/p&gt;&lt;p&gt;The ubiquitious tool in Haskell for this are Monads. Not a single monad like IO, but a for-the-case relevant monad built from monad transformers. A couple of days ago, I installed &lt;a href="http://xmonad.org/"&gt;XMonad&lt;/a&gt; by Spencer Janssen, Don Stewart, Jason Creighton and many more. This is a window manager — but surprisingly, it needs to solve some problems similar to the one in haskell-torrent. By inspiration from XMonad, we define&lt;/p&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code&gt;&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;newtype Process a b c = Process (ReaderT a (StateT b &lt;/span&gt;&lt;span class="DataType TypeConstructor"&gt;IO&lt;/span&gt;&lt;span class="Normal NormalText"&gt;) c)&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;   &lt;/span&gt;&lt;span class="Keyword"&gt;deriving&lt;/span&gt;&lt;span class="Normal NormalText"&gt; (&lt;/span&gt;&lt;span class="Keyword Class"&gt;Functor&lt;/span&gt;&lt;span class="Normal NormalText"&gt;, &lt;/span&gt;&lt;span class="Keyword Class"&gt;Monad&lt;/span&gt;&lt;span class="Normal NormalText"&gt;, MonadIO, MonadState b, MonadReader a, Typeable)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That is, a &lt;em&gt;Process&lt;/em&gt; is a type. It contains some configuration data &lt;em&gt;a&lt;/em&gt;, an internal state &lt;em&gt;b&lt;/em&gt; and is in the process of evaluating to a value of type &lt;em&gt;c&lt;/em&gt;. We use a Reader transformer so we can &lt;em&gt;ask&lt;/em&gt; for configuration data when we need it. We do not expect this configuration data to be altered when the process runs. A State Transformer takes care of the internal state of the process. Finally, we let the underlying monad be IO. This gives us access to CML and the outside world.&lt;/p&gt;&lt;p&gt;We let GHC derive a large set of things automatically (using several extensions in the process). This gives an easier way to manipulate the state when the process is running.&lt;/p&gt;&lt;p&gt;Running a Process is easy:&lt;/p&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code&gt;&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Function FunctionDefinition"&gt;runP ::&lt;/span&gt;&lt;span class="Normal NormalText"&gt; a -&amp;gt; b -&amp;gt; Process a b c -&amp;gt; &lt;/span&gt;&lt;span class="DataType TypeConstructor"&gt;IO&lt;/span&gt;&lt;span class="Normal NormalText"&gt; (c, b)&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;runP c st (Process p) = runStateT (runReaderT p c) st&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;which is exactly like in XMonad. Spawning a new process is also fairly easy:&lt;/p&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code&gt;&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Function FunctionDefinition"&gt;spawnP ::&lt;/span&gt;&lt;span class="Normal NormalText"&gt; a -&amp;gt; b -&amp;gt; Process a b () -&amp;gt; &lt;/span&gt;&lt;span class="DataType TypeConstructor"&gt;IO&lt;/span&gt;&lt;span class="Normal NormalText"&gt; ThreadId&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;spawnP c st p = spawn proc&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;  &lt;/span&gt;&lt;span class="Keyword"&gt;where&lt;/span&gt;&lt;span class="Normal NormalText"&gt; proc = &lt;/span&gt;&lt;span class="Keyword"&gt;do&lt;/span&gt;&lt;span class="Normal NormalText"&gt; runP c st p&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;                  &lt;/span&gt;&lt;span class="Function"&gt;return&lt;/span&gt;&lt;span class="Normal NormalText"&gt; ()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In general different processes will have different configurations &lt;em&gt;a&lt;/em&gt;. These will usually contain the channels on which the process can communicate. We then define a type class&lt;/p&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code&gt;&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Keyword"&gt;class&lt;/span&gt;&lt;span class="Normal NormalText"&gt; Logging a &lt;/span&gt;&lt;span class="Keyword"&gt;where&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;  &lt;/span&gt;&lt;span class="Function FunctionDefinition"&gt;getLogger ::&lt;/span&gt;&lt;span class="Normal NormalText"&gt; a -&amp;gt; LogChannel&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Keyword"&gt;instance&lt;/span&gt;&lt;span class="Normal NormalText"&gt; Logging LogChannel &lt;/span&gt;&lt;span class="Keyword"&gt;where&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;  getLogger = &lt;/span&gt;&lt;span class="Function"&gt;id&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;of types that contain a logger channel. This means we can define a generic log function like this:&lt;/p&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code&gt;&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Function"&gt;log&lt;/span&gt;&lt;span class="Normal NormalText"&gt; :: Logging a =&amp;gt; &lt;/span&gt;&lt;span class="DataType TypeConstructor"&gt;String&lt;/span&gt;&lt;span class="Normal NormalText"&gt; -&amp;gt; Process a b ()&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Function"&gt;log&lt;/span&gt;&lt;span class="Normal NormalText"&gt; msg = &lt;/span&gt;&lt;span class="Keyword"&gt;do&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;    logC &amp;lt;- asks getLogger&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;    liftIO $ logMsg logC msg&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Type classes are a magnificent tool when we want to coerce a general function on top of different types. Many of our configurations in the client will instance the &lt;em&gt;Logging&lt;/em&gt; class and then the log function knows how to access the logger in the Reader.&lt;/p&gt;&lt;/div&gt;&lt;div id="what-does-this-buy-us"&gt;&lt;h2&gt;What does this buy us&lt;/h2&gt;&lt;p&gt;The advantage of doing this change on the code is twofold: First, the amount of parameter passing is considerably reduced. Reflection into the monad solves this problem. We are now able to compose easier. Function composition is considerably harder when there are many parameters abound. With the change, preliminary restructuring of the Peer process shows a much simpler flow. Also, there are now ample refactoring opportunities available with the change.&lt;/p&gt;&lt;p&gt;Second, the monad means we can use locality much more to our advantage. A common idiom is to modify the state of the process or to retrieve the current state for query. This now happens locally at the point where it is needed. Before, we might have needed to pass a parameter through several functions and then use it.&lt;/p&gt;&lt;/div&gt;&lt;div id="what-next"&gt;&lt;h2&gt;What next?&lt;/h2&gt;&lt;p&gt;There are a small number of things that needs to be addressed before we can claim that the client is a full bittorrent client:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The client needs to correctly handle the concept of &lt;em&gt;interest&lt;/em&gt;. It must tell other clients if it is interested in the pieces they have at their disposal for transmission. I have some preliminary code for doing this.&lt;/li&gt;&lt;li&gt;The client needs to correctly tell the tracker how many bytes it uploaded and downloaded. This measure is needed on many private trackers as they require people to upload data back.&lt;/li&gt;&lt;li&gt;The client needs to be better at choosing the next eligible piece. Choosing one randomly is good enough.&lt;/li&gt;&lt;li&gt;The client needs to handle multi-file torrents. It is not as hard as it may sound — the only part of the system that needs to know about files is the code handling the file system. All other parts can just keep on transferring pieces.&lt;/li&gt;&lt;li&gt;For choking to work correctly, we must know how fast we are currently transferring to a peer. This is an interesting little problem if somebody feels their curiosity tickled :)&lt;/li&gt;&lt;li&gt;We currently take space proportional to torrent size due to our SHA1 calculation being slow and not use a file descriptor. Research into a faster SHA1 library would be really beneficial.&lt;/li&gt;&lt;li&gt;We need to accept incoming connections. The system only connects outward at the moment.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;And of course, it needs some testing in a non-lab setting. Currently it can seed and leech, but my setup is very simple: Opentracker and rtorrent on another computer.&lt;/p&gt;&lt;p&gt;The main github repository for haskell-torrent is &lt;a href="http://github.com/jlouis/haskell-torrent/"&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-1770211370099302589?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/1770211370099302589/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=1770211370099302589' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/1770211370099302589'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/1770211370099302589'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2010/01/state-of-haskell-torrent.html' title='The state of Haskell-Torrent'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-621239437930874200</id><published>2010-01-05T12:40:00.000-08:00</published><updated>2010-01-05T12:50:22.015-08:00</updated><title type='text'>Thoughts on process hierarchies in Haskell.</title><content type='html'>&lt;div id="on-process-hierachies"&gt;&lt;h1&gt;On Process Hierachies&lt;/h1&gt;&lt;p&gt;I have been in thinking mode the last couple of days. It all started when I decided to look at the problem of &lt;em&gt;wrong&lt;/em&gt; in haskell-torrent. What will happen when something fails? Joe Armstrong has part of the answer by arguing that we must proactively expect a process to fail and then let some other process clean it up (paraphrased a lot by me, these are not his exact words).&lt;/p&gt;&lt;p&gt;Take a look at this image,&lt;/p&gt;&lt;p style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_ZmTZzIup5tY/S0OkTpVs7TI/AAAAAAAAACA/h9WjWJahvMI/s1600-h/PHierachy.png"&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 0); -webkit-text-decorations-in-effect: none; "&gt;&lt;/span&gt;&lt;/a&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_ZmTZzIup5tY/S0OkTUntJBI/AAAAAAAAAB4/lXdYFk27S4s/s1600-h/processes.png"&gt;&lt;img src="http://4.bp.blogspot.com/_ZmTZzIup5tY/S0OkTUntJBI/AAAAAAAAAB4/lXdYFk27S4s/s320/processes.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5423359028143924242" style="display: block; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; text-align: center; cursor: pointer; width: 320px; height: 194px; " /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;It is a &lt;a href="http://en.wikipedia.org/wiki/Hypergraph"&gt;hypergraph&lt;/a&gt; where each vertex corresponds to a process and each edge corresponds to an channel. The graph is undirected because in principle each process can both send and receive on the channel in question. In practice however, one can limit the communication as some processes will only transmit on a channel, and others will only receive (and some will do both).&lt;/p&gt;&lt;p&gt;To simplify the graph, I omit local RPC channels. It is customary to implement RPC by creating a local channel and transmitting that channel over one of the hypergraph edges. Response can then work directly on the local channel, simplifying the problem of giving &lt;em&gt;identity&lt;/em&gt; to processes in many cases.&lt;/p&gt;&lt;div id="termination"&gt;&lt;h2&gt;Termination&lt;/h2&gt;&lt;p&gt;A somewhat scary part of such a network is what happens when we want to terminate it or if something goes wrong in one of the processes. In particular, we have the problem that while Haskell is a pure, nice, protected Nirvana — the real world inside IO is a dank, dark place of twisted little passages (all alike). Thus it might very well be that we get to experience an exception first-hand in one of the above processes.&lt;/p&gt;&lt;p&gt;I have toyed with the idea of copying the excellent CHP library by Neil Brown. Neil defines a concept of &lt;em&gt;poison&lt;/em&gt; for channels. A channel that has been poisoned will always transmit poison. Poison thus propagates through the hypergraph and slowly but surely kills off each process. Neil has a description of the process &lt;a href="http://chplib.wordpress.com/2009/09/30/poison-concurrent-termination/"&gt;on his blog&lt;/a&gt;. I like the idea because it uses the existing infrastructure of the hypergraph. It would be fairly easy to add support for writing poison handlers at each node.&lt;/p&gt;&lt;/div&gt;&lt;div id="process-hierachies"&gt;&lt;h2&gt;Process Hierarchies&lt;/h2&gt;&lt;p&gt;I have pondered on a different scheme for the last couple of days however. We can impose a &lt;em&gt;location graph&lt;/em&gt; on the hypergraph above:&lt;/p&gt;&lt;p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_ZmTZzIup5tY/S0OkTpVs7TI/AAAAAAAAACA/h9WjWJahvMI/s1600-h/PHierachy.png"&gt;&lt;img src="http://4.bp.blogspot.com/_ZmTZzIup5tY/S0OkTpVs7TI/AAAAAAAAACA/h9WjWJahvMI/s320/PHierachy.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5423359033705557298" style="display: block; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; text-align: center; cursor: pointer; width: 320px; height: 87px; " /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;This graph, a tree, describes the location or hierarchy of the processes in question. The processes named S0, S1, … and so forth are &lt;em&gt;supervisors&lt;/em&gt;. Their responsibility is only one: Keep their children running according to a &lt;em&gt;policy&lt;/em&gt;. Erlang programmers fluent in the OTP high level libraries present in the Erlang distribution will recognize the supervisor term.&lt;/p&gt;&lt;p&gt;A normal (&lt;em&gt;worker&lt;/em&gt;) process has two rules:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;If the process terminates, it must inform its supervisor.&lt;/li&gt;&lt;li&gt;If the process gets an asynchronous KillThread exception, it &lt;em&gt;must&lt;/em&gt; die.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;A supervisor process needs to obey the following scheme:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;If a process under its supervision dies it must take affair according to its policy. This may mean that it kills off all other children and reports back to its supervisor for instance. Or it may mean that it simply restarts the process that got killed. What happens is dependent on the policy we configured the supervisor with.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;If a supervisor is asked to shutdown by a KillThread exception, it must first kill all of its children.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Note that with these rules, termination is almost free: Terminate the tree. Because everything is linked to the tree, termination will happen. We will terminate by asynchronous exceptions aggressively.&lt;/p&gt;&lt;p&gt;An interesting difference from Erlang is that of communication, which is a certain sense is Dual in Haskell+CML: In Erlang, the process id is what you need to hold in order to transmit an (async.) message to the process. In our CML-based system the &lt;em&gt;channel&lt;/em&gt; is the name you must hold in order to communicate. In other words, this lets us, in some circumstances, replace the process with a new one but keeping the channel. Note, though, that the interface is not completely clean: if the Haskell runtime figures out a thread is indefinitely blocked, it will in general throw an exception — but I have not yet read the CML code in detail so I do not know if this will happen. It depends on what MVar references a channel hold.&lt;/p&gt;&lt;/div&gt;&lt;div id="another-view"&gt;&lt;h2&gt;Another view&lt;/h2&gt;&lt;p&gt;The hypergraph and location graph constitutes what is sometimes called a &lt;em&gt;Bigraph&lt;/em&gt;. This is not to be confused with the term Bi&lt;em&gt;partite&lt;/em&gt; graph which is a completely different term but sometimes also called a bigraph unfortunately. I somewhat resist the idea to use the same term for different concepts, but &lt;a href="http://www.itu.dk/~mikkelbu/research/bigraphsbib/index.html"&gt;work&lt;/a&gt; done in this twi-graph concept presented in this post on &lt;a href="http://www.itu.dk/research/pls/wiki/index.php/A_Brief_Introduction_To_Bigraphs"&gt;bigraphs&lt;/a&gt; suggests that the term is quite used in this respect.&lt;/p&gt;&lt;p&gt;The research seems different from what I need however. &lt;a href="http://www.itu.dk/"&gt;ITU&lt;/a&gt; has done extensive research in bigraphical programming languages, letting them describe various known calculi (Lambda, Pi, etc.). I just want to use the descriptive power of the bigraphs to discriminate &lt;em&gt;location&lt;/em&gt; from &lt;em&gt;communication&lt;/em&gt;.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;So to conclude: Does that give anybody out there a brilliant idea or does my design have an inherent flaw I should be aware of? If not, I'll probably try to sketch some code in Haskell for the Supervisor tree and processes.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-621239437930874200?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/621239437930874200/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=621239437930874200' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/621239437930874200'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/621239437930874200'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2010/01/thoughts-on-process-hierarchies-in.html' title='Thoughts on process hierarchies in Haskell.'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_ZmTZzIup5tY/S0OkTUntJBI/AAAAAAAAAB4/lXdYFk27S4s/s72-c/processes.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-147140034412694675</id><published>2009-12-29T11:30:00.000-08:00</published><updated>2009-12-29T11:36:53.438-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><category scheme='http://www.blogger.com/atom/ns#' term='bittorrent'/><category scheme='http://www.blogger.com/atom/ns#' term='concurrency'/><title type='text'>On the idioms in haskell-torrent</title><content type='html'>&lt;div id="on-the-idioms-used-in-haskell-torrent"&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_ZmTZzIup5tY/SzpY4kSxL-I/AAAAAAAAABw/2M9DonRog8I/s1600-h/PieceManager.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 246px;" src="http://4.bp.blogspot.com/_ZmTZzIup5tY/SzpY4kSxL-I/AAAAAAAAABw/2M9DonRog8I/s320/PieceManager.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5420742830332129250" /&gt;&lt;/a&gt;
&lt;p&gt;This post serves several purposes. First, we bring an update on the code state: The client is now able to leech, that is download, in a lab setting. The lab consist of a test tracker, an rtorrent client two computers. The tesfile is file of 5000000 bytes containing a specific phrase over and over. This gives good compression ratio in git and thus it is not that irritating to move over the wire if needed.&lt;/p&gt;&lt;p&gt;Alex Mason did a good job improving several things in the project. He added prioritization to logging, got compilation working on GHC 6.12.x and is now looking at improving every aspect of data parsing. The BCode work, able to handle the bittorrent bencoded data using applicative functors (&lt;strong&gt;Data.Applicative&lt;/strong&gt;) look really good.&lt;/p&gt;&lt;p&gt;The latter part serves two purposes in parallel: It describes the used idioms and it describes the piece manager code used for leeching torrents. This is a work in progress and there are some things we don’t handle yet.&lt;/p&gt;&lt;p&gt;Also, I am trying to use John MacFarlane’s excellent &lt;a href="http://johnmacfarlane.net/pandoc/"&gt;pandoc&lt;/a&gt; package for typesetting this in blogger.&lt;/p&gt;&lt;div id="the-piecemanager"&gt;&lt;h2&gt;The Piecemanager&lt;/h2&gt;&lt;p&gt;The Piece Manager is defined in the module &lt;strong&gt;PieceMgrP&lt;/strong&gt;. It is responsible for keeping track of the torrents internal Piece State. That is, what do we need to download, and what have we already downloaded and can serve to other peers. Remember that in our terminology, a Block is a subset of a piece, given by an offset and a length. You could call it a &lt;em&gt;slice&lt;/em&gt; of a piece.&lt;/p&gt;&lt;p&gt;The basic idiom of the piecemanager is that of an owning process. In traditional semaphore-oriented programming we protect a data structure by a mutex. We could also protect it software transactions, but since we partially derived haskell-torrent from etorrent, we’ll go with the message passing method. We simple invent a process to manage the data structure. Operations on the structure is then serialized by passing them to the process and gettings answers back, RPC-style. It might not be parallel, but it certainly is easy.&lt;/p&gt;&lt;p&gt;The data structure we want to protect is the piece database:&lt;/p&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code&gt;&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Keyword"&gt;data&lt;/span&gt;&lt;span class="Normal NormalText"&gt; PieceDB = PieceDB&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;   { &lt;/span&gt;&lt;span class="Function FunctionDefinition"&gt;pendingPieces ::&lt;/span&gt;&lt;span class="Normal NormalText"&gt; [PieceNum]&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;   , &lt;/span&gt;&lt;span class="Function FunctionDefinition"&gt;donePiece     ::&lt;/span&gt;&lt;span class="Normal NormalText"&gt; [PieceNum]&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;   , &lt;/span&gt;&lt;span class="Function FunctionDefinition"&gt;inProgress    ::&lt;/span&gt;&lt;span class="Normal NormalText"&gt; &lt;/span&gt;&lt;span class="Normal ModuleName"&gt;M.Map&lt;/span&gt;&lt;span class="Normal NormalText"&gt; PieceNum InProgressPiece&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;   , &lt;/span&gt;&lt;span class="Function FunctionDefinition"&gt;infoMap       ::&lt;/span&gt;&lt;span class="Normal NormalText"&gt; PieceMap&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;   }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The database contains a list of pieces which are pending for download. This list should, in a perfect world, be maintained with a histogram such that we know the rarity of each piece. A &lt;em&gt;good&lt;/em&gt; client prefers rare pieces to young pieces and selects randomly among pieces of the same rarity. A weaker client picks randomly without taking their rarity into consideration. A dumb client, like haskell-torrent currently, just picks them off from a single end. This is bad for the torrent cloud to do, but it is a start. If someone comes up with a data structure which is (practically) efficient for storing histograms, I would be happy to hear about it.&lt;/p&gt;&lt;p&gt;The &lt;em&gt;donePiece&lt;/em&gt; record field is the list of pieces that are done. We keep this around because when a new peer is connected to the client then we need to tell this peer about what pieces we have fully downloaded.&lt;/p&gt;&lt;p&gt;Then we have &lt;strong&gt;Data.Map&lt;/strong&gt; &lt;strong&gt;Map&lt;/strong&gt; which tells us something about Pieces that are in progress. The InProgress data type has the following structure:&lt;/p&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code&gt;&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Keyword"&gt;data&lt;/span&gt;&lt;span class="Normal NormalText"&gt; InProgressPiece = InProgressPiece&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;   { &lt;/span&gt;&lt;span class="Function FunctionDefinition"&gt;ipDone  ::&lt;/span&gt;&lt;span class="Normal NormalText"&gt; &lt;/span&gt;&lt;span class="DataType TypeConstructor"&gt;Int&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;   , &lt;/span&gt;&lt;span class="Function FunctionDefinition"&gt;ipSize  ::&lt;/span&gt;&lt;span class="Normal NormalText"&gt; &lt;/span&gt;&lt;span class="DataType TypeConstructor"&gt;Int&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;   , &lt;/span&gt;&lt;span class="Function FunctionDefinition"&gt;ipHaveBlocks ::&lt;/span&gt;&lt;span class="Normal NormalText"&gt; &lt;/span&gt;&lt;span class="Normal ModuleName"&gt;S.Set&lt;/span&gt;&lt;span class="Normal NormalText"&gt; Block&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;   , &lt;/span&gt;&lt;span class="Function FunctionDefinition"&gt;ipPendingBlocks ::&lt;/span&gt;&lt;span class="Normal NormalText"&gt; [Block]&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;   } &lt;/span&gt;&lt;span class="Keyword"&gt;deriving&lt;/span&gt;&lt;span class="Normal NormalText"&gt; &lt;/span&gt;&lt;span class="Keyword Class"&gt;Show&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;These fields are (in order) how many blocks in the piece we have downloaded, the complete size of the piece, a set of the blocks we have downloaded and a list of blocks pending download. The size of the piece is almost always the same, but the last piece is different if the complete file is not a multiple of the block size.&lt;/p&gt;&lt;p&gt;Returning to the &lt;em&gt;PieceDB&lt;/em&gt;, the last entry describes the complete torrent. The PieceMap tells, for each piece, its offset in the file, its length and its SHA1 digest. Note we do not support multi-file torrents yet, although this code would probably be unaltered. The offset is in the multi-file-case the offset in the concatenation of the files in the torrent.&lt;/p&gt;&lt;/div&gt;&lt;div id="starting-the-process"&gt;&lt;h2&gt;Starting the process&lt;/h2&gt;&lt;p&gt;The PieceManager process is started with the &lt;em&gt;start&lt;/em&gt; call:&lt;/p&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code&gt;&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Function FunctionDefinition"&gt;start ::&lt;/span&gt;&lt;span class="Normal NormalText"&gt; LogChannel -&amp;gt; PieceMgrChannel -&amp;gt; FSPChannel -&amp;gt; PieceDB -&amp;gt; &lt;/span&gt;&lt;span class="DataType TypeConstructor"&gt;IO&lt;/span&gt;&lt;span class="Normal NormalText"&gt; ()&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;start logC mgrC fspC db = (spawn $ lp db) &amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="Function"&gt;return&lt;/span&gt;&lt;span class="Normal NormalText"&gt; ()&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;  &lt;/span&gt;&lt;span class="Keyword"&gt;where&lt;/span&gt;&lt;span class="Normal NormalText"&gt; lp db = &lt;/span&gt;&lt;span class="Keyword"&gt;do&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;          msg &amp;lt;- sync $ receive mgrC (&lt;/span&gt;&lt;span class="Function"&gt;const&lt;/span&gt;&lt;span class="Normal NormalText"&gt; &lt;/span&gt;&lt;span class="Keyword DataConstructor"&gt;True&lt;/span&gt;&lt;span class="Normal NormalText"&gt;)&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;          &lt;/span&gt;&lt;span class="Keyword"&gt;case&lt;/span&gt;&lt;span class="Normal NormalText"&gt; msg &lt;/span&gt;&lt;span class="Keyword"&gt;of&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We supply a number of &lt;strong&gt;CML&lt;/strong&gt;-channels to the process from the outside and then we spawn off the main loop before returning (). This is probably not good in the long run, where we will need to handle errors in the process. But for now we accept that the code is supposedly error-free and never have any problems.&lt;/p&gt;&lt;p&gt;The loop code itself synchronizes on messages here named &lt;em&gt;msg&lt;/em&gt;. These messages have the form&lt;/p&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code&gt;&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Keyword"&gt;data&lt;/span&gt;&lt;span class="Normal NormalText"&gt; PieceMgrMsg = GrabBlocks &lt;/span&gt;&lt;span class="DataType TypeConstructor"&gt;Int&lt;/span&gt;&lt;span class="Normal NormalText"&gt; [PieceNum] (Channel [(PieceNum, [Block])])&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;                 | StoreBlock PieceNum Block &lt;/span&gt;&lt;span class="Normal ModuleName"&gt;B.ByteString&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;                 | PutbackBlocks [(PieceNum, Block)]&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;                 | GetDone (Channel [PieceNum])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;and each of these are going to be explained in the following. A general note is that if the message contains a channel, it is usually a form of RPC-message, where the channel is the return channel on which to send back an answer. One could probably factor this out into a generic RPC-construction with a bit of cleverness, but I have not given it much thought yet.&lt;/p&gt;&lt;p&gt;In the following, we present some examples of processing these messages.&lt;/p&gt;&lt;div id="grabbing-blocks"&gt;&lt;h3&gt;Grabbing blocks&lt;/h3&gt;&lt;p&gt;Here is the fragment for grabbing blocks. It is one of the paths in the diagram above.&lt;/p&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code&gt;&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;GrabBlocks n eligible c -&amp;gt;&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;   &lt;/span&gt;&lt;span class="Keyword"&gt;do&lt;/span&gt;&lt;span class="Normal NormalText"&gt; logMsg logC $ &lt;/span&gt;&lt;span class="String"&gt;"Grabbing blocks"&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;      &lt;/span&gt;&lt;span class="Keyword"&gt;let&lt;/span&gt;&lt;span class="Normal NormalText"&gt; (blocks, db') = grabBlocks' n eligible db&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;      logMsg logC $ &lt;/span&gt;&lt;span class="String"&gt;"Grabbed..."&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;      sync $ transmit c blocks&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;      lp db'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Basically, this call is a request by a peer process to get exclusive access to &lt;em&gt;n&lt;/em&gt; blocks among all the available blocks for a while. This ensures that only this peer will download the blocks, eliminating block collisions. The &lt;em&gt;eligible&lt;/em&gt; value is a list of pieces that the peer has already downloaded, and we should of course only choose blocks among those. Our block grabber may honor the request or return an empty list if no block can be satisfied.&lt;/p&gt;&lt;p&gt;The guts is hidden in the call to the helper &lt;em&gt;grabBlocks’&lt;/em&gt;, which we will describe later.&lt;/p&gt;&lt;/div&gt;&lt;div id="storing-blocks"&gt;&lt;h3&gt;Storing blocks&lt;/h3&gt;&lt;p&gt;The other path in the diagram is maintained by this code fragment:&lt;/p&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code&gt;&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt; StoreBlock pn blk d -&amp;gt;&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;     &lt;/span&gt;&lt;span class="Keyword"&gt;do&lt;/span&gt;&lt;span class="Normal NormalText"&gt; FSP.storeBlock fspC pn blk d&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;        &lt;/span&gt;&lt;span class="Keyword"&gt;let&lt;/span&gt;&lt;span class="Normal NormalText"&gt; (done, db') = updateProgress db pn blk&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;        &lt;/span&gt;&lt;span class="Keyword"&gt;if&lt;/span&gt;&lt;span class="Normal NormalText"&gt; done&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;           &lt;/span&gt;&lt;span class="Keyword"&gt;then&lt;/span&gt;&lt;span class="Normal NormalText"&gt; &lt;/span&gt;&lt;span class="Keyword"&gt;do&lt;/span&gt;&lt;span class="Normal NormalText"&gt; assertPieceComplete db pn logC&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;                   pieceOk &amp;lt;- FSP.checkPiece fspC pn&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;                   &lt;/span&gt;&lt;span class="Keyword"&gt;let&lt;/span&gt;&lt;span class="Normal NormalText"&gt; db'' =&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;                     &lt;/span&gt;&lt;span class="Keyword"&gt;case&lt;/span&gt;&lt;span class="Normal NormalText"&gt; pieceOk &lt;/span&gt;&lt;span class="Keyword"&gt;of&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;                       &lt;/span&gt;&lt;span class="Keyword DataConstructor"&gt;Nothing&lt;/span&gt;&lt;span class="Normal NormalText"&gt; -&amp;gt;&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;                         &lt;/span&gt;&lt;span class="Function"&gt;error&lt;/span&gt;&lt;span class="Normal NormalText"&gt; &lt;/span&gt;&lt;span class="String"&gt;"PieceMgrP: Piece Nonexisting!"&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;                       &lt;/span&gt;&lt;span class="Keyword DataConstructor"&gt;Just&lt;/span&gt;&lt;span class="Normal NormalText"&gt; &lt;/span&gt;&lt;span class="Keyword DataConstructor"&gt;True&lt;/span&gt;&lt;span class="Normal NormalText"&gt; -&amp;gt; completePiece db' pn&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;                       &lt;/span&gt;&lt;span class="Keyword DataConstructor"&gt;Just&lt;/span&gt;&lt;span class="Normal NormalText"&gt; &lt;/span&gt;&lt;span class="Keyword DataConstructor"&gt;False&lt;/span&gt;&lt;span class="Normal NormalText"&gt; -&amp;gt; putBackPiece db' pn&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;                   lp db''&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;            &lt;/span&gt;&lt;span class="Keyword"&gt;else&lt;/span&gt;&lt;span class="Normal NormalText"&gt; lp db'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We get a request to store the block &lt;em&gt;blk&lt;/em&gt; in piece &lt;em&gt;pn&lt;/em&gt; where &lt;em&gt;d&lt;/em&gt; is the data we want to store as a &lt;strong&gt;ByteString&lt;/strong&gt;. We invoke the filesystem to actually store the block. In a real world, we would check that this is really what we wanted. If the piece is already complete and checked, we don’t want a stray block to errornously destroy the piece. In general we want more checks like these in the client.&lt;/p&gt;&lt;p&gt;Then we update the database with the progress on the piece. If the piece is done, we invoke a checking of that piece. Either it is complete and Ok, in which case we mark it as such in the database — or it is not Ok, in which case we put it back for downloading. This happens in the real world at times due to clients with bugs so it is always important not to trust the other client. If the piece completes, we should send out HAVE messages to all connected peers. I plan to make the Peer Manager do that, but the code has not yet been implemented for that.&lt;/p&gt;&lt;/div&gt;&lt;div id="the-rpc-idiom"&gt;&lt;h3&gt;The RPC idiom&lt;/h3&gt;&lt;p&gt;When we initially connect to a peer, we will have to transfer the pieces we have. To do this, we construct a BITFIELD message and to construct this, we need the set of pieces which are complete. The &lt;em&gt;GetDone&lt;/em&gt; message handles this:&lt;/p&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code&gt;&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;GetDone c -&amp;gt; &lt;/span&gt;&lt;span class="Keyword"&gt;do&lt;/span&gt;&lt;span class="Normal NormalText"&gt; sync $ transmit c (donePiece db)&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;                lp db&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;and the peer which want this calls the function&lt;/p&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code&gt;&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Function FunctionDefinition"&gt;getPieceDone ::&lt;/span&gt;&lt;span class="Normal NormalText"&gt; PieceMgrChannel -&amp;gt; &lt;/span&gt;&lt;span class="DataType TypeConstructor"&gt;IO&lt;/span&gt;&lt;span class="Normal NormalText"&gt; [PieceNum]&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;getPieceDone ch = &lt;/span&gt;&lt;span class="Keyword"&gt;do&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt; c &amp;lt;- channel&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt; sync $ transmit ch $ GetDone c&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt; sync $ receive c (&lt;/span&gt;&lt;span class="Function"&gt;const&lt;/span&gt;&lt;span class="Normal NormalText"&gt; &lt;/span&gt;&lt;span class="Keyword DataConstructor"&gt;True&lt;/span&gt;&lt;span class="Normal NormalText"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I think there is an idiom to be extracted from this code and as it is used quite a lot it would be very beneficial to have in the long run.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="grabbing-blocks-the-inner-workings"&gt;&lt;h2&gt;Grabbing blocks, the inner workings&lt;/h2&gt;&lt;p&gt;The diagram above hints that grabbing blocks has a more complicated control flow. The idea of the code is that the control flow is modeled by a tail call into the next box. Let us break up the code:&lt;/p&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code&gt;&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Function FunctionDefinition"&gt;grabBlocks' ::&lt;/span&gt;&lt;span class="Normal NormalText"&gt; &lt;/span&gt;&lt;span class="DataType TypeConstructor"&gt;Int&lt;/span&gt;&lt;span class="Normal NormalText"&gt; -&amp;gt; [PieceNum] -&amp;gt; PieceDB&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;            -&amp;gt; ([(PieceNum, [Block])], PieceDB)&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;grabBlocks' k eligible db = tryGrabProgress k eligible db []&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;  &lt;/span&gt;&lt;span class="Keyword"&gt;where&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So we will try to grab &lt;em&gt;k&lt;/em&gt; blocks from the &lt;em&gt;eligible&lt;/em&gt; pieces from &lt;em&gt;db&lt;/em&gt;. The empty list is the accumulator in which we add the blocks we found as we go.&lt;/p&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code&gt;&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;   tryGrabProgress &lt;/span&gt;&lt;span class="DecVal Decimal"&gt;0&lt;/span&gt;&lt;span class="Normal NormalText"&gt; _  db captured = (captured, db) &lt;/span&gt;&lt;span class="Comment"&gt;-- Enough, exit&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;   tryGrabProgress n ps db captured =&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;       &lt;/span&gt;&lt;span class="Keyword"&gt;case&lt;/span&gt;&lt;span class="Normal NormalText"&gt; ps &lt;/span&gt;&lt;span class="Others InfixOperator"&gt;`intersect`&lt;/span&gt;&lt;span class="Normal NormalText"&gt; (&lt;/span&gt;&lt;span class="Function"&gt;fmap&lt;/span&gt;&lt;span class="Normal NormalText"&gt; &lt;/span&gt;&lt;span class="Function"&gt;fst&lt;/span&gt;&lt;span class="Normal NormalText"&gt; $ M.toList (inProgress db)) &lt;/span&gt;&lt;span class="Keyword"&gt;of&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;         []  -&amp;gt; tryGrabPending n ps db captured&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;         (h:_) -&amp;gt; grabFromProgress n ps h db captured&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Grabbing from the pieces already in progress minimizes the number of “open” pieces. We want to minimize this as a complete piece can be checked for correctness. Correct pieces can then be shared to others and since our download speed is dependent on our upload speed, complete pieces is key. Finding a piece is simply to carry out set intersection. If you’ve read to this point, there is a refactoring opportunity by using &lt;em&gt;M.keys&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;A smarter client, as hinted, would order the eligible pieces such that the rarest pieces were tried first. One could also toy with the idea of &lt;em&gt;pruning&lt;/em&gt;: tell the peer what pieces we already have downloaded so it won’t include them in further requests. This would keep the &lt;em&gt;ps&lt;/em&gt; parameter small in size.&lt;/p&gt;&lt;p&gt;There are three exit-points. Either there was a piece, &lt;em&gt;h&lt;/em&gt;, we can grab from that one, or there were none among the pieces in progress: we will then seek the list of pending pieces. Finally, if we are requested to grab 0 blocks, we already have enough blocks and can return those we have together with the new database.&lt;/p&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code&gt;&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;  grabFromProgress n ps p db captured =&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;      &lt;/span&gt;&lt;span class="Keyword"&gt;let&lt;/span&gt;&lt;span class="Normal NormalText"&gt; ipp = fromJust $ M.&lt;/span&gt;&lt;span class="Function"&gt;lookup&lt;/span&gt;&lt;span class="Normal NormalText"&gt; p (inProgress db)&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;          (grabbed, rest) = &lt;/span&gt;&lt;span class="Function"&gt;splitAt&lt;/span&gt;&lt;span class="Normal NormalText"&gt; n (ipPendingBlocks ipp)&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;          nIpp = ipp { ipPendingBlocks = rest }&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;          nDb  = db { inProgress = M.insert p nIpp (inProgress db) }&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;      &lt;/span&gt;&lt;span class="Keyword"&gt;in&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;          &lt;/span&gt;&lt;span class="Keyword"&gt;if&lt;/span&gt;&lt;span class="Normal NormalText"&gt; grabbed == []&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;           &lt;/span&gt;&lt;span class="Keyword"&gt;then&lt;/span&gt;&lt;span class="Normal NormalText"&gt; tryGrabProgress n (ps \\ [p]) db captured&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;           &lt;/span&gt;&lt;span class="Keyword"&gt;else&lt;/span&gt;&lt;span class="Normal NormalText"&gt; tryGrabProgress (n - &lt;/span&gt;&lt;span class="Function"&gt;length&lt;/span&gt;&lt;span class="Normal NormalText"&gt; grabbed) ps nDb ((p, grabbed) : captured)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here, we have found the piece &lt;em&gt;p&lt;/em&gt; as being in progress. So we find its &lt;em&gt;InProgress&lt;/em&gt; structure, and use &lt;strong&gt;Data.List.splitAt&lt;/strong&gt; to cut off as many blocks as possible. We may find that we can’t grab any blocks. This happens when we or other peers are already downloading all pieces. We then prune the piece &lt;em&gt;p&lt;/em&gt; from the set of eligible pieces and try again. Otherwise, we update the database and the number of pieces to grab and go back to start. Another hint: We should probably prune &lt;em&gt;p&lt;/em&gt; from &lt;em&gt;ps&lt;/em&gt; here as well :)&lt;/p&gt;&lt;pre class="sourceCode haskell"&gt;&lt;code&gt;&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;  tryGrabPending n ps db captured =&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;      &lt;/span&gt;&lt;span class="Keyword"&gt;case&lt;/span&gt;&lt;span class="Normal NormalText"&gt; ps &lt;/span&gt;&lt;span class="Others InfixOperator"&gt;`intersect`&lt;/span&gt;&lt;span class="Normal NormalText"&gt; (pendingPieces db) &lt;/span&gt;&lt;span class="Keyword"&gt;of&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;        []    -&amp;gt; (captured, db) &lt;/span&gt;&lt;span class="Comment"&gt;-- No (more) pieces to download, return&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;        (h:_) -&amp;gt;&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;            &lt;/span&gt;&lt;span class="Keyword"&gt;let&lt;/span&gt;&lt;span class="Normal NormalText"&gt; blockList = createBlock h db&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;                ipp = InProgressPiece &lt;/span&gt;&lt;span class="DecVal Decimal"&gt;0&lt;/span&gt;&lt;span class="Normal NormalText"&gt; bSz S.empty blockList&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;                bSz = len $ fromJust $ M.&lt;/span&gt;&lt;span class="Function"&gt;lookup&lt;/span&gt;&lt;span class="Normal NormalText"&gt; n (infoMap db)&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;                nDb = db { pendingPieces = (pendingPieces db) \\ [h],&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;                           inProgress    = M.insert h ipp (inProgress db) }&lt;/span&gt;
&lt;span class="Special"&gt;&amp;gt; &lt;/span&gt;&lt;span class="Normal NormalText"&gt;            &lt;/span&gt;&lt;span class="Keyword"&gt;in&lt;/span&gt;&lt;span class="Normal NormalText"&gt; tryGrabProgress n ps nDb captured&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Finally, this part grabs from the pending pieces. Either we can’t find a piece and then we can just exit. In the other case we have found a piece. We then create the blocks of the piece and insert it into the pieces in progress. The tail-call to &lt;em&gt;tryGrabProgress&lt;/em&gt; will then find it.&lt;/p&gt;&lt;p&gt;I hope the similarity to the diagram is clear. When building these tail-call mazes I usually start with the diagram sketch. Then I hand-write them in Graphviz’s dot-notation and create them. Finally I write the code.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-147140034412694675?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/147140034412694675/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=147140034412694675' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/147140034412694675'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/147140034412694675'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2009/12/on-idioms-in-haskell-torrent.html' title='On the idioms in haskell-torrent'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_ZmTZzIup5tY/SzpY4kSxL-I/AAAAAAAAABw/2M9DonRog8I/s72-c/PieceManager.png' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-3715563760340949096</id><published>2009-12-27T16:37:00.000-08:00</published><updated>2009-12-27T16:58:08.937-08:00</updated><title type='text'>On Peer Processes</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_ZmTZzIup5tY/Szf9-9KdJnI/AAAAAAAAABo/a6Hbosydy_w/s1600-h/Peer.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 180px;" src="http://2.bp.blogspot.com/_ZmTZzIup5tY/Szf9-9KdJnI/AAAAAAAAABo/a6Hbosydy_w/s320/Peer.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5420079934575814258" /&gt;&lt;/a&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;On Peer Processes&lt;/span&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;The diagram above is the control-flow in the Peer Process as it stands right now. This process is responsible for communicating with another Peer in haskell-bittorrent. This post is not about the details of the inner workings. Rather it serves to document the legend of the diagram.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;All the ellipses that are blue signifies other processes. The inbound process waits on the socket for incoming messages and sends them into the Peer process. The outbound process is a queue which dequeues messages as fast as possible to the peer in the other end. Peer Manager is the process which manages a set of peers -- we have one Peer process for each peer. Finally, Piece Manager is responsible for managing the state of the torrent: what subsets of pieces do we have and what is missing before we have the full file?&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;A little bit of terminology: a &lt;i&gt;piece&lt;/i&gt; is the smallest array of bytes we can SHA1 check for correctness. A &lt;i&gt;block&lt;/i&gt; is a subset of a piece which is transferred by the wire protocol. In practice these are always 16K although the protocol provisions for alternative sizes. The reason for this split is that the 16K blocks means we can interleave other messages in between. Further, we can get a hunch on how fast we transfer to a peer by looking at the amount of bytes we can dequeue and smaller blocks means a better granularity.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;The diagram depicts the control flow of the client. Black arrows designate how control transfers from one function to the next (usually by tail-calling this &lt;i&gt;is &lt;/i&gt;functional programming after all). The blue dotted arrows specifies synchronization points with external processes. If a blue dotted arrow &lt;i&gt;enters&lt;/i&gt; a box it usually means that control can only transfer to this point if the corresponding event tied to the arrow fires. The Piece Mgr and "Grab up to ..." is the exception from the rule however: when arrows are back and forth, it is a rpc call.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;If a blue dotted arrow leaves towards an external process it means we will wait for a synchronization towards that process before continuing out of the box.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;The current state&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;Modulo some work in the debugging and QA department, the client should be able to leech in a laboratory setting. We cheat by having no Peer Manager yet and we can essentially not really support many Peers properly yet. When the client portion stabilizes it should be fairly easy to add proper Peer managent. I hope to support leeching in the coming days.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Wanna help?&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;If you want to help out, there is plenty to do. I am still, deliberately, leaving many things open so it should be fairly easy to pick up the code from github and then do some of the simpler stuff. I've not run the excellent hlint by Neil Mitchell - so there should be an opportunity there. There is also an amortized queue implementation which could do with some documentation. Finally, the TODO list is littered with what needs to be done.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;On github: &lt;a href="http://github.com/jlouis/haskell-torrent"&gt;haskell-torrent&lt;/a&gt;.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium; "&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-3715563760340949096?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/3715563760340949096/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=3715563760340949096' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/3715563760340949096'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/3715563760340949096'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2009/12/on-peer-processes.html' title='On Peer Processes'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_ZmTZzIup5tY/Szf9-9KdJnI/AAAAAAAAABo/a6Hbosydy_w/s72-c/Peer.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-2010312872044288604</id><published>2009-12-19T15:16:00.000-08:00</published><updated>2009-12-19T16:05:15.784-08:00</updated><title type='text'>Concurrency, Bittorrent clients, and Haskell</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_ZmTZzIup5tY/Sy1kCETyF4I/AAAAAAAAABg/VdLD7gU3vpE/s1600-h/processes.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 314px; height: 320px;" src="http://2.bp.blogspot.com/_ZmTZzIup5tY/Sy1kCETyF4I/AAAAAAAAABg/VdLD7gU3vpE/s320/processes.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5417095913475807106" /&gt;&lt;/a&gt;
I have been writing code lately on a BitTorrent client in Haskell. Here is the grand old history of that effort. Many years ago, I attempted to start a client, Conjure, written in Haskell. Sadly, it really did not make it to the point where it was really usable, for me at least.

Then a couple of years passed, I became involved with programming in Erlang. Erlang has a really nice Actor-based concurrency model. Since BitTorrent is highly concurrent and event-driven it was easy to start another implementation effort in Erlang. Thus etorrent was born. Sadly, I lost interest in etorrent - partially because I am partial to statically typed languages of which Erlang is not one.

Thus, we come to this december, where I decided to figure out the state of concurrency in Haskell. To really give GHC a whirl, we need to implement something which is fairly complex. Some people implement ray tracers when toying with programming languages, some solve &lt;a href="http://projecteuler.net/"&gt;projecteuler&lt;/a&gt; problems. I ... write BitTorrent clients.&lt;a href="http://projecteuler.net/"&gt;&lt;/a&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;BitTorrent is a good maturity check. First, you need decent Disk I/O, decent network I/O and a fairly complete HTTP client. Second, the protocols are easy, but still requires some nontrivial parsing to occur. Finally, the system is fairly concurrent, so it fits nicely into concurrency models if the language has one.&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;Initial Thougths:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Initally, there is the choice of a concurrency framework. In Haskell, there are several such. The built-in &lt;b&gt;Control.Concurrent&lt;/b&gt; is fairly low level and fairly simple. At the CS department at Copenhagen University, DIKU, there is currently a course running in CSP and some students decided to use &lt;b&gt;Control.Concurrent.CHP&lt;/b&gt; by Neil Brown. I think it will suit them well for the course, but it irritated me that it mapped so weakly to the etorrent model. So &lt;b&gt;Control.Concurrent.CML&lt;/b&gt; became the basic library for concurrency. This concurrency model is not entirely unfamiliar to me: it is written by John Reppy for ML.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;The CML model is somewhat reminiscent of the Pi-calculus. In particular, we can transmit channels on channels. This gives a neat method for doing RPC-style operations. Send off a message together with a responder channel and then wait for a response on that channel. This means we are easily able to emulate most of what the Actor model has if needed.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;Haskell-torrent design:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Haskell-torrent uses a basic design, where a fairly large number of processes communicate with each other to solve the problem of uploading and downloading files. We have a limitation of one single torrent right now, but that should be fixable in time. The process diagram at the header describes the basic layout. Each box is a single process, apart from the "Peer" box, which is multiple processes. The diamond-shapes describes external communication over the network.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;b&gt;Console: &lt;/b&gt;A process responsible for User communication. The idea is to have a simple console-interface on which to log messages (it is heavily used for debugging). The Console can in time also be used for parsing user input and affecting the system. It only responds to a "quit" command at the moment. Logging is done with a LogChannel on which the Console process syncs and prints out information.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;b&gt;Main: &lt;/b&gt;Initial program entry point. Spawns everything else and is the last thing that closes again.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;b&gt;Status: &lt;/b&gt;Keeps track of various torrent-specific statuses. How much is left to download? How many seeders are there? How fast is the torrent currently? The intention is to keep this kind of information around in that process.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;b&gt;Tracker: &lt;/b&gt;Communicates with the tracker. Is a specialized HTTP client. It talks to the &lt;b&gt;Timer&lt;/b&gt; so it won't continually request the tracker for information. In due time, it should also be able to do UDP tracking. It is using &lt;i&gt;bencoded &lt;/i&gt;documents as per the tracker spec. These bcoded documents are handled as in Conjure with the monadic parser generator Parsec.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;b&gt;PeerMgr: &lt;/b&gt;Handles a set of peers. Gets lists of other peers via the Tracker process and spawns a pool of them. In due time, this process will handle choking/unchoking of peers so we don't clog the TCP/IP stack by trying to talk to everybody at once.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;b&gt;Listener: &lt;/b&gt;Listens on a TCP port and spawns off Peers when they try to connect. Not implemented at all yet, but is fairly easy to get to work.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;b&gt;OMBox: &lt;/b&gt;A very simple implementation on top of &lt;b&gt;CML&lt;/b&gt; of what is present in &lt;b&gt;Control.Concurrent.SampleVar. &lt;/b&gt;This will let the PeerMgr be able to place things for the Peer to read later and it avoids a deadlock between those two which otherwise would occur. OMBox is currently not cleaned up properly. We need some mechanism for poisoning the communication channel so it closes down again gracefully.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;b&gt;Peer: &lt;/b&gt;The system contains zero or more peers. Each peer is really four processes. One controls the state of the peer and reacts on the events from the peer. Two are responsible for sending messages to the peer: one as a queue, and one blocks on the socket. Finally, a process receives messages on the socket and then sends them to the controller, blocking in the process.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;b&gt;PieceMgr: &lt;/b&gt;Keeps track of the current piece-state. It knows what pieces we have, what we are missing and what to request next. Peers will be using it for asking what to download next.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;b&gt;FS: &lt;/b&gt;Abstracts away the file system for the rest of the client. Is implemented as a communication process which peers ask for blocks to send.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Current State:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;Currently, the client is pretty flaky. It is able to seed in a controlled lab-setting, but needs much work to be able to leech data from other clients. The TODO-list is fairly long and some of the things on it are pretty hard. But there are also many things which are fairly simple to fix. Feel free to grab anything and help out if it sounds interesting. I am deliberately keeping things simple and leaving doors open. It is my hope that even aspiring Haskell programmers might stand a chance at solving some of the things on the TODO list. I'll happily take any help I can get as in the long run, this is fairly hard to carry out as a single person. The code is on github in my &lt;a href="http://github.com/jlouis/haskell-torrent"&gt;haskell-torrent&lt;/a&gt; repository if this should indulge you.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt; &lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-2010312872044288604?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/2010312872044288604/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=2010312872044288604' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/2010312872044288604'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/2010312872044288604'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2009/12/concurrency-bittorrent-clients-and.html' title='Concurrency, Bittorrent clients, and Haskell'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_ZmTZzIup5tY/Sy1kCETyF4I/AAAAAAAAABg/VdLD7gU3vpE/s72-c/processes.png' height='72' width='72'/><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-1788024627830372924</id><published>2009-12-14T07:15:00.000-08:00</published><updated>2009-12-14T07:42:25.683-08:00</updated><title type='text'>Parsing Binary data in Erlang and Haskell</title><content type='html'>&lt;p&gt;The Bittorrent Wire protocol is a protocol used for communication
between peers in a bittorrent cloud. The protocol is explicitly
defined to balance between conserving bandwidth and being easy to
parse. Hence, it is a binary protocol, but it is fairly easy to
parse.&lt;/p&gt;&lt;p&gt;When I wrote etorrent as an experiment, I was faced with the problem
of parsing this protocol. In Erlang the task is not hard however,
since the language can pattern match on bit-patterns. I began by
defining a set of constant values, each corresponding to a message
type:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;%% Packet types
-define(CHOKE, 0:8).
-define(UNCHOKE, 1:8).
-define(INTERESTED, 2:8).
-define(NOT_INTERESTED, 3:8).
-define(HAVE, 4:8).
-define(BITFIELD, 5:8).
-define(REQUEST, 6:8).
-define(PIECE, 7:8).
-define(CANCEL, 8:8).
-define(PORT, 9:8).
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The designation 1:8 means that we need to represent the integer value
of 1 in 8 bits of information (i.e., in a byte). With these values
down, defining a decoder in Erlang is pretty straightforward:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;
%%--------------------------------------------------------------------
%% Function: recv_message(Message) -&amp;gt; keep_alive | choke | unchoke |
%%   interested | not_interested | {have, integer()} | ...
%% Description: Receive a message from a peer and decode it
%%--------------------------------------------------------------------
recv_message(Rate, Message) -&amp;gt;
    MSize = size(Message),
    Decoded =
    case Message of
        &amp;lt;&amp;lt;&amp;gt;&amp;gt; -&amp;gt;
            keep_alive;
        &amp;lt;&amp;lt;?CHOKE&amp;gt;&amp;gt; -&amp;gt;
            choke;
        &amp;lt;&amp;lt;?UNCHOKE&amp;gt;&amp;gt; -&amp;gt;
            unchoke;
        &amp;lt;&amp;lt;?INTERESTED&amp;gt;&amp;gt; -&amp;gt;
            interested;
        &amp;lt;&amp;lt;?NOT_INTERESTED&amp;gt;&amp;gt; -&amp;gt;
            not_interested;
        &amp;lt;&amp;lt;?HAVE, PieceNum:32/big&amp;gt;&amp;gt; -&amp;gt;
            {have, PieceNum};
        &amp;lt;&amp;lt;?BITFIELD, BitField/binary&amp;gt;&amp;gt; -&amp;gt;
            {bitfield, BitField};
        &amp;lt;&amp;lt;?REQUEST, Index:32/big, Begin:32/big, Len:32/big&amp;gt;&amp;gt; -&amp;gt;
            {request, Index, Begin, Len};
        &amp;lt;&amp;lt;?PIECE, Index:32/big, Begin:32/big, Data/binary&amp;gt;&amp;gt; -&amp;gt;
            {piece, Index, Begin, Data};
        &amp;lt;&amp;lt;?CANCEL, Index:32/big, Begin:32/big, Len:32/big&amp;gt;&amp;gt; -&amp;gt;
            {cancel, Index, Begin, Len};
        &amp;lt;&amp;lt;?PORT, Port:16/big&amp;gt;&amp;gt; -&amp;gt;
            {port, Port};
    end,
{Decoded, etorrent_rate:update(Rate, MSize), MSize}.
&lt;/code&gt;&lt;/pre&gt;
This is pretty straightforward idiomatic Erlang as one would write&lt;p&gt;it. We convert the numbers into tuples or atoms. The idea is that the
atom or the first element of the tuple identifies the type of the
message that was sent. Note that in idiomatic Erlang code, the process
will &lt;em&gt;crash&lt;/em&gt; if the pattern match fails. In that case, we have to
handle that problem in another janitorial process.&lt;/p&gt;&lt;p&gt;I toyed with the idea of doing the same parsing in Haskell. Initially,
my thought was that it would be rather hard to beat the Erlang code in
size. Looking at the above code, it is almost the specification of the
protocol and we can't get rid of the specification.&lt;/p&gt;&lt;p&gt;In Haskell, I started with the default construction of an algebraic
datatype. It simply reflects the tuple/atom construction of Erlang:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;type BitField = B.ByteString
type PieceNum = Integer
type PieceOffset = Integer
type PieceLength = Integer
data Message = KeepAlive
        | Choke
        | Unchoke
        | Interested
        | NotInterested
        | Have PieceNum
        | BitField BitField
        | Request PieceNum PieceOffset PieceLength
        | Piece PieceNum PieceOffset B.ByteString
        | Cancel PieceNum PieceOffset PieceLength
        | Port Integer
deriving (Eq, Show)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If it seems more verbose than the initial Erlang counterpart, then it
fools you. In the above, we also encode the types of the messages -
but this is the only place where we would have to designate the types
in the whole program. Type reconstruction by inference will figure out
the details for us.&lt;/p&gt;&lt;p&gt;I expect my data to be presented to me via lazy bytestrings (see
&lt;strong&gt;Data.ByteString.Lazy&lt;/strong&gt;). It also turns out that George Giorgidze built
the HCodecs package. This package provides decoders for MIDI, Wave and
SoundFont2 files. But the real gem of the package is the development
of binary parsers for ByteStrings. This turns out to be exactly what
we would like to process.&lt;/p&gt;&lt;p&gt;The parser is a monad. So we can use do-notation to decode the
messages. Here is an example of decoding the &lt;em&gt;PIECE&lt;/em&gt;-message:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;7 -&gt; do pn &lt;- fromIntegral &lt;$&gt; getWord32be
   os &lt;- fromIntegral &lt;$&gt; getWord32be
   c &lt;- getRemainingLazyByteString         return $ Piece pn p c &lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This looks nice, but the &lt;code&gt;&lt;$&gt;&lt;/code&gt; from &lt;strong&gt;Control.Applicative&lt;/strong&gt; hints
somewhat at where this will go. Note that we are not using the full
power of the monad. In particular, we don't use earlier results from
the monad to decide what to do next. Since there is no dependency
chain, it means we can just utilize that every monad is also an
applicative functor. In particular we can define&lt;/p&gt;&lt;pre&gt;&lt;code&gt;7 -&gt; Piece    &lt;$&gt; gw32 &lt;*&gt; gw32 &lt;*&gt; gw32 &lt;*&gt; getRemainingLazyByteString
...
where gw32 = fromIntegral &lt;$&gt; getWord32be
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;using the applicative functor to solve the game. With this down, the
rest of the parser is easy:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;decodeMsg :: Parser Message
decodeMsg =
do m &lt;- getWord8        case m of          0 -&gt; return Choke
    1 -&gt; return Unchoke
    2 -&gt; return Interested
    3 -&gt; return NotInterested
    4 -&gt; Have     &lt;$&gt; gw32
    5 -&gt; BitField &lt;$&gt; getRemainingLazyByteString
    6 -&gt; Request  &lt;$&gt; gw32 &lt;*&gt; gw32 &lt;*&gt; gw32
    7 -&gt; Piece    &lt;$&gt; gw32 &lt;*&gt; gw32 &lt;*&gt; getRemainingLazyByteString
    8 -&gt; Cancel   &lt;$&gt; gw32 &lt;*&gt; gw32 &lt;*&gt; gw32
    9 -&gt; Port     &lt;$&gt; (fromIntegral &lt;$&gt; getWord16be)
    _ -&gt; fail "Incorrect message parse"
where gw32 = fromIntegral &lt;$&gt; getWord32be
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And there you have it: A Haskell version which is more succinct than
the Erlang version while being type safe in the process. The reason it
works is due to the clever type class hierachy in Haskell: The parser
is a monad and all monads are applicative functors. This lets us
combine parsers cleverly into an effective decoder for wire protocol
messages.&lt;/p&gt;&lt;p&gt;I do hope it is fairly efficient. Protocol decoding is probably going
to be a hot place in the program.&lt;/p&gt;&lt;p&gt;&lt;a href="http://hackage.haskell.org/packages/archive/bytestring/0.9.1.4/doc/html/Data-ByteString.html"&gt;Data.ByteString.Lazy&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://hackage.haskell.org/cgi-bin/hackage-scripts/package/HCodecs"&gt;HCodecs&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://github.com/jlouis/etorrent/tree/"&gt;Erlang code&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://github.com/jlouis/haskell-torrent/tree/"&gt;Haskell code&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-1788024627830372924?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/1788024627830372924/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=1788024627830372924' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/1788024627830372924'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/1788024627830372924'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2009/12/parsing-binary-data-in-erlang-and.html' title='Parsing Binary data in Erlang and Haskell'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-4995338752116679759</id><published>2009-10-05T06:10:00.000-07:00</published><updated>2009-10-05T07:05:53.054-07:00</updated><title type='text'>Behaviour Driven Development is...</title><content type='html'>So I spent the time necessary to look into this Behavior-driven-development idea. Summing it up in one sentence: "BDD is computable specifications". That is, you write a specification which is a program. This program takes as input a component and produces as output one of &lt;i&gt;success&lt;/i&gt; or &lt;i&gt;failure. &lt;/i&gt;A driver program then tries all the behavior-programs in succession and produces a report to the user or programmer.&lt;div&gt;
&lt;/div&gt;&lt;div&gt;This is a natural extension of test-driven-development, where one writes a computable test for each component in the software system before the component itself is written. The insight is that these tests are specification behaviors in the system so one can name them as such rather than as "tests".&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;The idea of building a model of the specification which can be computed is not new. There are strong similarities with Design by Contract (Meyer, 1986) and I am sure you can find older examples in the Lisp community with strong similarities. The BDD term is not defined rigorously, in tradition with most software development terms, sadly. Thus it means different things to different people. Some will say that DbC &lt;i&gt;is &lt;/i&gt;BDD and some will say that it is not.&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;Main insight: If you have a specification written in English prose, you have no way to automatically check if the program lives up to the specification. You can only test it manually, which is a tedious, cumbersome process prone to failures. If the process is computable, we can get the machines to work for us and work out the details.&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;Getting the machine to understand the specification means it needs to be precisely specified, like a computer program. Our hope is that while the program specified may be complex, the specification itself is not. Thus we can specify the behavior of the program and have some assurance that the specification is correct. If the specifications are as hard to write as the main program it turns out to be turtles all the way down.&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;There are several ways we could attempt to write down a formal specification. We could, for instance, use Hoare logic - meaning we specify the behavior of the program in an assertion language different from the implementation language. One then tests the specification by verifying that the rules of HL is fulfilled.&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;Another path is to make the type system strong enough to capture formal logic and specify the program in the type system. To achieve this, one must have a type system much more expressive and powerful than what most mainstream programming languages provide. Testing the specification then amounts to a type check. &lt;i&gt;Aside: &lt;/i&gt;Expressive type systems like the one found in Haskell or ML provides an approximation to this complete correctness. When we say that "type systems eliminate bugs in the program", we mean that the approximation caught a bug which would otherwise have slept into the program. Note that (static) type systems are a knob you can turn. The more expressive the system, the better an approximation to the specification. Turned to 11, the type system &lt;i&gt;is&lt;/i&gt; the specification, but most programmers abhor the idea of programming at this level of precision. &lt;i&gt;End of aside.&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;
&lt;/i&gt;&lt;/div&gt;&lt;div&gt;The BDD path is to define the specification in the host-language as a program itself. Usually this can be done by a compiler from a domain-specific language (describing behaviors) into the language in which the tested component is written. The advantage of this approach is that you don't need a separate tool chain but can reuse the existing one for running your tests. Testing the specification is done by running the spec-program against the implemented components and observing their behavior.&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;Thus, BDD is a runtime-oriented path to verifying the program specification. We check the program correctness by executing the test. I would imagine that we also design the behaviors such that they cover all paths of the component. This is fairly easily achieved by a coverage checker.&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;Personally, I see the BDD-idea as a poor-mans formal specification -- it is what you end up with if you just use the available tools rather than define a spec-language. You end up with exactly the same problems as most formal specifications any way: Explaining and understanding what they mean is hard. The problem can somewhat be alleviated by clever tricks where the actual code is hidden in a textual presentation which normal people would have a chance at understanding. This part of BDD circles around the problem of defining a good User Interface for the specification in question. This is the part of BDD I find the most interesting.&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;Also, the fine merits of BDD might be the first casualty to any deadline. Deadlines kill. Anything which can be placed into the scheme of "short-term good, long-term bad" and incurs technical debt is turned on as soon as the deadline approaches. Everything falls to a fast cost-benefit analysis. The problem here is that there are no measurable way to evaluate different software development methodologies so an equally good and faster analysis is thrown dice.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-4995338752116679759?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/4995338752116679759/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=4995338752116679759' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/4995338752116679759'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/4995338752116679759'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2009/10/behaviour-driven-development-is.html' title='Behaviour Driven Development is...'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-4508143707545715443</id><published>2009-10-01T05:20:00.000-07:00</published><updated>2009-10-01T06:06:52.130-07:00</updated><title type='text'>Things I love using PostgreSQL</title><content type='html'>Let there be no doubt, that I like to use PostgreSQL as my main database of choice. I like my databases to use SQL, a declarative language, for my operations and queries. I guess the reason for this is my strong knowledge and experience with functional languages in general. The path from functional programming to SQL is rather short.&lt;div&gt;
&lt;/div&gt;&lt;div&gt;This is a list, in no particular order, why I love PostgreSQL. Note that many of these things are far better explained in the excellent documentation of PgSQL, so you can look up things there.&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;First, PgSQL takes types seriously. Data is typed from the outset and you need to convert data to match the given type. This means we rule out dates like '2009-02-31' by default. MySQL fails this blatantly for instance. Also, it allows us to import data into a typed language fairly easily as soon as we have a type mapping defined.&lt;/li&gt;&lt;li&gt;PgSQL has TOAST-storage. This includes several techniques like compression and out-of-line storage. What this means is that you can process data faster since disk I/O is what tend to kill database performance as soon as your data get beyond 'fits-in-memory'.&lt;/li&gt;&lt;li&gt;PgSQL can do partial indexes. I keep partial indexes on unprocessed data. Hence, even if the table contains billions of rows, I can quickly grab the unprocessed records and process them. I also keep some partial indexes around for performance.&lt;/li&gt;&lt;li&gt;PgSQL does bitmap index scans. This can combine several indexes into a bitmap telling the system what rows or pages to retrieve. Again, it lowers the amount of disk I/O needed to access data. Wonderful for complex queries.&lt;/li&gt;&lt;li&gt;PgSQL uses Multi-version concurrency control (MVCC). This means you can do backups of your database without having to worry too much about what happens while you take the backup. It also means you can be sure that your ACID compliance is done correctly without affecting the performance of individual queries.&lt;/li&gt;&lt;li&gt;You can disable autocommit by default in the psql client. No more accidentially destroying data.&lt;/li&gt;&lt;li&gt;Data Definitions (the DDL) are transaction safe! You can undo an ALTER TABLE statement if it goes wrong. It makes data manipulation into a blissful operation: Alter the table, CREATE VIEW to get the old view of the data back. COMMIT the transaction. You can do this on a live system, which is wonderful.&lt;/li&gt;&lt;li&gt;Need to add millions of rows? Use the COPY command (or its psql client \copy cousin). It is a lot faster than INSERT INTO for large amounts of data. My work desktop machine with an old SATA disk imports millions of (rather large) rows in a matter of minutes. This including raising a couple of indexes on the data.&lt;/li&gt;&lt;li&gt;Need to export data? CREATE TEMPORARY TABLE export ( ... ), fill it with a SELECT statement, fire up COPY. Done. I've built many reports directly in the guts of the psql prompt with a couple of VIEWs and this technique.&lt;/li&gt;&lt;li&gt;PgSQL is fast, especially for complex queries. This is especially true for recent PostgreSQL releases, where performance was the optimization target. And it paid off. Combine it with a query cache or a dedicated key-value store and you have a very stable, robust and fast platform which can scale to thousands of simultaneous users.&lt;/li&gt;&lt;li&gt;Built-in full-text-search. I've used this to answer search queries from users on the data with ease.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;And I get to combine PgSQL with Ocaml, awk and R. Don't underestimate the data manipulation power of awk, it is extremely fast.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-4508143707545715443?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/4508143707545715443/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=4508143707545715443' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/4508143707545715443'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/4508143707545715443'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2009/10/things-i-love-using-postgresql.html' title='Things I love using PostgreSQL'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-8940810814119144405</id><published>2009-09-02T06:40:00.000-07:00</published><updated>2009-09-02T06:58:49.926-07:00</updated><title type='text'>The gatekeeper role</title><content type='html'>The single most important role in a software project, be it Open or closed source is the role of the gatekeeper. This person, or group of persons oversees the general progression and development of code in the project. Their responsibility is to read through the code of all commits and review them for correctness before they are let into the source code baseline upon which further development happens.

There are many advantages in having a gatekeeper role in a software project. First and foremost, all code gets some review. Second, the gatekeeper can usually direct people to reuse existing code rather than write their own (At one time, the pine mail reader had several places in which file I/O operations happened for instance). Third, the gatekeeper can make sure that coding guidelines and structure is adhered to.

If you are serious about the development, the gatekeeper must have the power of vetoing &lt;span style="font-weight: bold;"&gt;everything&lt;/span&gt;. It doesn't matter if it is the final release theres at stake. If the GK says no, it ain't gonna happen. This is important to ensure the quality in the project. Also, the GK should not have roles beyond the role of reviewing software.

The best thing you can do for a software project is to get a model where people are willing to share their code patches with a mailing list so other people can chime in on the code. While the GK has the role of getting people to talk to each other and steer the project in general, getting other developers to work together is very important.

I've seen to many projects with cage-isolation in the sense that each developer has their area of responsibility. It works fine until someone quits. Also, the GK hat could walk around among the most experienced developers.

As a software vendor, you win if you can continue to improve the quality of your product and the skill of your creative software people. Constructive critique is a tremendous way to get this done.

I don't give much for the idea of "Agile" development in general, but wether you adopt it or not, the GK role is crucial anyway. In some kind of perverted way, leading Open Source projects can't be wrong -- and you will find that almost all of them employ a de-facto gatekeeper somewhere.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-8940810814119144405?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/8940810814119144405/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=8940810814119144405' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/8940810814119144405'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/8940810814119144405'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2009/09/gatekeeper-role.html' title='The gatekeeper role'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-786714017413186238</id><published>2009-07-20T10:12:00.000-07:00</published><updated>2009-07-20T10:23:15.819-07:00</updated><title type='text'>Using Twelf to lift code quality in ExSML</title><content type='html'>The ExSML project is a fork of Moscow ML which aims to replace the current MosML runtime with one based on LLVM. In Moscow ML the following things happen when you compile a file of SML source code:

First the file is lexed and parsed into an abstract syntax tree. Then elaboration happens. In the elaboration phase we resolve, through type inference, the types of all expressions. We also resolve overloading such that all types are explicit from then on.

Second the program is compiler by the frontend compiler into an Intermediate Representation (IR) called Lambda. This is an extended lambda calculus which is far simpler then core ML. At this step we also compile pattern matches into simple decision DAGs via a pattern match compiler by Peter Sestoft.

The backend compiler then transforms lambda into bytecode which the mosml runtime reads and executes.

We want to cut at the IR and produce LLVM code instead. However, there is a slight problem: LLVM is essentially a typed assembler whereas Lambda is untyped lambda calculus. To get around this, we have decided to use a typed variant of Lambda. This means we need a type system and we want the type system to be safe.

Enter Twelf. The plan is to formalize the safety properties of the type system in Twelf. We are a far way from the goal at the moment as our Twelf-representation lacks many important things: reference operations, exceptions, reference state, recursive types, sum types, product types and polymorphism. But we hope to be able to add these to the representation with a little work.

Knowing our language is type safe will give us some obvious advantages later on when we begin doing code transformations.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-786714017413186238?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/786714017413186238/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=786714017413186238' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/786714017413186238'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/786714017413186238'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2009/07/using-twelf-to-lift-code-quality-in.html' title='Using Twelf to lift code quality in ExSML'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-2363537665597363942</id><published>2009-05-13T05:57:00.000-07:00</published><updated>2009-05-14T02:20:18.877-07:00</updated><title type='text'>Arr, we be killin' the newspapers, mate</title><content type='html'>Lately, we saw the emerging trend that newspapers are beginning to die. Good riddance. I've never bought a newspaper, I will never buy a newspaper, and I am pretty sure people younger than my age won't as well. The market is gone, so how are newspapers going to survive?

Currently, they have placed their hope in advertising. As Steve Ballmer has said, it is all about advertising, advertising, advertising! This to the point where newspaper sites are infested to the brink with ugly colored flash behemoths in odd colors with nasty animations. Don't even get me started on what I want to do to the marketdroid who imagined that &lt;span style="font-weight: bold;"&gt;sound &lt;/span&gt;is a good idea, but let me divulge it includes a meeting with Mr. Garotte at the very least. I don't buy that advertising will be helping them anytime soon.

First, I love to block Ads. I utterly despise ads, so I block them with AdBlock+ in Firefox. I don't want some idiotic marketdroid to invade and misuse my precious desktop space. Goodbye. This also has the nice side-effect that it undermines the Ad-industry and every industry basing their income system on Ads. Luckily, the majority of people can't block it, because they are too uneducated to install ad blocking software. Consequence: I can have my free stuff without paying for it or seeing Ads.

But the majority will learn eventually, and that will be the slow and effective demise of Newspapers as we know them. We already face the first part of the "crisis" in Denmark as a major danish newspaper will have us pay for their service. This is a really good thing! I would probably like to pay others who use their time producing interesting material I can read about topics in my sphere of interest. But I also do not lament the death if everything I can get is the "Extended nobility package" where I get Wine and Restaurant reviews, news distilled to 99% irrelevance off of Reuters, and "Feminist" crap. Either newspapers will get a new networked revival or they will die.

To survive, newspapers must produce something with a greater pastime value than perusing the /b/ board off 4chan (Might I add that the /b/ board is the sewage spill of the internet) -- or else irrelevancy will hit them where it hurts the most.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-2363537665597363942?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/2363537665597363942/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=2363537665597363942' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/2363537665597363942'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/2363537665597363942'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2009/05/arr-we-be-killin-newspapers-mate.html' title='Arr, we be killin&apos; the newspapers, mate'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-3354589434217203090</id><published>2009-05-09T16:03:00.000-07:00</published><updated>2009-05-09T16:13:53.217-07:00</updated><title type='text'>Static/Dynamic typing discussions are uninteresting</title><content type='html'>&lt;p&gt;People are talking about the RailsConf keynote "What killed Smalltalk?" by Robert Martin. You can watch the &lt;a href="http://blip.tv/file/2089545"&gt;keynote talk&lt;/a&gt; at blip.tv. Of course, the Smalltalk guys weren't slow to &lt;a href="http://www.cincomsmalltalk.com/blog/blogView?showComments=true&amp;amp;printTitle=Smalltalk:_Our_Death_has_been_Exaggerated&amp;amp;entry=3419278263"&gt;answer&lt;/a&gt; the argument, which revolves around the fact that code easily becomes cluttered in Smalltalk programs. The arch-angel that will save this problem with Ruby is, of course, unveiled to be "Test Driven Development" much to the rejoice of the Audience.&lt;/p&gt;&lt;p&gt;Martins presentation is flawless in the sense that he does a really good job at capturing the audience. Another interesting point is that he has no slides, just a stack of paper cards on which the key points of the talk is written. In Academia, this would not have worked for most talks I note. Sooner or later you'll at least need a blackboard to draw up and explain a formulae or similar.&lt;/p&gt;&lt;p&gt;A side argument however is that the dynamically typed languages won over the statically typed languages. It is driven by the observation that Java now has reflection, which must mean it is dynamically typed, right? Unfortunately, this viewpoint is misguided in the sense it lacks delicate detail about the situation at hand. This blog postseeks to remedy the omission.&lt;/p&gt;&lt;h2&gt;Static vs. Dynamic typing is uninteresting&lt;/h2&gt;&lt;p&gt;Taking the argument as being static versus dynamic typing alone is a moot point. Here is why: suppose we want to embed a Java program in Ruby. This can easily be done, if we choose to ignore the types and strip them out. In fact, any statically typed language can be embedded in the dynamic world by stripping the types away. After all, assembly language is untyped, so compilers will at some point have to eschew the typing information for good in their transformation.&lt;/p&gt;&lt;p&gt;But any dynamically typed language can also trivially be embedded in a language with static type discipline. We invent a new type, lets call it &lt;strong&gt;T&lt;/strong&gt; and then proceed to give everything type &lt;strong&gt;T&lt;/strong&gt;. This is what
happens inside the Ruby interpreter written in C. Of course we must then have a way to discriminate the different values of &lt;strong&gt;T&lt;/strong&gt; but this is exactly what low-level operations will do in a dynamically typed
language anyway.&lt;/p&gt;&lt;p&gt;Thus we have a way to convert back and forth between the static and dynamic world, so why do we not regard them as equal? We know they are not equal, but in what kind of sense are they not equal? If we convert from Java to Ruby and then back to the static world, everything will have the magic type &lt;strong&gt;T&lt;/strong&gt;. We have lost the Java type information in the process. But this merely states that the conversion is not
isomorphic.&lt;/p&gt;&lt;p&gt;If one thinks about it, there is little to be gained by studying the trivial world of dynamic typing: everything would look the same once it has been converted into the dynamic world. If we look at the static world, we obtain a different picture.&lt;/p&gt;&lt;h2&gt;Meta-theoretic properties, baby!&lt;/h2&gt;&lt;p&gt;Since Ruby would be trivially typable in the statically typed world, the whole debate about static typing versus dynamic typing falls apart. It is uninteresting because the level at which we communicate is too low. What really matters are the properties of the type systems: what kind of guarantee do we have from the type system weighing in favor of complex type systems -- and the hassle of maintaining well-typed programs weighing in favor of trivial type systems.&lt;/p&gt;&lt;p&gt;In Ruby, or Smalltalk, the contents of a value (an object) can be changed without having to retype big parts of the program. This is not always true in Java. It holds when there is a certain subtyping relationship between the objects in question, but it can't be done in general, since there is no "duck typing" available. &lt;em&gt;Reflection&lt;/em&gt; in Java adds the magic type &lt;strong&gt;T&lt;/strong&gt; so to speak so we can embed any type in
a &lt;strong&gt;T&lt;/strong&gt; and we can project any type out of a &lt;strong&gt;T&lt;/strong&gt;. The latter might incur a runtime-error when done however; this is no different from Ruby where everything might potentially incur runtime errors.&lt;/p&gt;&lt;p&gt;The static type system on the other hand tends to guarantee varying levels of &lt;em&gt;type safety&lt;/em&gt;. If the program is well typed (read: passes the type checker), then there will be no type errors at runtime. Since there will be no errors at runtime, we can just strip away type discrimination at runtime as well -- yielding great &lt;a href="http://shootout.alioth.debian.org/u64q/benchmark.php?test=all&amp;amp;lang=all&amp;amp;box=1"&gt;speedup&lt;/a&gt; compared to dynamically typed languages.&lt;/p&gt;&lt;p&gt;The difference is that Java, even with the addition of &lt;em&gt;reflection&lt;/em&gt;, still have better meta-theoretic properties than Ruby, though we have added a way to poison the type system safety. This is not at all new to most static type systems out there, which allows coercing types unsafely if you really know what you are doing.&lt;/p&gt;&lt;p&gt;Java is also a fairly simple language from a type-complexity perspective. ML is much further up the scale. And Haskell is even further up, with many more complex concepts in the type system. Most
theorem provers rely on even &lt;em&gt;more&lt;/em&gt; complex type systems to get their work done. In fact they have type system; so powerful they can, in principle, encode correctness specifications of the program. You do
not really need unit tests at that level. But it becomes increasingly harder to write correct programs, so most proponents of static typing settles on something further down the scale.&lt;/p&gt;&lt;p&gt;Also, most advanced languages will infer (deduce) types automatically. For ML it is customary to just specify types at the API-level and omit typing details elsewhere. This brings some of the ease from dynamic typing back into static typing.&lt;/p&gt;&lt;h2&gt;Wrapping up&lt;/h2&gt;&lt;p&gt;One can't possibly say that "dynamic typing won" when the world is much more complex. In reality one must ask: "What static type system won?"; which is not trivially answerable and subject to individual level of expertise, viewpoint, ideology, religion and what not.&lt;/p&gt;&lt;p&gt;What is clear though should be that the type systems of Java with reflection and Ruby are far from equal. Neither are Java or Haskell for instance. Or Haskell and Coq. Or...&lt;/p&gt;&lt;p&gt;Based on that, I think the view Mr. Martin puts forth is a bit too quick and simplified. I also hope we can move beyond the simple dynamic/static debate which is hardly interesting.&lt;/p&gt;&lt;p&gt;And finally the snide remark: What is &lt;em&gt;interesting&lt;/em&gt; is the viewpoint that type systems are chastity belts or impose Bondage &amp;amp; Discipline upon programmers when I have just shown, by trivial conversion, how to
embed dynamic features into any statically typed language. You just got the skeleton key to the chastity belt, should you need it!&lt;/p&gt;&lt;p&gt;
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-3354589434217203090?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/3354589434217203090/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=3354589434217203090' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/3354589434217203090'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/3354589434217203090'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2009/05/staticdynamic-typing-discussions-are.html' title='Static/Dynamic typing discussions are uninteresting'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-7011477775632701855</id><published>2009-04-01T05:47:00.000-07:00</published><updated>2009-04-01T05:56:21.604-07:00</updated><title type='text'>Moving bits in a pirated world for fun and profit</title><content type='html'>&lt;h2&gt;The premise&lt;/h2&gt;&lt;p&gt;As soon as a movie/episode is out in the wild on the internet it is
going to be spread like a wildfire. To circumvent this, the
movie/series industry have to change their stance towards copyright
protection. The best they can hope for is to slow down the spreading,
because it is technically impossible to stop.&lt;/p&gt;&lt;p&gt;The right stance is that of convenience. Currently it is more
convenient to download from the internet than it is to buy the
movie. The internet download is almost instantaneous, the buy can take
days to finish. For a series on a channel the problem is that the
episodes will air at specific days of the week, whereas the episode on
the internet can be viewed at your discretion when you want.&lt;/p&gt;&lt;p&gt;Convenience is a powerful and important tool to harness if you want to
battle piracy. Most people know there will be no next episode if they
don't pay for it in the first place. Most people do want to pay a fair
price for a series.&lt;/p&gt;&lt;p&gt;If the MPAA did harness the convenience, they would have an increased
market quickly. I hypothesize that episodes pirated from the internet
is done also by legitimate buyers who just was not home the day the
episode happened to be aired.&lt;/p&gt;&lt;h2&gt;The idea&lt;/h2&gt;&lt;p&gt;Occams Razor applied to the problem. You have no need for a new wild
intricate system. You just need some basic, conservative tricks. An
episode will be distributed by bittorrent in encrypted form before the
airing. This means that people on a measly 1 megabit line can download
around 5-6 HD quality episodes per week. If the distribution happens
one week in advance, there is ample time to get the data out.&lt;/p&gt;&lt;p&gt;Next, on the airing you distribute the key, unlock the encryption and
proceed to view the episode. At the same time an &lt;em&gt;unencrypted&lt;/em&gt; file is
produced, so the DRM is thrown out with the bathwater. This step is
important guys! If the data is laden with DRM it has &lt;em&gt;less&lt;/em&gt; value
compared to the pirated one.&lt;/p&gt;&lt;p&gt;A season for a series costs $5 at maximum. The customer pays these
money for the ease of getting things delivered to his doorstep each
week, and to pay in advance for the production. In fact, production
starts when the donation box has been filled to a certain point where
it is profitable to start a new season, rather than being a gamble.&lt;/p&gt;&lt;h2&gt;Why nobody has done this&lt;/h2&gt;&lt;p&gt;Hypothesis: MPAA and RIAA are not desparate, are not operating at a
loss and will continue to bully around. In general, money is still
being made or shops would have closed up long ago. Hence, they have no
intention in building a smarter distribution scheme because their
current scheme works. After all they have TV channels and Cinemas as
their primary distribution form and it works fine. &lt;/p&gt;&lt;p&gt;So then, why go after the pirates? Greed? No, they fear somebody
creates a distribution system like the one above and takes them out of
business. In one year the smarter distribution system could mean the
end for their current structure which they are milking for money as a
cash cow. They don't want disruptive technology to enter the
marketplace at this moment.&lt;/p&gt;&lt;p&gt;The solution is to create a simple equation "internet = piracy" and
bang that into the heads of people. This is their only hope as it will
build a barrier making them able to cash in for a longer time before
their structure is eradicated.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-7011477775632701855?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/7011477775632701855/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=7011477775632701855' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/7011477775632701855'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/7011477775632701855'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2009/04/premise-as-soon-as-movieepisode-is-out.html' title='Moving bits in a pirated world for fun and profit'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-1246341554796432097</id><published>2009-03-29T07:21:00.000-07:00</published><updated>2009-03-29T07:22:30.537-07:00</updated><title type='text'>An update on the Moscow ML for LLVM</title><content type='html'>&lt;p&gt;The Moscow ML LLVM project is having a blast these days. First, we got
autotools into the project, so everything is now built from
autotools. Then we eliminated a lot of magic in the
code base. Importantly, you can now reorder C functions without fear of
the run-time breaking down and getting out of sync with the compiler.&lt;/p&gt;&lt;p&gt;We killed the threaded code interpreter. It is presumably fast, but it
also hampers our further development with LLVM, so it had to go. The
code base ended up much cleaner.&lt;/p&gt;&lt;p&gt;Then we coded up a simple opcode tracer that can write out the
sequence of opcodes as they are executing. If you can simplify an
error to the point where a trace can be used, then it tends to be easy
to identify the problem with the tracer. It did uncover a couple of
bugs.&lt;/p&gt;&lt;p&gt;The final nail in the coffin is the regression framework. We imported
the regression framework from mlton and proceeded to add the tests
that makes sense for mosml. We have 2 failing tests out of 88 at the
moment. The original mosml passes all 88 and our version fails in 2 of
those. Both these are in I/O, so it is narrowed down to a few commits
at the moment. It is wickedly cool to have a working regression
framework again.&lt;/p&gt;&lt;p&gt;We also killed the C preprocessor on all Standard ML files. Autoconf
gives us what we need, so it is fairly easy to generate the correct
files.&lt;/p&gt;&lt;h2&gt;Looking forward&lt;/h2&gt;&lt;p&gt;In the future, we intend to clean up the run-time some more and
systematically begin getting more test cases to pass correctly, and
construct the correct install-targets. We also need to get the
standard ml front-end code into the game. Then we add 2003 Basis
support and begin simplifying the back-end such that we can add LLVM on
top if it. Another nail is the eradication of all C-compiler warnings
and a simplification of the opcodes.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-1246341554796432097?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/1246341554796432097/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=1246341554796432097' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/1246341554796432097'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/1246341554796432097'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2009/03/update-on-moscow-ml-for-llvm.html' title='An update on the Moscow ML for LLVM'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-1241214529351668739</id><published>2009-03-28T05:51:00.001-07:00</published><updated>2009-03-28T05:54:23.533-07:00</updated><title type='text'>Graphviz talk slides</title><content type='html'>So I did a small talk (in danish) on what Graphviz can do for you in the local LUG. But I have been a slacker and did not put up the slides yet. This remedies it:

&lt;a href="http://dl.getdropbox.com/u/196031/graphviz-talk.pdf"&gt;Graphviz talk slides&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-1241214529351668739?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/1241214529351668739/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=1241214529351668739' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/1241214529351668739'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/1241214529351668739'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2009/03/graphviz-talk-slides.html' title='Graphviz talk slides'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-6384965645121021286</id><published>2009-03-04T15:00:00.000-08:00</published><updated>2009-03-04T15:20:37.759-08:00</updated><title type='text'>LLVM Update</title><content type='html'>&lt;p&gt;People tracking along will know that I am in the process of writing an
LLVM backend for Moscow ML. There are several ways in which one can
do this, so one has to be decided upon and tried out. It is however
clear we need a way to manipulate and output LLVMs IR, so I set upon
writing an set of bindings.&lt;/p&gt;&lt;p&gt;These bindings are not using an FFI to call into the C++ LLVM
code. Rather they produce the IR assembly from an internal SML-like
data structure. This approach has the disadvantage that it is more
work to maintain. On the other hand, the OCaml bindings passes around
llvalues all over the place so very few bugs will be captured at
compile time (we could do oh so much better had we had dependent
types).&lt;/p&gt;&lt;p&gt;I have written LLVM as a datatype in SML and then written about 40
percent of a type checker for it. The process is very simple as soon
as one has converted LLVM rules into SML datatypes. Here is a part of
the Type module&lt;/p&gt;&lt;pre&gt;&lt;code&gt;datatype t =
    T_Integer of int
  | T_Real of float_ty
  | T_Fun of {return: t, params: t list}
  | T_Struct of {elements: t list, packed: bool}
  | T_Array of {ty: t, length: int}
  | T_Pointer of t
  | T_Vector of {ty: t, length: int}
  | T_Opaque
  | T_Void
  | T_Label
  | T_Top
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which is a straightforward adaptation of the Language Reference of
LLVM. I could simplify it more, but at the moment there is little need
for that.&lt;/p&gt;&lt;p&gt;Type checking is carried out by a set of combinators. They &lt;em&gt;probably&lt;/em&gt;
form a monad (Haskell guys can relate this to a variant of the Either
monad with a Writer on it as well. It should be straightforward to
write it down as one or use a transformer stack to achieve the same. I
have not given it much thought though).&lt;/p&gt;&lt;p&gt;The checking basis is the datatype&lt;/p&gt;&lt;pre&gt;&lt;code&gt;datatype t_check = Ok | Wrong of string list
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Immediately, a helper is introduced&lt;/p&gt;&lt;pre&gt;&lt;code&gt;fun type_fail str = Wrong [str]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And a function for running a checker&lt;/p&gt;&lt;pre&gt;&lt;code&gt;fun run checker_fun ty =
 case checker_fun ty of
   Ok =&amp;gt; ()
 | Wrong errors =&amp;gt;
     &amp;lt;&amp;lt;Print out type checking errors&amp;gt;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Note that run will have type (ty -&gt; t_check) -&gt; ty -&gt; unit. The
question is then how to produce type checkers. This is done with
combinators but of course:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;(* Logical or for types, consider monadizing *)
fun or checker1 checker2 ty =
case checker1 ty of
 Ok =&amp;gt; Ok
| Wrong err1 =&amp;gt; case checker2 ty of
         Ok =&amp;gt; Ok
       | Wrong err2 =&amp;gt; Wrong (List.concat [err1, err2])
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The 'or' checker tries the first checker and if it fail it tries the
second, picking up any errors on the way. It is also easy to assert
that a given type must be the base type of a vector type:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;fun vectorized checker1 vty =
case vty of
 T_Vector {ty, ...} =&amp;gt; checker1 ty
| _ =&amp;gt; type_fail "Checked type is not a vector type"
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Perhaps one could be giving a better error message here by capturing
the eventual error output from checker1, but this has not been done
yet.&lt;/p&gt;&lt;p&gt;Primitive checks are just doint what they are supposed to do. The
assertion for an integer looks like the following:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;fun assert_int ty =
case ty of
 T_Integer _ =&amp;gt; Ok
| _ =&amp;gt; type_fail "Type is not of integer type."
&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Usage&lt;/h2&gt;&lt;p&gt;An addition in LLVM is either an integer, a float or a vector of
these. Aha:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;val assert_int_float = or assert_int assert_float
val assert_add = or assert_int_float (vectorized assert_int_float)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Hopefully this shows the succinctness of the approach.&lt;/p&gt;&lt;p&gt;EDIT: Layout was bad. Fixed
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-6384965645121021286?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/6384965645121021286/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=6384965645121021286' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/6384965645121021286'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/6384965645121021286'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2009/03/llvm-update.html' title='LLVM Update'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-1631738356818116816</id><published>2009-02-06T10:02:00.000-08:00</published><updated>2009-02-06T10:19:46.847-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SML'/><category scheme='http://www.blogger.com/atom/ns#' term='parsing'/><category scheme='http://www.blogger.com/atom/ns#' term='code'/><title type='text'>Combinator parsing, part 3</title><content type='html'>In the 3rd installment of combinator parsing, we will write the actual parser and use it for parsing our original problem from part 1. Parsers have a specific type, namely
&lt;pre&gt;type ('a, 'b) parser = 'a -&gt; 'b * 'a
&lt;/pre&gt;so a parser takes some type, 'a, breaks off part of the stream returning 'b and the rest of the stream. Our parser will have type (token list, exp) parser, as it will process a token list and produce an exp. We begin by defining two exceptions
&lt;pre&gt;exception Punt
exception ParserError
&lt;/pre&gt;These are used a bit differently. The Punt exception is used whenever the parser wants to backtrack and attempt another parse. ParserError is going to be used when the parser fails to parse the input stream.

Wrapping up the parser system is a function we use for parsing stuff. It handles the task of checking there are no excess data when the parse finishes. It also handles the coercion of top-level punts into general parser errors.
&lt;pre&gt;fun parse_list parser stream =
(case parser stream of
  (result, []) =&gt; result
| _ =&gt; raise ParserError) handle Punt =&gt; raise ParserError
&lt;/pre&gt;Let us now build a parser for symbols:
&lt;pre&gt;fun symbol x ph =
case ph of
  (Symb y :: rest) =&gt; if x = y then (x, rest) else raise Punt
| _ =&gt; raise Punt
&lt;/pre&gt;given a symbol, x, and a phrase, ph, to attempt to parse, we test if the head of the stream is the desired symbol. If yes, we return the pair of the symbol and the rest of the phrase. If no, we punt; the parsing failed here so we backtrack to try something else.

It is easy to build more simple parsers like the one above. Here are numbers and identifiers:
&lt;pre&gt;fun number ph =
case ph of
  (Number n :: rest) =&gt; (n, rest)
| _ =&gt; raise Punt

fun identifier ph =
case ph of
  (Id id :: rest) =&gt; (id, rest)
| _ =&gt; raise Punt
&lt;/pre&gt;But what makes this kind of parser special are the parser combinators. A parser combinator is a function which takes several parsers (of the ('a, 'b) parser type) and combines them into new parsers. We declare a couple of new operators and fill in their definitions later
&lt;pre&gt;infix 0 |||
infix 3 ---
infix 5 &gt;&gt;&gt;
&lt;/pre&gt;Normally, I am not that keen on declaring new operators, but when there is a certain sense of closure among the operators and they work on a specific domain, it might be easier to read code with operators. An aside is that it not always helps to have operators infix. For instance, 3 + 4 + 7 + 13 in ML can be written more succinctly in Lisp-systems as (+ 3 4 7 13). Nor do I find the operator noise of most Haskell programs very appealing. So one must use great care before just blindly declaring another operator. It should be warranted and justified. One justification is when you have a set of operators with closure, operating on the same domain. Binary arithmetic modulo N for instance. Or combinators for parsers.

Back to our combinators. The first one, ||| is the 'or'-combinator. ph1 ||| ph2 will first try to parse with ph1. Upon success of ph1, then that is the return of the whole parse. Upon fail, it tries ph2. Observant readers will recognize the short-circuiting nature. The code is using the backtracking to achieve the described informal semantics:
&lt;pre&gt;fun ph1 ||| ph2 =
(fn stream =&gt;
ph1 stream handle Punt =&gt; ph2 stream)
&lt;/pre&gt;Similarly, there is --- which is the equivalent of a logical 'and'. The parser ph1 --- ph2 first parses with ph1 and then with ph2 on the stream remaining from ph1. It returns the pair of the result. Perhaps the code explains this better than I do:
&lt;pre&gt;fun ph1 --- ph2 =
(fn stream =&gt;
let
  val (a, stream') = ph1 stream
  val (b, stream'') = ph2 stream'
in
  ((a, b), stream'')
end)
&lt;/pre&gt;Next up is &gt;&gt;&gt; which is the application operator. If one writes ph &gt;&gt;&gt; f, then ph is used to parse the stream into (x, rest) but the final result will be (f x, rest). The code is straightforward:
&lt;pre&gt;fun ph &gt;&gt;&gt; f = (fn stream =&gt;
    let val (x, rest) = ph stream
    in (f x, rest) end)
&lt;/pre&gt;The &gt;&gt;&gt; operator lets us shove any translating post-processor into the parser at any point, which will become handy.

With these down, it is easy to define some derived parsers. Here is one that lets you surround any parse with parenthesis:
&lt;pre&gt;fun parens ph = ((symbol #"(") --- ph --- (symbol #")"))
   (* Cut the relevant part *)
   &gt;&gt;&gt; (fn ((_, x), _) =&gt; x)
&lt;/pre&gt;Or even better, generalize that one:
&lt;pre&gt;fun surround left right ph = ((symbol left) --- ph --- (symbol right))
         (* Cut the relevant part *)
         &gt;&gt;&gt; (fn ((_, x), _) =&gt; x)

val parens = surround #"(" #")"
&lt;/pre&gt;One might look at the function that cuts out the relevant part and
deem that it is an ugly function. It is, indeed. But since we are
writing a combinator-parser, we can do a lot better than that. We can
simply define functions to get rid of it:
&lt;pre&gt;infix 3 --$
infix 3 $--
fun ph1 --$ ph2 = (ph1 --- ph2) &gt;&gt;&gt; (fn (x, _) =&gt; x)
fun ph1 $-- ph2 = (ph1 --- ph2) &gt;&gt;&gt; (fn (_, y) =&gt; y)

fun surround left right ph = (symbol left) $-- ph --$ (symbol right)

fun parens token = surround #"(" #")" token
&lt;/pre&gt;The functions $-- and --$ can now be used to remove parts of the
parse-result without having to use a pattern deconstruction all over
the place. It has been confined to the functions $--,--$ once and for
all.

The next obvious step is to use our combinator parser for parsing the
small expression language from part one. First, we handle the two
primitive, or atomic, rules:
&lt;pre&gt;fun exp_number token = (number &gt;&gt;&gt; (fn n =&gt; Const n)) token
fun exp_id token    = (identifier &gt;&gt;&gt; (fn id =&gt; Var id)) token
&lt;/pre&gt;These functions are straightforward: If we parse a number, we just
have to add the right constructor onto the result. The same is true
for identifiers.

There are several ways to parse the rest of the expression language,
but one of the more clever ways is to use a function I first saw
Lawrence C. Paulson do. Here is the function, which may look a bit
daunting at first:
&lt;pre&gt;fun infixes (ph, prec_of, apply) =
let
  fun over k toks = next k (ph toks)
  and next k (x, Symb a :: rest) =
  if prec_of a &lt;&gt;&gt;&gt; apply a x) rest)
    | next k (x, toks) = (x, toks)
in
  over 0
end
&lt;/pre&gt;The function infixes takes a primitive expression parser, ph, a
precedence discriminator function, prec_of and an applicator function
apply. It then proceeds to produce a parser with the given precedence
designations.

Basically, there are two functions mutually defined, over
and next. The over function parses expressions over a given
precedence. The next function operates the next symbol token we
see. So, suppose we got a symbol. Then we look up it precedence. If
the precedence is lower than the current level we are operating on, we
simply return it back to the lower level. If it is higher, we start a
recursive run for the higher level via a call to over -- and we
arrange it such that when it returns, it applies the 'a' symbol with
the return value and 'x' (it is nice to see currying at
work). Finally, we proceed towards to next token at current level via
a recursive call to next.

In our case, the precedence table is easily given:
&lt;pre&gt;fun precOf x =
case x of
  #"+" =&gt; 1
| #"-" =&gt; 1
| #"*" =&gt; 2
| _ =&gt; ~1
&lt;/pre&gt;and same for the apply table:
&lt;pre&gt;fun apply a x y =
case a of
  #"+" =&gt; Add (x, y)
| #"-" =&gt; Sub (x, y)
| #"*" =&gt; Mul (x, y)
| _ =&gt; raise InternalError
&lt;/pre&gt;To use our infixes function, we build a mutual definition of primitive
expressions, parenthesis structure and a call to infixes:
&lt;pre&gt;fun prim_exp toks =
let fun p_exp toks = parens exp_parser toks
in
  (exp_number ||| exp_id ||| p_exp) toks
end
and exp_parser toks = infixes (prim_exp, precOf, apply) toks
&lt;/pre&gt;and exp_parser is our desired expression parser. A simple test:
&lt;pre&gt;fun p stream =
let
  val lexed = lexer stream
in
  parse_list exp_parser lexed
end

val testlex_str = "x + 33 * (y - 5)" : string
val testparser = p testlex_str
val out = eval_exp test_env testparser
&lt;/pre&gt;returns the expected value, so we have some indication that it may
work as desired:
&lt;pre&gt;...
val p = fn : string -&gt; exp
val testparser = Add (Var "x",Mul (Const #,Sub #)) : exp
val out = 68 : int
&lt;/pre&gt;There are still several things we can do with the
parser combinators however, and there are some things left to discuss.

There is a big disadvantage to having a parser that backtracks by
default. At each possible junction it must store all of its state
since it might return to that point later on when backtracking. Of
course, this can be used for finding all possible parses with some
alteration of the parser, but mostly, it is a bad idea. The Haskell
Parsec library takes a more clever route. It has no backtracking by
default and the ||| operator only tries the second parser if the first
one &lt;emph&gt;failed&lt;/emph&gt; to consume any input. Thus it can avoid
keeping state around for backtracking.

Also, combinator-parsers have certain limitations. If your grammar has
left recursion, you will find yourself at an infinite loop very
quickly. For anything that needs speed and efficiency one is probably
better off with a parser generator for the LR family. But for smaller
problems where speed is not paramount, combinator parsers tend to be a
fine choice.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-1631738356818116816?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/1631738356818116816/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=1631738356818116816' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/1631738356818116816'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/1631738356818116816'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2009/02/combinator-parsing-part-3.html' title='Combinator parsing, part 3'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-6137331903708377129</id><published>2009-01-31T09:18:00.000-08:00</published><updated>2009-01-31T09:32:45.144-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SML'/><category scheme='http://www.blogger.com/atom/ns#' term='parsing'/><category scheme='http://www.blogger.com/atom/ns#' term='code'/><title type='text'>Combinator parsing, part 2 (Lexing)</title><content type='html'>In the first part, we set up the scene for combinator parsing. We introduced a small toy language and an interpreter for it. The thing we left out was the meat of the problem. Namely how to parse an expression string into a Standard ML datatype value. We will not be ready for this entirely yet, however.

Most parsing endeavours begin with the concept of lexical analysis or lexing, in which we break up a stream of characters into a stream of tokens. It can best be described by grouping characters that belong together into a single token.

There exist lexer generators able to produce quite fast lexers automatically. These usually work by identifying tokens via regular expressions and then compiling these regular expressions into a state machine (DFA). The best of them do not even interpret this DFA but compile the DFA into code which when executed is the DFA is question. For a particularly cool version of this, see Shriram Krishnamurthi [1]

For our purpose here it will be overkill to use a lexer generator. So we will resort to the much simpler solution of just hand-write it. But we will be clever enough to write it in a way which is pretty fast. The main disadvantage compared to most of the lever generators is that they work on the input stream in chunks. In other words they keep a small amount of work in memory at all times. Our solution will just read everything in. Haskell fares better here, as the default is ts lazy-read streams.

Anyway, we begin by defining the basics:
&lt;pre&gt;exception Internal_Error
datatype token = Symb of char | Id of string | Number of int
val symbols = String.explode "+-*()"
&lt;/pre&gt;The exception is for catching internal errors in the lexer. I tend to have such an exception in each module and raise it whenever something is non-expected. This way I eliminate an unexhaustive pattern match and make it clear to the reader what the intention of the code was.

The datatype defines what tokens we have in our language. There are symbols, identifiers and numbers. Finally, we declare a character list of symbols our language has.
&lt;pre&gt;fun numTok ss =
 case Int.fromString (Substring.string ss) of
   NONE =&gt; raise Internal_Error
 | SOME i =&gt; Number i

fun idTok ss = Id (Substring.string ss)
&lt;/pre&gt;The numTok function handles a number. It expects a substring and then converts it to an integer. The pre-condition of this function is that there is something to convert at all, or we face an internal error. The idTok expects the substring to be an identifier and converting that to a string is trivial.

Substrings warrants an explanation. In Standard ML, strings are immutable. Strings cannot be modified once they have been created. In fact, strings are vectors of chars. And vectors are immutable. A substring is then 3 values (s, i, n) where s is the underlying substring, i is the index into it and n is the length. So substrings are slices of strings.

Our main lexer function uses substrings to maintain a window over the original string. While it processes the string, this window is then systematically moved forward and the token stream is generated. Here is the main lexer function:
&lt;pre&gt;fun scan (toks, ss) =
 case Substring.getc ss of
   NONE =&gt; List.rev toks
 | SOME (c, r) =&gt;
   if List.exists (fn x =&gt; x = c) symbols
   then (* Symbol *)
     scan (Symb c::toks, r)
   else if Char.isAlpha c
   then (* Identifier *)
     let
       val (cs, rest) = Substring.splitl Char.isAlpha ss
       val tok = idTok cs
     in
       scan (tok :: toks, rest)
     end
   else if Char.isDigit c
   then (* Number *)
     let
       val (cs, rest) = Substring.splitl Char.isDigit ss
       val tok = numTok cs
     in
       scan (tok :: toks, rest)
     end
   else (* Skip whitespace, etc *)
     scan (toks, Substring.dropl (not o Char.isGraph) ss)

fun lexer str =
 scan ([], Substring.full str)
&lt;/pre&gt;The beast is easily explained: If we call lexer on a string, the string is made into a substring, and scan is called with an empty token list. The scan function carries out the hard work. If there are no more substring chars, then the tokens are just reversed and we are done. It might look odd to build the token list in reverse but SML mandates that list can only be built from the front, so this is the typical way to handle the last part of a tail-calling function.

If there is a character, then we discriminate the type of character. For each possible discrimination, we break off some of the string, create the right token type, and proceed with the rest of the string. Finally, we have a skip of white-space in case nothing else matches.

As a rather crude test
&lt;pre&gt;val testlex_str = "x + 33 * (y - 5)"
val testlex_toks = lexer testlex_str
&lt;/pre&gt;results in
&lt;pre&gt;exception Internal_Error
datatype token = Id of string | Number of int | Symb of char
val symbols = [#"+",#"-",#"*",#"(",#")"] : char list
val numTok = fn : substring -&gt; token
val idTok = fn : substring -&gt; token
val scan = fn : token list * substring -&gt; token list
val lexer = fn : string -&gt; token list
val testlex_str = "x + 33 * (y - 5)" : string
val testlex_toks =
[Id "x",Symb #"+",Number 33,Symb #"*",Symb #"(",Id "y",Symb #"-",Number 5,
Symb #")"] : token list
&lt;/pre&gt;Which looks right.

In the next part we will finish this up and write the combinator-parser for the token list into the abstract syntax tree we aim for.

[1] &lt;a href="http://www.cs.brown.edu/%7Esk/Publications/Talks/SwineBeforePerl/"&gt;Swine Before Perl&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-6137331903708377129?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/6137331903708377129/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=6137331903708377129' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/6137331903708377129'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/6137331903708377129'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2009/01/combinator-parsing-part-2-lexing.html' title='Combinator parsing, part 2 (Lexing)'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-5506108342341752521</id><published>2009-01-20T04:12:00.000-08:00</published><updated>2009-01-20T04:27:12.614-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SML'/><category scheme='http://www.blogger.com/atom/ns#' term='code'/><title type='text'>Ripping the backend from Moscow ML</title><content type='html'>Suppose you have two functions:
&lt;pre&gt;(* Type: int * int -&gt; int *)
fun f (x,y) = x + y

(* Type: int -&gt; int -&gt; int *)
fun g x y = x + y
&lt;/pre&gt;These functions do the same thing, namely add two numbers 'x' and 'y'. They have different types however, and they are called in different ways. 'f' is the usual way in most languages. We take a pair, and return the result. 'g' is curried: it is a function that takes an 'x' and then produces a new function taking a 'y'. The produced function returns the result when given an 'y'.

Interestingly, 'g' is more powerful than 'f'. If we write
&lt;pre&gt;(* Type: int -&gt; int *)
g 3
&lt;/pre&gt;we get a so called partial application of 'g'. This means we only supply the first parameter to the function. It allows us to optmize with respect to the first parameter and it is a good way to define very general functions and then specialize them into what we need later on. Here is an example:
&lt;pre&gt;(* Type: int -&gt; int -&gt; int *)
fun h x =
 let val z = expensive_operation x
 in (fn y =&gt; y + z)
 end
&lt;/pre&gt;We have defined a function which carries out some expensive operation between getting its first and second parameter. An application, 'let val foo = h 37' say, will only compute the expensive operation once and each time we use 'foo' we reap the benefits.

Moscow ML is a quasi-implementation of the Standard ML programming language. It does not follow the standard completely, but it follows it enough to be usable and to let simple code flow between SML implementations without too much problems. What does not flow that easily is the module system which is treated somewhat differently between Moscow ML and e.g. SML/NJ or MLton.

Moscow ML works by taking SML source code through a lexer and a parser into an abstract syntax tree. Then the types of all expressions are inferred in an 'elaboration' phase. Next, modules are stripped and pattern matches are simplified via a pattern match compiler. Now, the code is translated into an internal languauge, Lambda. Lambda is a lambda calculus + stuff. Finally, Lambda is translated into bytecode of a virtual machine.

The Moscow ML runtime is written in C and can interpret the bytecode output from the compiler. The engine is neat, but it suffers somewhat from age. Several speedups are readily possible on this machine with relative little effort.

The naive implementation of the 'g' function from before follows the semantics directly. Take the 'x', produce the intermediate function as a closure and then invoke the closure on 'y'. It is inefficient to produce the closure however, and we don't always have to! in 'g x y' we know all the arguments, so we can avoid building the intermediate function. Moscow ML relies on a derivative of the ZINC abstract machine as its VM. ZINC was an experiment by Xavier Leroy for writing a virtual machine for the Caml language. It is interesting because curried arguments do not build intermediate closures unless they have to. In other words, using the curried, more powerful, variant of a function has no extra cost in this machine.

I want to compile Moscow ML into LLVM bytecode. The idea is to compile from Lambda down to LLVM, which is not that different to what the Ocaml compiler is currently doing. In the process, I would like carry over the ZINC machines good handling of curried arguments.

I am taking some preliminary steps to get this done, but don't expect anything wild the next couple of months. This takes a lot of time getting right since I am writing it as a hobby project for the time being. I might be posting some updates later when the project has progressed furhter.


References -- if you know any reading which might be interesting, do not hesitate to write me:

&lt;a href="http://pauillac.inria.fr/%7Exleroy/publi/ZINC.ps.gz"&gt;The ZINC Experiment&lt;/a&gt;
&lt;a href="http://research.microsoft.com/en-us/um/people/simonpj/papers/eval-apply/index.htm"&gt;How to make a fast curry&lt;/a&gt; (I love Simon Peyton Jones paper names)
&lt;a href="http://github.com/jlouis/mosml-llvm/tree/master"&gt;The Mosml-llvm code lives here&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-5506108342341752521?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/5506108342341752521/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=5506108342341752521' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/5506108342341752521'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/5506108342341752521'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2009/01/ripping-backend-from-moscow-ml.html' title='Ripping the backend from Moscow ML'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-3750859720410959003</id><published>2009-01-09T07:23:00.000-08:00</published><updated>2009-01-20T04:27:57.053-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SML'/><category scheme='http://www.blogger.com/atom/ns#' term='parsing'/><category scheme='http://www.blogger.com/atom/ns#' term='code'/><title type='text'>Combinator parsing, part 1 (Setup)</title><content type='html'>&lt;p&gt;In this series of posts, we want to parse expressions. In order to make it worthwhile and fun, we will begin by placing some constraints on this.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;We will be using the language Standard ML for describing the approach. Though note that any functional language of a certain power can do this. Converting it to Ocaml, Haskell, Erlang or a lisp should be pretty straightforward once you get the hang of the idea.

In some sense, Standard ML is the simplest of the (statically typed) functional languages in that it has almost no fancy tricks you can pull.
&lt;/li&gt;
&lt;li&gt;We will not be using regular expressions. Not that regular expressions are bad, but I want to show that this can be done easily without the use of RE's. The goal here is to show people that there are different approaches to parsing data than just throwing a regular expression at the problem.
&lt;/li&gt;&lt;/ul&gt;The language we will study has the following simple syntax structure, given in BNF form:
&lt;pre&gt;  e ::= x | n | e1 + e2 | e1 - e2 | e1 * e2
&lt;/pre&gt;The 'x' is a variable. Its value can range over integers (we won't be concerned with the actual range of these integers, altough it is interesting to muse over). The 'n' is some integer constant. The term 'e1 + e2' is an addition of two numbers. Likewise for subtraction and multiplication. Here is a typical expression:
&lt;pre&gt;  x + 3 * (y - 5)
&lt;/pre&gt;Note that the parenthesis are not given in the syntax. We just assume their existence and they work as you would expect: grouping together terms to force evaluation order.
&lt;p&gt;&lt;/p&gt;Writing down the syntax in Standard ML is straightforward:
&lt;pre&gt;datatype exp = Var of string | Const of int | Add of exp * exp
           | Sub of exp * exp | Mul of exp * exp
&lt;/pre&gt;Hopefully it is clear what is going on here. We have translated the syntax into an ML datatype. To discriminate each construct, we have added &lt;emph&gt;constructors&lt;/emph&gt; 'Var','Const','Add','Sub', and 'Mul'.
&lt;p&gt;&lt;/p&gt;&lt;p&gt;If we can somehow bring strings of the form 'x + 3 * (y - 5)' into this datatype (correctly!) -- and we know what 'x' and 'y' is, then we are able to evaluate the expression. Here is how:
&lt;/p&gt;&lt;pre&gt;fun eval_exp env exp =
  case exp of
    Var x        =&gt; env x
  | Const n      =&gt; n
  | Add (e1, e2) =&gt; (eval_exp env e1) + (eval_exp env e2)
  | Sub (e1, e2) =&gt; (eval_exp env e1) - (eval_exp env e2)
  | Mul (e1, e2) =&gt; (eval_exp env e1) * (eval_exp env e2)
&lt;/pre&gt;So we destruct the form of 'exp'. If it is a 'Var', we look up the variable in the environment 'env', which we will define shortly. If it is a 'Const', we just return the integer value. Finally, if it is a binary operator, we proceed to evaluate the two sub-expressions and apply the right ML-operator to it.
&lt;p&gt;&lt;/p&gt;&lt;p&gt; We still need to give a meaning to the environment 'env'. We would like to represent it as a map from strings to integers (ie, a function of type 'string -&gt; int'), as our variables are strings. This is straightforward in Standard ML fortunately. Suppose we want to represent the mapping 'x' maps to 2 and 'y' maps to 7:
&lt;/p&gt;&lt;pre&gt;exception env_notfound of string
fun test_env v =
  case v of
    "x" =&gt; 2
  | "y" =&gt; 7
  | _   =&gt; raise (env_notfound v)
&lt;/pre&gt;We define an exception for the case where we don't know about the variable and raise it if the variable is unknown. In Standard ML '_' stands as a wild-card for "any other unnamed value."
&lt;p&gt;&lt;/p&gt;Let us round up by playing with what we have. If we manually parse the term 'x + 3 * (y - 5)' it becomes:
&lt;pre&gt;val term = Add (Var "x", Mul (Const 3, Sub (Var "y", Const 5)))
&lt;/pre&gt;So if we try to run the term with our environment from above, we expect the result to be '2 + 3 * (7 - 5) = 2 + 3 * 2 = 2 + 6 = 8'. Here is what our Standard ML system says:
&lt;pre&gt;- eval_exp test_env term;
val it = 8 : int
&lt;/pre&gt;In the next part, we will write the parser that allows us to automate the parsing of the term into the datatype of 'val term'&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-3750859720410959003?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/3750859720410959003/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=3750859720410959003' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/3750859720410959003'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/3750859720410959003'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2009/01/combinator-parsing-part-1-setup.html' title='Combinator parsing, part 1 (Setup)'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-2356426159531316603</id><published>2009-01-06T02:10:00.000-08:00</published><updated>2009-01-06T08:34:05.450-08:00</updated><title type='text'>Common Erlang misconceptions</title><content type='html'>There is a common saying that Erlangs I/O layer is slow. Bullshit. The etorrent program can easily sustain 70 megabit with less than 5% of CPU usage on my old machines. The reason is that etorrent is shuffling 16k binary blocks around mostly. But that means you have a pointer to each 16k block and you are only a writev(2) call away from the disk.

This means I/O is not itself a problem. The problem that people often hit is Erlangs string handling. In Erlang a string can either by represented as an &lt;span style="font-style: italic;"&gt;immutable &lt;/span&gt;array of 8-bit characters, called a binary; or it can be represented as a list of integers (ie, a linked list of integers). The latter is mutable in the sense that you can generate new integers and update the linked list from the front only.

Whenever you mutate the list of integers, garbage is generated. Allocation will happen and this directly translates to more garbage collection pressure later on. Had you had destructible arrays in Erlang it would have been very easy to circumvent the worst performance problems, but you will have to do with a limited zoo of types. In better languages, like Ocaml, Standard ML or Haskell, your type zoo is much richer here. You can choose between several immutable and mutable variants so the leverage is much greater.

First trick: Erlang has the concept of an IO list. These are lists of binary/string chunks. They are fast because they lend themselves to a writev(2) in the bottom of the system. Thus you don't have to concatenate strings in the Erlang language but you can hand a quasi-concatenated list to the VM and let C do the heavy-lifting for you.

Second trick: Mutating data as strings is slow. But if you have a abstract tree of tuples then it can be manipulated fast. If you think about the command &lt;span style="font-weight: bold;"&gt;[Bin | IOList] &lt;/span&gt;where we add a Binary to the front of an IOList, you'll know it happens in O(1) (constant) time. If we build a tuple &lt;span style="font-weight: bold;"&gt;{atom, D1, D2, ...}, &lt;/span&gt;we can build it in constant time. So the trick is to maintain your data in a &lt;span style="font-style: italic;"&gt;non-string &lt;/span&gt;form for as long as possible and then only change it to a string at the very last point in time.

Third trick: Correct data structure. Ropes. Finger Trees. M-way trees. Don't brute force yourself over a string. Process the structure by pattern matching in a clever way so you minimize the amount of change needed. A good tree will have around logarithmic change whereas a list will have linear change. This leads to the next point: allocation.

Another crap problem in Erlang is that you have few (traditional) ways to minimize &lt;span style="font-style: italic;"&gt;allocation. &lt;/span&gt;Any kind of operation will allocate data if you are not wary of it. Hence you should try to build programs that do not gloss over data and allocate all the time. Mapping of lists via list comprehensions is a good example. It is easy to understand but it will build a new list and garbage collection will cost you. If you can do multiple things in one list comprehension, you win traversals and allocations.

Whenever I hear about "Slow string processing" in Erlang I immediately think: "Another Ruby programmer trying to cram his language into Erlang". If you hit slowness the trick in Erlang is to redefine the problem! Don't try to string process yourself into oblivion. If the sole thing your problem concerns is string-processing, go use perl. Please. Or be clever and use Ocaml. Pre-process the data in other languages and make them into erlang terms which can be read fast by erlang. Erlangs power is the concurrency at which it is really good. There were no reason for giving it fast string processing.

Also, don't get bitten by the mnesia bug, please. It is almost always the case that mnesia and ETS are the wrong way to go. I got bitten by it multiple times in etorrent and now I am contemplating ripping all of it out again. Plain old data structures baby! There are some nasty caveats to mnesia and ETS and they are not related to the size limit of the database.

For mnesia, be aware that a failed transaction will be re-run! Now take 100 transactions tripping over each other. They will &lt;span style="font-style: italic;"&gt;never&lt;/span&gt; finish. Etorrent did that when peers should update their state. Instant snail-speed application. Mnesia is crap at doing joins. Just forget it.

ETS is also problematic: Any store or get from ETS means a data copy. Don't do as etorrent and add large rows (128k+) to ETS. Your app will come to a grinding halt.

Don't message big data structures around. Any message incurs a copy (in the default VM). If you need to work with a big data structure, shove it into a process and then send the Pid of that process around or register him globally. You can think of a Pid as "Passing a pointer around" in this case.

And finally: Measure measure measure! Be scientific about your performance problems. You need to know exactly what causes it before jumping to conclusions. And don't worry too much about being parallel at the beginning. You can always split things up in finer granularity later.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-2356426159531316603?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/2356426159531316603/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=2356426159531316603' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/2356426159531316603'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/2356426159531316603'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2009/01/common-erlang-misconceptions.html' title='Common Erlang misconceptions'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-379550611048075793</id><published>2009-01-05T14:48:00.001-08:00</published><updated>2009-01-05T15:07:01.648-08:00</updated><title type='text'>A little set of tools</title><content type='html'>This is a little set of tools that I like to use now and then. I name them by their Ubuntu/Debian package names although I think one can find them easily for any package system out there.

apg - The "automated password generator". It generates automated &lt;span style="font-style: italic;"&gt;pronounceable&lt;/span&gt; passwords. It takes a lot of options as to how the passwords should look and what they must contain etc. It is a handy tool for generating passwords which are hard to guess but still easy to memorize.

mp3gain - Mastered music today has different loudness levels. You will search for your volume button all the time because some tracks are much louder than others. This tool can analyze mp3 files and hint about the loudness level so programs can adjust accordingly. Or it can adjust the volume of the mp3 file in a lossless way (using a nice property of the MDCT in mp3s).

password-gorilla - A Password safe application written on top of "pwsafe" in TCL. Main advantage of using this is that there are Windows and OSX programs able to read the format as well.

stow - Manager for the hell that is /usr/local. You create /usr/local/stow and proceed to compile programs with "--prefix=/usr/local" but run "make install prefix=/usr/local/stow/foo-1.2.3". Now you can cd into /usr/local/stow and call the "stow" command on "foo-1.2.3". This creates a symlink farm in /usr/local. Want to get rid of the program? "stow -D" it followed by deletion. This is nice for handling seamless upgrades/downgrades of non-packaged software as wel.

vorbisgain - Like mp3gain, just for vorbis files.

graphviz - Hate drawing diagrams? Now you can &lt;span style="font-style: italic;"&gt;program&lt;/span&gt; diagrams instead! Graphviz takes a description of a graph (not a plot!) and proceeds to build the graph for you. It uses some really good layout algorithms so you often get extremely neat graphs if you know a bit about the tool. Most kinds of graphs can be drawn easily. There are also tools for doing post-processing of drawn graphs if you want to do things a bit different than what the tool thought - but you rarely need that. It got a Cairo rendering backend and can output to PDF, PS, PNG, SVG, etc.

The real power of graphviz is when your graph changes a lot. You just add vertices and edges and the system figures out layout itself. It is way easier than editing the graph in tool most of the time.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-379550611048075793?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/379550611048075793/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=379550611048075793' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/379550611048075793'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/379550611048075793'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2009/01/little-set-of-tools.html' title='A little set of tools'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-7713649079410945897</id><published>2009-01-04T15:05:00.001-08:00</published><updated>2009-01-04T15:10:51.361-08:00</updated><title type='text'>Unison - A file sync application</title><content type='html'>Most system admins know about rsync. It is a really good tool to synchronize between different machines because it only moves data that happen to be changed. It lacks some things however. One of the things it is lacking is interactivity.

Unison is a tool written by Benjamin C. Pierce and a couple of other guys. Pierce is a type theory researcher and he likes writing ocaml programs. But you should not let that put you off Unison. It uses the rsync protocol down below ;)

When it sync's 2 sites it will ask you which way to propagate changes. It is also much more clever when it comes to shortcutting work. It can, for instance, detect that a file was moved so it has a local copy of that file it can use in the sync process.

My preferred usage is to sync. directory contents between machines I work on. It often happens that I have worked on the machines in a way such a 2-way sync is needed. And Unison can give you that right away while it will be pain in rsync.

Pierce now works on the Boomerang language which is really interesting. But I'll save that for a later post.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-7713649079410945897?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/7713649079410945897/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=7713649079410945897' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/7713649079410945897'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/7713649079410945897'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2009/01/unison-file-sync-application.html' title='Unison - A file sync application'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-7225092716660566059</id><published>2009-01-02T11:25:00.000-08:00</published><updated>2009-01-02T11:42:56.022-08:00</updated><title type='text'>Avoiding memory fragmentation for fun and profit</title><content type='html'>One problem that might occur in long-running programs is that of memory fragmentation in the VM-heap. The problem is pretty simple: when you allocate and deallocate memory in the program you might end up with small "holes" all over your heap which are too small for the new data you need. In a page-allocated VM-heap world, this has a serious cost in memory usage.

There are several ways to avoid the problem. The first one is to be aware of the problem and be smart when allocating memory. With the right amount of thought you can often get around the memory fragmentation, or at least minimize it.

The second trick is to restart the application periodically. It is not as bad as it sounds in a UNIX system. You set up the application and fork() off a child to do the hard work. When the child has been running for some time, you kill it and fork() off another from the (non-fragmented) parent. Apache 1.x used this.

The third trick is to allocate a big region of memory, keep a pointer to the first unallocated word and then reset the pointer when you are done with your request and don't need the memory anymore. Interestingly there has been considerable research in the area to attempt to automate this idea. It is known as "Region Inference" in the automated setting, but here it is used in a manual way in e.g. C to achieve the same thing. The Subversion project used a region handler some years ago when I looked at their code. I don't know if they still do however. Poul Henning Kamp uses the reset-trick in Varnish as well.

The fourth trick is to use a good garbage collector. Garbage collectors have the advantage that they are allowed to move data around, so the good ones compact live data to one end of the heap periodically and clears up fragmentation in the process. Note that most garbage collectors used in "scripting languages" like Python or Ruby are pretty weak. They usually avoid doing "real" garbage collection and opts for some simple poor-mans solutions. It is unfortunate because this puts GC in a bad light. That and Java-enterprise-behemoths abusing the VM-heap :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-7225092716660566059?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/7225092716660566059/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=7225092716660566059' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/7225092716660566059'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/7225092716660566059'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2009/01/avoiding-memory-fragmentation-for-fun.html' title='Avoiding memory fragmentation for fun and profit'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-3201964545462010001</id><published>2008-12-10T14:45:00.000-08:00</published><updated>2008-12-10T15:03:28.872-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='puppet'/><category scheme='http://www.blogger.com/atom/ns#' term='sysadmin'/><title type='text'>The magic of puppetry</title><content type='html'>At work, we have several geographically separated machines. This is no problem for puppet, one just declares a variable for the location and then proceed to factor out differencies between the locations. I just naively went along and choose one machine from each geo-location as the defining one in that location for generic services.

We use OpenNTPd for our NTP services. Use geo-location to pick out the right DNS-name/IP-address and then proceed to set it in /etc/openntpd/ntpd.conf. Ensure that the package is installed, and the service is running on the host. Do the very same for the logcheck tool, though the configuration is less specialized to geo-locations. Go to lunch.

When I come back, three hosts has tripped in the spider web of logcheck. All because they are off on the clock. The magic is that the streamlining of hosts happens automatically. You don't have to hunt for the discrepancies, you just have to specify what the hosts should contain. I had no idea that some machines were without NTP. It is not because system administrators are lazy and have bad memories. It is because you need better tools to maintain your server farm, ie, puppet.

The next thing I do is to get apt to run via cron (There are several tools for this, pick your poison), get it to update the database and to download new updates. Then the following little piece of magic from the Puppet website does wonders:
&lt;pre&gt;
 file { "/etc/update_initiator":
  group =&gt; root,
  owner =&gt; root,
  mode  =&gt; 640,
  source =&gt; "puppet:///dist/config/update_initiator",
 }

 exec { "/usr/bin/apt-get -y dist-upgrade":
  refreshonly =&gt; true,
  subscribe =&gt; File["/etc/update_initiator"],
 }
&lt;/pre&gt;
When '/etc/update_initiator' is changed, then run the dist-upgrade. The update_initiator file also serves as the descriptive changelog of when an update was sent through to the machines. Update that file on the puppetmaster and then all machines happily install their updates.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-3201964545462010001?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/3201964545462010001/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=3201964545462010001' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/3201964545462010001'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/3201964545462010001'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2008/12/magic-of-puppetry.html' title='The magic of puppetry'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-4359110514351818262</id><published>2008-12-03T10:54:00.000-08:00</published><updated>2008-12-03T11:25:59.802-08:00</updated><title type='text'>Master of puppets.</title><content type='html'>No, this is not a post about Guitar Hero 3. It is about system administration and puppetry!

If you manage more than 5 hosts you &lt;span style="font-weight: bold;"&gt;will&lt;/span&gt; need configuration management automation. Either you write your own scripts (shudder), use CFEngine (more shudder) or you use &lt;a href="http://reductivelabs.com/trac/puppet"&gt;Puppet&lt;/a&gt; from Reductive labs (There are .deb packages: puppet and puppetmaster).

Choose a server that is going to be the puppetmaster. This guy should be fairly well protected as he will be the server handing out configuration to other machines. Give him a repository in /etc/puppet via either Subversion, Git, Hg, Bzr or your poison of preference. Make it such that a DNS lookup on puppet.[dnsdomainname] hits the puppetmaster. Enable the puppetmaster fileserver if not already done.

Install puppet on the clients. Hand it the server address and it will try to communicate. It will fail miserably until you allow the clients Security CA's on the puppetmaster. Then you are ready for the fun: Assimilation!

I started with something easy. Behold, sudo.pp:
&lt;pre&gt;
class sudo {
       package { sudo: ensure =&gt; installed }

 file { "/etc/sudoers":
  owner =&gt; root,
  group =&gt; root,
  mode  =&gt; 440,
  source =&gt; "puppet://puppet/dist/apps/sudo/sudoers",
               require =&gt; Package[sudo]
 }
}
&lt;/pre&gt;
This incantation tells puppet that we need the 'sudo' package. Puppet is intelligent enough to use the right poison: portage, apt, aptitude, yum, pkg-install (Hi FreeBSD!), etc for installing the package. Next it will update /etc/sudoers with a file over the puppet protocol from the 'puppet' host (Remember the DNS setup? You'll love it in the long run ;) and take it from /dist/apps/sudo/sudoers. This path is prefixed with whatever is set in /etc/puppet/fileserver.conf and the file is copied, checksummed and configured. B00m! You now have centralized your sudo configuration.

Next up: NTP!
&lt;pre&gt;
class openntpd {
 package { openntpd: ensure =&gt; installed }

       file { "/etc/openntpd/ntpd.conf":
     source =&gt; "puppet://puppet/dist/apps/openntpd/ntpd.conf",
           require =&gt; Package[openntpd]
 }

 service { openntpd:
     ensure =&gt; running,
     enable =&gt; true,
     pattern =&gt; "ntpd",
     subscribe =&gt; [Package[openntpd], File["/etc/openntpd/ntpd.conf"]]
 }
}
&lt;/pre&gt;
Note we have a declaration 'require' that orders the dependencies among things. We'll be sure things trigger in the right order. Next we define that openntpd needs a service 'openntpd' which should be running and enabled. The 'pattern' part tells puppet that it should look for a program 'ntpd' to discern whether openntpd is running or not.

Puppet is intelligent enough to force the enabling via 'update-rc.d' on my Ubuntu/Debian boxes.

Final thing: Locales (shudder).
&lt;pre&gt;
class locales {
 package { locales: ensure =&gt; installed }

 file {
 "/etc/environment":
  owner =&gt; root,
  group =&gt; root,
  mode =&gt; 644,
  source =&gt; "puppet://puppet/dist/config/environment",
  require =&gt; Package[locales];
 "/etc/locale.gen":
  owner =&gt; root,
  group =&gt; root,
  mode =&gt; 644,
  source =&gt; "puppet://puppet/dist/config/locale.gen",
  require =&gt; Package[locales],
  before =&gt; Exec["generate locales"];
 }

 exec { "locale_gen":
  command =&gt; "/usr/sbin/locale-gen",
  alias =&gt; "generate locales",
  subscribe =&gt; File["/etc/locale.gen"],
  refreshonly =&gt; true
 }
}
&lt;/pre&gt;
The new thing is the 'exec' declaration that will call '/usr/sbin/locale-gen' if our subscription '/etc/locale.gen' were updated (refreshed).

Now you add the classes to the machines that need them through the 'node' facility of puppet. And then you have centralized control over ntpd and locales as well.

Of course, puppet can also do things depending on host-types, fill in config-file templates, discriminate configuration in every conceivable way and so on. I can live with the fact it is written in Ruby. It happens to be brilliant.

If you want to start using it, I recommend going straight to the root of a &lt;a href="http://git.black.co.at/?p=manifests;a=summary"&gt;complete setup,&lt;/a&gt; and use that as a base for yours.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-4359110514351818262?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/4359110514351818262/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=4359110514351818262' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/4359110514351818262'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/4359110514351818262'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2008/12/master-of-puppets.html' title='Master of puppets.'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-6098208126836533289</id><published>2008-11-27T12:39:00.000-08:00</published><updated>2008-12-03T11:36:30.282-08:00</updated><title type='text'>Erlang Talk slides</title><content type='html'>Some days ago I gave a talk at the local LUG on Erlang. The basic idea was to spark the interest in the language while keeping it comprehensible to most people. Of course you need slides for such an occasion, and what tool but LaTeX is the solution?

First, you'll need the BEAMER package. Ubuntu has a 'latex-beamer' package. Then you'll simply begin a LaTeX document with:

&lt;span style="font-style: italic;"&gt;Update: &lt;/span&gt;Changed 'fontend' to 'fontenc' which is the right thing to write here ;)
&lt;code&gt;
\documentclass[20pt]{beamer}
\usepackage[T1]{fontenc}

\begin{document}
...
&lt;/code&gt;

Each slide page can then be added with the following construction
&lt;code&gt;
\frame{
\begin{center}
Concurrency\\
$+$\\
Parallelism
\end{center}
}
&lt;/code&gt;
which creates a single slide frame on which text is placed. Calling 'pdflatex' on the document then produces a PDF you can show in 'evince' or similar program. Run the document in presentation mode and you are set to go.

The next part is graphics. One would think this is hard, but oh no! Not so! You just add

&lt;code&gt;
\usepackage{graphicx}
&lt;/code&gt;

before the document environment. And then you can include images like I did in this slide (note that you can often omit the file-type ending and let LaTeX figure out that part by itself)
&lt;code&gt;
\frame{
\begin{center}
  \includegraphics[scale=0.5]{400px-Skull_and_crossbones.pdf}\\
  \textbf{\large{``Doom doom doom''}}
\end{center}
}
&lt;/code&gt;

Luckily, you are not limited to only PDF documents. I used PNGs, JPEGs and a couple of other things.

&lt;a href="http://latex-beamer.sourceforge.net/"&gt;The Beamer homepage&lt;/a&gt;
&lt;a href="http://dl.getdropbox.com/u/196031/erlang-talk-final.pdf"&gt;Slides from the talk&lt;/a&gt;
&lt;a href="http://www.youtube.com/watch?v=liQLdRk0Ziw"&gt;Guy Kawasaki: the 10-20-30 rule for Pitching on Youtube&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-6098208126836533289?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/6098208126836533289/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=6098208126836533289' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/6098208126836533289'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/6098208126836533289'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2008/11/erlang-talk-slides.html' title='Erlang Talk slides'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-4287162135933227385</id><published>2008-10-12T12:54:00.000-07:00</published><updated>2008-10-12T13:00:04.636-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><category scheme='http://www.blogger.com/atom/ns#' term='debugging'/><title type='text'>Debugging Erlang programs 101</title><content type='html'>The first step in debugging Erlang programs is simple: Acknowledge that debugging concurrent programs is hard. Extremely hard. When you have that acknowledgement, the trick is to get your bag of debugging tools up to date.

The very first thing you should do is to enable SASL. This can be done with the command
&lt;pre&gt;
application:start(sasl).
&lt;/pre&gt;
or by using the boot-script that includes the SASL application. SASL will enable different kinds of information in the shell, but it can also be configured to output to a file. SASL will send reports in different situations.

Whenever something CRASH-es or something PROGRESS-es, SASL will send a report to you. The next part of debugging is to understand how to dissect Erlang back-traces. Erlang will not report line-numbers where the error occurred. Hence, you should use many small functions, as the function will occur in the back-trace. You must also remember that the back-trace may does not include tail-calling stack-frames.

How do you read a back-trace from Erlang? The first thing is to know what the different error messages means.  The &lt;a href="http://erlang.org/doc/reference_manual/errors.html#exit_reasons"&gt;exit reason&lt;/a&gt; of a function will tell us what is wrong at the point where the error was raised. The next part of the stack-trace looks like:
&lt;pre&gt;
** exited: {function_clause,[{foo,fact,[0.00000e+0]},
                             {foo,fact,1},
                             {erl_eval,do_apply,5},
                             {shell,exprs,6},
                             {shell,eval_loop,3}]} **
&lt;/pre&gt;
So what does this tell us? It says that the exit reason was a "function_clause" error. These are because no pattern matches in the foo modules fact function. The next term is a call to "foo:fact/1" and that comes from a call "erl_eval:do_apply/5" and so on. More evil are local "fun (...) ..." declarations which will be put into the stack as well. Watch out for these.

&lt;h3&gt;Assertions&lt;/h3&gt;

The single assignment form of Erlang let us write assertions in a neat way in the code. If we set
&lt;code&gt;
X = Y
&lt;/code&gt;
where both [X] and [Y] have already been defined, we define an assertion. Note this is also true if X or Y are (partially) constant expressions. This asserts that X and Y are equal. Use this to your advantage! Spray with assertions all over your code. Write down what you expect the value to be. Write functions that tests assumptions about the code. If the assertion is violated, you get an error right away. Use function guards. If you expect an integer, write
&lt;pre&gt;
foo(X) when is_integer(X) -&gt; ...
&lt;/pre&gt;
rather than
&lt;code&gt;
foo(X) -&gt; ...
&lt;/code&gt;
Sometimes, guards can't be used as only certain BIFs are allowed as guards. Then you, write a longer function that tests your assumptions and assert on that function. When things get concurrent, it is assertions that will save you.

You should not worry too much about adding assertions to the code. Unless you add them in the cost-centre, it won't affect you much. Rather, you should worry about the correctness of the program. You can always remove assertions from critical parts and surround the critical part with a check if needed.

&lt;h3&gt;Dialyzer&lt;/h3&gt;

One last debugging tool to mention is the dialyzer. It is a static checker for Erlang code and it is able to find many discrepancies in the code if you let it run on it. You should heed its warnings, for often they can alleviate a problem before it even becomes one.

This concludes the 101 in Erlang debugging.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-4287162135933227385?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/4287162135933227385/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=4287162135933227385' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/4287162135933227385'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/4287162135933227385'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2008/10/debugging-erlang-programs-101.html' title='Debugging Erlang programs 101'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-2979658571862632376</id><published>2008-10-01T11:41:00.000-07:00</published><updated>2008-10-01T11:44:55.621-07:00</updated><title type='text'>Books equals code?</title><content type='html'>Suppose you were an author writing books. A publisher wants to publish a novel on a particular subject; a sci-fi novel say. Now imagine that the author will be paid for each month he or she works on the book with a nice pay, but once the book has been written, then it belongs solely to the publisher. The publisher will sell the book for the next 20-30 years and make a bit of money off it each month. The author will not get anything of these money.

A mediocre author would -- perhaps -- jump at this. A bestselling author, however, wouldn't. She would only accept writing the sci-fi novel should she get considerate percentage of the earnings. She would know that her value is built by accumulating it in the books she writes because they will throw off a small bit of money each month for 20-30 years.

Now imagine you are a programmer at a company. Most programmers happily give over all rights on the code to the company. They happily get their pay each month, and when they get fired or move on, their accumulated value is lost entirely. The paradoxical thing is: most programmers accept this. Some of their worth is in the code they wrote, but since it is entombed in the repository of the company they have access to that worth in their next job.

I command this to stop. Now. Here is a set of ideas:

First, you could tie the success of the company with your earnings, but be sure that you get something other than salary. It is gone when you leave. Stock options is one way. Or you may be one of the owners.

Second, you could ignore the company and write code "in stealth" on the side of the company. When you have a product you could try to shrink-wrap it into something salable. With luck, you can then either get something fun out of it, or a lot of money. Note that many companies disallow such activity. If you are at one such company, I suggest you move on and let them outsource your seat to India. They will be sorry for trying to outsource the system kernel (it always fails).

Third, you could have the company release part of their code as open source. This leaves you with a way to take your work with you to another company and with luck you also generate "street credit" in the Open Source community. In other words, you are generating accumulating value you can take with you when you leave. The company can get a feedback loop going on such open sourced software, so it might end up being beneficial to them.

Fourth, you can write software and release the software under an open source license. But you only do work on the system by contract. If a company wants tailoring, it is negotiable for a price. They get the best programmer for the job and you back-fit the changes into your code generating even more value in the project. Another path is to take money for support on the code base.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-2979658571862632376?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/2979658571862632376/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=2979658571862632376' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/2979658571862632376'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/2979658571862632376'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2008/10/books-equals-code.html' title='Books equals code?'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-8851443205504822222</id><published>2008-07-20T18:00:00.001-07:00</published><updated>2008-07-20T18:13:55.472-07:00</updated><title type='text'>The Law of secret weapons</title><content type='html'>So, one searches the a job index in denmark:

ML: 0
Lisp: 0
Haskell: 0
Erlang: 0
Python: 1 - Manage a Java EE build system(!)

Perl: 2-3 system admin jobs.

The conclusion is clear: the Law of the Secret Weapons(tm) still holds true. You can pick anything from the list above and you will be able to enter almost any field with the best technical platform in 4-6 months time. I am sick of the Java and .NET jobs which let me code in a mediocre language with mediocre IDE-crap on some project I have absolutely no love for.

I can understand the functional toolset and mindset of ML and Haskell puts off people. Lisp is harder since it has so much backing in the commercial world after all. Same goes with Erlang - given that it currently has some of the hype. But seeing that few Python jobs astounds me. It is fairly easy to learn and has some great backing in Google. It is not going to perish the next 10 years. And you can deliver great software in a short amount of time with it.

Python also has the advantage that its dynamic typing makes it easier for the PHP crowd to pick up. Static types are awfully cool, but they require some training and routine to use effectively to your advantage. Most integration is also complete bliss to pull off in Python if you know what you are doing.

So any company that wants to use anything of the above can have me. I would be delighted to rip some Java/C# programs apart with a real language.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-8851443205504822222?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/8851443205504822222/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=8851443205504822222' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/8851443205504822222'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/8851443205504822222'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2008/07/law-of-secret-weapons.html' title='The Law of secret weapons'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-2667682594986832659</id><published>2008-07-18T17:40:00.000-07:00</published><updated>2008-07-18T17:46:09.603-07:00</updated><title type='text'>fprof in few paragraphs</title><content type='html'>First you find a pid. Then you run
&lt;code&gt;
fprof:trace([start, {file, "f"}, {procs, [pid(0,1292,0)]}]).
&lt;/code&gt;
and let it cook for a while. "f" will contain the profile raw data. When it has cooked for some time, you can run
&lt;code&gt;
fprof:trace(stop).
&lt;/code&gt;
to close the file and stop the trace. Then you read in the data with
&lt;code&gt;
fprof:profile(file, "f").
&lt;/code&gt;
which builds a database in memory from the profile run. The analysis output is then generated in 150 columns with
&lt;code&gt;
fprof:analyse([{dest, "f.analysis"}, {cols, 150}]).
&lt;/code&gt;
to the file "f.analysis".

To understand the profile output, you can read the Tools Users Guide which has a chapter on fprof and describes the output format. Let the CPU-cycle hunt begin!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-2667682594986832659?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/2667682594986832659/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=2667682594986832659' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/2667682594986832659'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/2667682594986832659'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2008/07/fprof-in-few-paragraphs.html' title='fprof in few paragraphs'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-2457912089596460545</id><published>2008-07-17T06:21:00.000-07:00</published><updated>2008-07-17T06:29:27.987-07:00</updated><title type='text'>The Dialyzer tool, love at first sight</title><content type='html'>So I am hacking a lot of erlang at the moment. The problem is that erlang is a dynamically typed language and bugs are sneaking into my code. This is where the dialyzer enters the game. It is a system which will take erlang code, infer types for the code and use it in a static analysis in order to find errors.

For me, this is a very valuable tool. While you can just run the code, it may take some time before you cover all cases, so periodically running the dialyzer can sometimes find bugs before they show up in running code. You compile your code and then you run
&lt;code&gt;
dialyzer -r "path-to-ebin-beams"
&lt;/path-to-ebin-beams&gt;&lt;/code&gt;
and the dialyzer will process your code and report problems. You will have to produce a PLT first. The PLT is the initial table with type information from other applications that you have stored in it. Creating the PLT takes time. A lot of time. If you run the dialyzer without a PLT you get hints on how to produce the initial PLT.

I most often use the dialyzer before comitting a larger set of code or after merging a branch upwards (From less stable to more stable code). Sometimes it finds messy stuff. And then I can go and fix it!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-2457912089596460545?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/2457912089596460545/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=2457912089596460545' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/2457912089596460545'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/2457912089596460545'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2008/07/dialyzer-tool-love-at-first-sight.html' title='The Dialyzer tool, love at first sight'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-1041048212724568747</id><published>2008-07-09T05:25:00.000-07:00</published><updated>2008-07-09T05:34:09.598-07:00</updated><title type='text'>etorrent - a bit of some history.</title><content type='html'>So, writing a torrent client goes through 3 phases:

In the first phase, you implement what is in the spec. These are the obvious things you need and the things you use as building blocks for the later steps.

In the second phase, you read the spec and figure out how things must fit together. Luckily, there is only one way to fit in most places, but there are some small nasty exceptions where you need to read code of other clients to figure out what should happen.

In the third phase, you go from the spec to implementing all the features that are more or less undocumented, but crucial for speed. Here is an example:

&lt;blockquote&gt;It does reciprocation and number of uploads capping by unchoking the four peers which it has the best download rates from and are interested. Peers which have a better upload rate but aren't interested get unchoked and if they become interested the worst uploader gets choked.&lt;/blockquote&gt;

So this is simple enough to implement. Sort the peers on download speed to the client and go through them one by one, choking and unchoking accordingly. But you need to recalculate this on state changes. And then there is optimistic unchoking which must also be handled. Seems easy enough.

The etorrent client currently has numerous problems with the above scheme. First of all, the measurement of download in clients must be running average, dampened and fine grained. Second, the 'four peers' part is a lie, and no modern client does that. Rather they choose the number based on the sum of the download rates and a heuristic. Of course this can only be understood if you read the source code of other clients.

This is the undocumented hairy part of the bittorrent protocol.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-1041048212724568747?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/1041048212724568747/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=1041048212724568747' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/1041048212724568747'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/1041048212724568747'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2008/07/etorrent-bit-of-some-history.html' title='etorrent - a bit of some history.'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-6871415120134635288</id><published>2008-05-04T12:33:00.000-07:00</published><updated>2008-05-04T12:45:56.287-07:00</updated><title type='text'>Erlang and bittorrent?</title><content type='html'>I have been working on an erlang bittorrent client for too many years at the moment. The reason it takes so long to get the code up and running is that it is a hobby project and that I have plenty of time doing it right.

So at the moment the code works, but it does not have the stability I would like it to have in the long run. But the code does work for downloading smaller things and I would like to have more hackers on the project.

To document my setup, I better explain what is used from the perspective of development. The editor is emacs with the distel mode on top of it. See &lt;a href="http://distel.googlecode.com"&gt;The Distel Googlecode site&lt;/a&gt;. The distel program allows me to dynamically upload recompiled code to a running erlang node so I can cut down the fix time to a minimum. For a dynamically typed language this is quite important as most bugs are related to wrong types.

Of course I run the standard Erlang distribution, without HiPE. I have not found the reason to compile code for speed yet as the code eats less than 1% CPU power when running. All database table access in the current code is linear, so there are definitely room for improvement and it will be needed as you want to download more than a single torrent file.

The code is kept in a GIT repository at &lt;a href="http://http://repo.or.cz/w/etorrent.git"&gt;repo.or.cz&lt;/a&gt; and the bug tracker is on &lt;a href="http://etorrent.googlecode.com"&gt;the google code site.&lt;/a&gt; I tend to keep the master branch in a stable baseline state so if you want to hack you better base your work on that. Also, I tend to keep my own main working branch in the repository as well so you can track what I am doing which is not yet ready to go into the baseline.

Do I like hacking Erlang? Yes and no. I really like the language, but the lack of a static type system is seriously pissing me off at the moment. But you can't have it all and Erlang does have a good production quality system which is rather hard to find with most other esoteric languages. The closest contenders being Haskell and Ocaml.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-6871415120134635288?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/6871415120134635288/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=6871415120134635288' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/6871415120134635288'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/6871415120134635288'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2008/05/erlang-and-bittorrent.html' title='Erlang and bittorrent?'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-1310910631559587852</id><published>2008-04-26T19:40:00.000-07:00</published><updated>2008-04-26T21:12:22.922-07:00</updated><title type='text'>Bugs which are not bumble bees</title><content type='html'>We have "bumble-bee-season" at the moment here. Every hour a queen is coming by my window and flies into my apartment. For some reason the queen must have a vain hope that my apartment will be a suitable place for her nest. Luckily it's not an aggressive type of bee, so you just gently guide it to the exit -- and on it flies.

Now this will not be about bumble bees, as however interesting it might be, the fate was that I shouldn't be a biologist. This is a shame -- gene manipulation sounds fun. So we will write on the other kind of bugs, that most readers will probably be more familiar with. The computer bugs who were once real insect bugs, but took on a more imaginative meta-physical form.

Any set can be partitioned in two. Let us partition bugs in the interesting and non-interesting ones. Of course this is for the pure reason of studying bugs. The set of interesting bugs are those, which make for a good story over a cup of coffee. They explain some fallacy in your thinking in help you understand the problem you are working with. To be specific: interesting bugs alters your perception of the problem you are trying to solve.

The other group of bugs, non-interesting, does not have the virtue of making a good story. These are most common and your only goal is to fix them as quickly as possible to get the program up and running. They manifest themselves all the time. It may be a wrong type that gets passed, it may be a wrong tag, off-by-one, a non-exhaustive pattern match with an obviously implemented missing pattern, swapped arguments in a function call or something similar. They may be really pesky to find and fix, but they do not tell anything new to your brain.

I don't like non-interesting bugs. I don't like to play with code to make it work either. I began hacking ML at a very early age, so my brain is wired to the thought of having static types on everything. To me, I rather want to skip the non-interesting bugs and write the code so I can attack the next problem. At some point, the ML type system becomes a tool for avoiding bugs of the non-interesting kind. We can't pass the wrong type as the type system will complain. We can still tag things incorrectly but not with a typo. The last problem I had in a dynamically typed language was that I had written &lt;span style="font-style:italic;"&gt;non-fetched&lt;/span&gt; rather than the correct &lt;span style="font-style:italic;"&gt;not-fetched.&lt;/span&gt; A proper sum-type eliminates this problem. Off-by-one tends to be eliminated by using a data structure such that indexes are abstracted away. Non-exhaustive pattern matches are caught by the compiler. And finally, swapped arguments are either caught by the type system, or you can pass a named record so each argument has a name rather than a position in the call parameter list.

Unfortunately, you don't get complete elimination of non-interesting bugs. There are still some left, but they tend to be few and far in between. I save time and altering the program is simpler because the types have to match for any change, eliminating much work with finding all spots having to be changed. For the experienced type hacker, one can use tricks like universal embeddings and phantom types to squeeze out even more expressibility. And that is without adding more tools into the bag: dependent typing, substructural typing and existential types.

And with this, I think I have explained why I don't like programming in dynamically typed languages that much. My claim will be: &lt;blockquote&gt;Dynamically typed languages make you fight more non-interesting bugs than statically typed languages.&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-1310910631559587852?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/1310910631559587852/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=1310910631559587852' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/1310910631559587852'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/1310910631559587852'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2008/04/bugs-which-are-not-bumble-bees.html' title='Bugs which are not bumble bees'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-3075456199407283489</id><published>2008-03-08T05:34:00.001-08:00</published><updated>2008-03-08T05:58:02.001-08:00</updated><title type='text'>Why I don't use Haskell for Functional Programming</title><content type='html'>When designing programming languages, the hard choice is not about
what you put into the language -- it is what you leave out or what is
mutually exclusive. Haskell did make the choice of being a purely
functional programming language and they did the choice of being
lazy. The positive things manifesting from this is: Lazy evaluation
finds more normal forms than strict evaluation. In the simply typed
lambda calculus it finds &lt;b&gt;all&lt;/b&gt; of them but I am not sure this is
the case in Haskell. Secondly, since the language is pure the compiler
is free to reorder computations as it sees fit. Languages which are
strict have an evaluation order limiting how we can reorder
terms. Standard ML is extremely limiting in this respect due to the
correct handling of IEEE floating point numbers and that arithmetic
overflow must throw exceptions.

It is possible to have a strict functional language with added
references and exceptions. These effects can, without too much hassle,
be added to the language in a way such that the implications are
minimal. Ocaml and Standard ML are the main examples, I believe. We
all know that Haskell took the monad route to add effects. A heavy
inspiration from Category Theory gave them a tool to build in effects
by encoding them as monads. It should be noted that there are other
ways to add effects into a purely lazy functional language as is shown
by Clean.

I don't like monads for programming effects. Granted, they give me a
way to formalize (in the type) what effectful computations a given
function have and that can be a tremendous help. But on the other
hand, it also forces me to lift computations into the monad as soon as
I bring it into play. First of all, the lifting adds a lot of boilerplate
code. If I need a monad transformer, this quickly gets out of hand: My
code tends to be invocation of the correct lifts into the
monads. Second, as effects can alter control flow, there is often the
requirement of doing global changes to the program. The changes are
not limited to the function using the effect only - the infection
spreads to the callers and often further up the call chain.

And SML is not perfect at all too: We have a lot of old cosmetic
changes we ought to do. And we better get a grip on how to add linear
typing and an effect system so we can reap the benefits that monads
does give you without all of the hassle.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-3075456199407283489?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/3075456199407283489/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5411139659011156551&amp;postID=3075456199407283489' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/3075456199407283489'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5411139659011156551/posts/default/3075456199407283489'/><link rel='alternate' type='text/html' href='http://jlouisramblings.blogspot.com/2008/03/why-i-dont-use-haskell-for-functional_08.html' title='Why I don&apos;t use Haskell for Functional Programming'/><author><name>Jesper Louis Andersen</name><uri>https://profiles.google.com/108725849902883879959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-z0sjSxK_dCk/AAAAAAAAAAI/AAAAAAAAALU/LnmFxf_VYJ0/s512-c/photo.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5411139659011156551.post-7125522015595503984</id><published>2008-03-04T05:55:00.000-08:00</published><updated>2008-03-04T06:07:45.605-08:00</updated><title type='text'>Ghost Records.</title><content type='html'>As I am typing this, Nine Inch Nails new album, &lt;a href="http://ghosts.nin.com"&gt;Ghosts&lt;/a&gt;, is downloading happily in FLAC format in the background. You have to pay $5 to get it, but that is around 25 DKK which is next to nothing. I feel like I ought to pay some tribute to Trent Reznor as he has produced so much good music through the ages. The $5 is vastly more than he would make, had he gone the usual record company way. I like paying Mr. Reznor. It is my hope that he will be inspired to produce more of his great music. I don't like paying a middle-man who has been factored out of the equation by time.

Trent must pay some money for me to download the album in FLAC format. Though this is peanuts compared to the $5. On the other hand, he do not have to pay for the production of a CD, and nor do I want it. Is the price fair? I really do think it is. Note that we are now entering a new era, where you can publish your music on the internet.

The record companies made a number of mistakes: They alienated their customers. They alienated their artists. They destroyed Napster, but did not have anything in its place. They promoted utterly bad artists by creating enormously expensive music videos. They didn't know statistics. They did not understand the internet as a media.

Now, they must suffer and die.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5411139659011156551-7125522015595503984?l=jlouisramblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jlouisramblings.blogspot.com/feeds/7125522015595503984/comments/default' title='Post Comme
