<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>ostinelli&#124;net</title>
	<atom:link href="http://www.ostinelli.net/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.ostinelli.net</link>
	<description>From onions to space neons.</description>
	<lastBuildDate>Sat, 12 Nov 2011 02:04:01 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.2</generator>
		<item>
		<title>A comparison between Misultin, Mochiweb, Cowboy, NodeJS and Tornadoweb</title>
		<link>http://www.ostinelli.net/a-comparison-between-misultin-mochiweb-cowboy-nodejs-and-tornadoweb/</link>
		<comments>http://www.ostinelli.net/a-comparison-between-misultin-mochiweb-cowboy-nodejs-and-tornadoweb/#comments</comments>
		<pubDate>Mon, 09 May 2011 02:19:08 +0000</pubDate>
		<dc:creator>Roberto Ostinelli</dc:creator>
				<category><![CDATA[erlang]]></category>
		<category><![CDATA[cowboy]]></category>
		<category><![CDATA[http servers]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[michiweb]]></category>
		<category><![CDATA[misultin]]></category>
		<category><![CDATA[nodejs]]></category>
		<category><![CDATA[tornadoweb]]></category>

		<guid isPermaLink="false">http://www.ostinelli.net/?p=411</guid>
		<description><![CDATA[As some of you already know, I&#8217;m the author of Misultin, an Erlang HTTP lightweight server library. I&#8217;m interested in HTTP servers, I spend quite some time trying them out and am always interested in comparing them from different perspectives. Today I wanted to try the same benchmark against various HTTP server libraries: Misultin (Erlang) [...]]]></description>
			<content:encoded><![CDATA[<p>As some of you already know, I&#8217;m the author of Misultin, an Erlang HTTP lightweight server library. I&#8217;m interested in HTTP servers, I spend quite some time trying them out and am always interested in comparing them from different perspectives.</p>
<p>Today I wanted to try the same benchmark against various HTTP server libraries:</p>
<ul>
<li><a href="https://github.com/ostinelli/misultin">Misultin</a> (Erlang)</li>
<li><a href="https://github.com/mochi/mochiweb">Mochiweb</a> (Erlang)</li>
<li><a href="https://github.com/extend/cowboy">Cowboy</a> (Erlang)</li>
<li><a href="http://nodejs.org/">NodeJS</a> (V8)</li>
<li><a href="http://www.tornadoweb.org/">Tornadoweb</a> (Python)</li>
</ul>
<p>I&#8217;ve chosen these libraries because they are the ones which currently interest me the most. <strong>Misultin</strong>, obviously since I wrote it; <strong>Mochiweb</strong>, since it&#8217;s a very solid library widely used in production (afaik it has been used or is still used to empower the Facebook Chat, amongst other things); <strong>Cowboy</strong>, a newly born lib whose programmer is very active in the Erlang community; <strong>NodeJS</strong>, since bringing javascript to the backend has opened up a new whole world of possibilities (code reusable in frontend, ease of access to various programmers,&#8230;); and finally, <strong>Tornadoweb</strong>, since Python still remains one of my favourites languages out there, and Tornadoweb has been excelling in loads of benchmarks and in production, empowering FriendFeed.</p>
<p>Two main ideas are behind this benchmark. First, I did not want to do a &#8220;Hello World&#8221; kind of test: we have static servers such as <a href="http://nginx.org/">Nginx</a> that wonderfully perform in such tasks. This benchmark needed to address dynamic servers. Second, I wanted sockets to get periodically closed down, since having all the load on a few sockets scarcely correspond to real life situations.</p>
<p>For the latter reason, I decided to use a <a href="http://gom-jabbar.org/articles/2009/02/04/httperf-and-file-descriptors">patched version</a> of <a href="http://www.hpl.hp.com/research/linux/httperf/">HttPerf</a>. It&#8217;s a widely known and used benchmark tool from HP, which basically tries to send a desired number of requests out to a server and reports how many of these actually got replied, and how many errors were experienced in the process (together with a variety of other pieces of information). A great thing about HttPerf is that you can set a parameter, called <em>&#8211;num-calls</em>, which sets the amount of calls per session (i.e. socket connection) before the socket gets closed by the client. The command issued in these tests was:</p>
<pre>httperf --timeout=5 --client=0/1 --server= --port=8080 --uri=/?value=benchmarks --rate= --send-buffer=4096
        --recv-buffer=16384 --num-conns=5000 --num-calls=10
</pre>
<p>The value of rate has been set incrementally between 100 and 1,200. Since the number of requests/sec = <em>rate</em> * <em>num-calls</em>, the tests were conducted for a desired number of responses/sec incrementing from 1,000 to 12,000. The total number of requests = <em>num-conns</em> * <em>rate</em>, which has therefore been a fixed value of 50,000 along every test iteration.</p>
<p>The test basically asks servers to:</p>
<ul>
<li>check if a GET variable is set</li>
<li>if the variable is not set, reply with an XML stating the error</li>
<li>if the variable is set, echo it inside an XML</li>
</ul>
<p>Therefore, what is being tested is:</p>
<ul>
<li>headers parsing</li>
<li>querystring parsing</li>
<li>string concatenation</li>
<li>sockets implementation</li>
</ul>
<p>The server is a virtualized up-to-date Ubuntu 10.04 LTS with 2 CPU and 1.5GB of RAM. Its <em>/etc/sysctl.conf</em> file has been tuned with these parameters:</p>
<pre># Maximum TCP Receive Window
net.core.rmem_max = 33554432
# Maximum TCP Send Window
net.core.wmem_max = 33554432
# others
net.ipv4.tcp_rmem = 4096 16384 33554432
net.ipv4.tcp_wmem = 4096 16384 33554432
net.ipv4.tcp_syncookies = 1
# this gives the kernel more memory for tcp which you need with many (100k+) open socket connections
net.ipv4.tcp_mem = 786432 1048576 26777216
net.ipv4.tcp_max_tw_buckets = 360000
net.core.netdev_max_backlog = 2500
vm.min_free_kbytes = 65536
vm.swappiness = 0
net.ipv4.ip_local_port_range = 1024 65535
net.core.somaxconn = 65535
</pre>
<p>The <em>/etc/security/limits.conf</em> file has been tuned so that ulimit -n is set to 65535 for both hard and soft limits.</p>
<p>Here is the code for the different servers.</p>
<p><strong>Misultin</strong></p>
<pre>-module(misultin_bench).
-export([start/1, stop/0, handle_http/1]).

start(Port) -&gt;
    misultin:start_link([{port, Port}, {loop, fun(Req) -&gt; handle_http(Req) end}]).

stop() -&gt;
    misultin:stop().

handle_http(Req) -&gt;
    % get value parameter
    Args = Req:parse_qs(),
    Value = misultin_utility:get_key_value("value", Args),
    case Value of
        undefined -&gt;
            Req:ok([{"Content-Type", "text/xml"}], ["&lt;http_test&gt;&lt;error&gt;no value specified&lt;/error&gt;&lt;/http_test&gt;"]);
        _ -&gt;
            Req:ok([{"Content-Type", "text/xml"}], ["&lt;http_test&gt;&lt;value&gt;", Value, "&lt;/value&gt;&lt;/http_test&gt;"])
    end.
</pre>
<p><strong>Mochiweb</strong></p>
<pre>-module(mochi_bench).
-export([start/1, stop/0, handle_http/1]).

start(Port) -&gt;
    mochiweb_http:start([{port, Port}, {loop, fun(Req) -&gt; handle_http(Req) end}]).

stop() -&gt;
    mochiweb_http:stop().

handle_http(Req) -&gt;
    % get value parameter
    Args = Req:parse_qs(),
    Value = misultin_utility:get_key_value("value", Args),
    case Value of
        undefined -&gt;
            Req:respond({200, [{"Content-Type", "text/xml"}], ["&lt;http_test&gt;&lt;error&gt;no value specified&lt;/error&gt;&lt;/http_test&gt;"]});
        _ -&gt;
            Req:respond({200, [{"Content-Type", "text/xml"}], ["&lt;http_test&gt;&lt;value&gt;", Value, "&lt;/value&gt;&lt;/http_test&gt;"]})
    end.
</pre>
<p><em>Note: i&#8217;m using misultin_utility:get_key_value/2 function inside this code since proplists:get_value/2 is much slower.</em></p>
<p><strong>Cowboy</strong></p>
<pre>-module(cowboy_bench).
-export([start/1, stop/0]).

start(Port) -&gt;
	application:start(cowboy),
	Dispatch = [
		%% {Host, list({Path, Handler, Opts})}
		{'_', [{'_', cowboy_bench_handler, []}]}
	],
	%% Name, NbAcceptors, Transport, TransOpts, Protocol, ProtoOpts
	cowboy:start_listener(http, 100,
		cowboy_tcp_transport, [{port, Port}],
		cowboy_http_protocol, [{dispatch, Dispatch}]
	).

stop() -&gt;
	application:stop(cowboy).
</pre>
<pre>-module(cowboy_bench_handler).
-behaviour(cowboy_http_handler).
-export([init/3, handle/2, terminate/2]).

init({tcp, http}, Req, _Opts) -&gt;
    {ok, Req, undefined_state}.

handle(Req, State) -&gt;
    {ok, Req2} = case cowboy_http_req:qs_val(&lt;&lt;"value"&gt;&gt;, Req) of
        {undefined, _} -&gt;
			cowboy_http_req:reply(200, [{&lt;&lt;"Content-Type"&gt;&gt;, &lt;&lt;"text/xml"&gt;&gt;}], &lt;&lt;"&lt;http_test&gt;&lt;error&gt;no value specified&lt;/error&gt;&lt;/http_test&gt;"&gt;&gt;, Req);
        {Value, _} -&gt;
			cowboy_http_req:reply(200, [{&lt;&lt;"Content-Type"&gt;&gt;, &lt;&lt;"text/xml"&gt;&gt;}], ["&lt;http_test&gt;&lt;value&gt;", Value, "&lt;/value&gt;&lt;/http_test&gt;"], Req)
    end,
    {ok, Req2, State}.

terminate(_Req, _State) -&gt;
    ok.
</pre>
<p><strong>NodeJS</strong></p>
<pre>var http = require('http'), url = require('url');
http.createServer(function(request, response) {
	response.writeHead(200, {"Content-Type":"text/xml"});
	var urlObj = url.parse(request.url, true);
	var value = urlObj.query["value"];
	if (value == ''){
		response.end("&lt;http_test&gt;&lt;error&gt;no value specified&lt;/error&gt;&lt;/http_test&gt;");
	} else {
		response.end("&lt;http_test&gt;&lt;value&gt;" + value + "&lt;/value&gt;&lt;/http_test&gt;");
	}
}).listen(8080);
</pre>
<p><strong>Tornadoweb</strong></p>
<pre>import tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler):
	def get(self):
		value = self.get_argument('value', '')
		self.set_header('Content-Type', 'text/xml')
		if value == '':
			self.write("&lt;http_test&gt;&lt;error&gt;no value specified&lt;/error&gt;&lt;/http_test&gt;")
		else:
			self.write("&lt;http_test&gt;&lt;value&gt;" + value + "&lt;/value&gt;&lt;/http_test&gt;")

application = tornado.web.Application([
	(r"/", MainHandler),
])

if __name__ == "__main__":
	application.listen(8080)
	tornado.ioloop.IOLoop.instance().start()</pre>
<p>I took this code and run it against:</p>
<ul>
<li>Misultin 0.7.1 (Erlang R14B02)</li>
<li>Mochiweb 1.5.2 (Erlang R14B02)</li>
<li>Cowboy master 420f5ba (Erlang R14B02)</li>
<li>NodeJS 0.4.7</li>
<li>Tornadoweb 1.2.1 (Python 2.6.5)</li>
</ul>
<p>All the libraries have been run with the standard settings. Erlang was launched with Kernel Polling enabled, and with SMP disabled so that a single CPU was used by all the libraries.</p>
<p><strong>Test results</strong></p>
<p>The raw printout of HttPerf results that I got can be downloaded from <a href="http://www.ostinelli.net/wp-content/uploads/2011/05/results.zip">here</a>.</p>
<p><a href="http://www.ostinelli.net/wp-content/uploads/2011/05/response_times.jpg"></a><a href="http://www.ostinelli.net/wp-content/uploads/2011/05/desired_vs_real.jpg"><img class="aligncenter size-full wp-image-384" title="desired_vs_real" src="http://www.ostinelli.net/wp-content/uploads/2011/05/desired_vs_real.jpg" alt="" width="650" height="529" /></a></p>
<p><a href="http://www.ostinelli.net/wp-content/uploads/2011/05/errors.jpg"><img class="aligncenter size-full wp-image-385" title="errors" src="http://www.ostinelli.net/wp-content/uploads/2011/05/errors.jpg" alt="" width="650" height="542" /></a></p>
<p><a href="http://www.ostinelli.net/wp-content/uploads/2011/05/response_times.jpg"></a><a href="http://www.ostinelli.net/wp-content/uploads/2011/05/response_times_log.jpg"><img class="aligncenter size-full wp-image-394" title="response_times_log" src="http://www.ostinelli.net/wp-content/uploads/2011/05/response_times_log.jpg" alt="" width="650" height="545" /></a></p>
<p style="text-align: center;"><em>Note: the above graph has a logarithmic Y scale.</em></p>
<p><a href="http://www.ostinelli.net/wp-content/uploads/2011/05/response_count.jpg"><img class="aligncenter size-full wp-image-386" title="response_count" src="http://www.ostinelli.net/wp-content/uploads/2011/05/response_count.jpg" alt="" width="650" height="577" /></a></p>
<p>According to this, we see that <strong>Tornadoweb</strong> tops at around 1,500 responses/seconds, <strong>NodeJS</strong> at 3,000, <strong>Mochiweb</strong> at 4,850, <strong>Cowboy</strong> at 8,600 and <strong>Misultin</strong> at 9,700. While Misultin and Cowboy experience very little or no error at all, the other servers seem to funnel under the load. Please note that &#8220;Errors&#8221; are timeout errors (over 5 seconds without a reply). Total responses and response times speak for themselves.</p>
<p>I have to say that I&#8217;m surprised on these results, to the point I&#8217;d like to have feedback on code and methodology, with alternate tests that can be performed. Any input is welcome, and I&#8217;m available to update this post and correct eventual errors I&#8217;ve made, as an ongoing discussion with whomever wants to contribute.</p>
<p>However, please do refrain from flame wars which are not welcomed here. I have published this post exactly because I was surprised on the results I got.</p>
<p>What is your opinion on all this?</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;</p>
<p><strong>UPDATE (May 16th, 2011)</strong></p>
<p>Due to the success of these benchmarks I want to stress an important point when you read any of these (including mines).</p>
<p>Benchmarks often are misleading interpreted as &#8220;the higher you are on a graph, the best that <em>*lib-of-the-moment-name-here*</em> is at doing everything&#8221;. This is absolutely the wrongest way to look at those. I cannot stress this point enough.</p>
<p>&#8216;Fast&#8217; is only 1 of the &#8216;n&#8217; features you desire from a webserver library: you definitely want to consider stability, features, ease of maintenance, low standard deviation, code usability, community, developments speed, and many other factors whenever choosing the best suited library for your own application. There is no such thing as generic benchmarks. These ones are related to a very specific situation: fast application computational times, loads of connections, and small data transfer.</p>
<p>Therefore, please use this with a grain of salt and do not jump to generic conclusions regarding any of the cited libraries, which as I&#8217;ve clearly stated in the beginning of my post I all find interesting and valuable. And I still am very open in being criticized for the described methodology or other things I might have missed.</p>
<p>Thank you,</p>
<p>r.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ostinelli.net/a-comparison-between-misultin-mochiweb-cowboy-nodejs-and-tornadoweb/feed/</wfw:commentRss>
		<slash:comments>45</slash:comments>
		</item>
		<item>
		<title>Erlang lists:keyfind or proplists:get_value?</title>
		<link>http://www.ostinelli.net/erlang-listskeyfind-or-proplistsget_value/</link>
		<comments>http://www.ostinelli.net/erlang-listskeyfind-or-proplistsget_value/#comments</comments>
		<pubDate>Thu, 20 May 2010 14:08:12 +0000</pubDate>
		<dc:creator>Roberto Ostinelli</dc:creator>
				<category><![CDATA[erlang]]></category>

		<guid isPermaLink="false">http://www.ostinelli.net/?p=359</guid>
		<description><![CDATA[Some days ago I quickly went through a post by Sergio Veiga, stating an interesting difference in speed between two Erlang functions which basically have the same functionality of retrieving a value from a list: lists:keyfind/3 and proplists:get_value/2. Intrigued, I decided to perform additional testing, by performing a small benchmark of a random key retrieval [...]]]></description>
			<content:encoded><![CDATA[<p>Some days ago I quickly went through a post by <a href="http://sergioveiga.com/index.php/2010/05/14/erlang-listskeyfind-vs-proplistsget_value/">Sergio Veiga</a>, stating an interesting difference in speed between two Erlang functions which basically have the same functionality of retrieving a value from a list: <a href="http://www.erlang.org/doc/man/lists.html#keyfind-3">lists:keyfind/3</a> and <a href="http://www.erlang.org/doc/man/proplists.html#get_value-2">proplists:get_value/2</a>.</p>
<p>Intrigued, I decided to perform additional testing, by performing a small benchmark of a random key retrieval on lists of different sizes, using those two different functions.</p>
<p>Here&#8217;s the code I used:</p>
<pre>
-module(pvsl).
-define(LIST_SIZES, [10000, 100000, 1000000]).
-define(RETRIES, 1000).
-compile(export_all).

start() ->
	% test for different list sizes
	lists:foreach(fun(N) -> test_list(N) end, ?LIST_SIZES).

test_list(ListSize) ->
	% generate a list of size ListSize of {Key, Val} entries
	KeyList = [{K, K} || K <- lists:seq(1, ListSize)],
	% test this list against both functions
	lists:foreach(fun(Type) -> get_val(Type, now(), KeyList, ListSize, ?RETRIES) end,
		[proplists, lists]).

% test getting values, compute necessary time and output print results
get_val(Type, Start, _KeyList, ListSize, 0) ->
	T = timer:now_diff(now(), Start),
	io:format("computed ~p random key searches on a ~p-sized list in ~p ms using ~p~n",
		[?RETRIES, ListSize, T/1000, Type]);
get_val(proplists, Start, KeyList, ListSize, Tries) ->
	proplists:get_value(random:uniform(ListSize), KeyList),
	get_val(proplists, Start, KeyList, ListSize, Tries - 1);
get_val(lists, Start, KeyList, ListSize, Tries) ->
	lists:keyfind(random:uniform(ListSize), 1, KeyList),
	get_val(lists, Start, KeyList, ListSize, Tries - 1).
</pre>
<p>I ran this test on my MacBook Pro, Intel Core i5 2.4GHz with 4GB Memory, and Erlang R13B04, with Kernel Polling enabled. These are the results.</p>
<pre>
roberto$ erl +K true +P 1000000
Erlang R13B04 (erts-5.7.5) [source] [smp:4:4] [rq:4] [async-threads:0] [hipe] [kernel-poll:true]

Eshell V5.7.5  (abort with ^G)
1> c(pvsl).
{ok,pvsl}
2> pvsl:start().
computed 1000 random key searches on a 10000-sized list in 323.373 ms using proplists
computed 1000 random key searches on a 10000-sized list in 12.897 ms using lists
computed 1000 random key searches on a 100000-sized list in 3273.973 ms using proplists
computed 1000 random key searches on a 100000-sized list in 130.592 ms using lists
computed 1000 random key searches on a 1000000-sized list in 34131.905 ms using proplists
computed 1000 random key searches on a 1000000-sized list in 2050.627 ms using lists
ok
3>
</pre>
<p>Of course, this is far from being a complete benchmark, however it does show that proplists:get_value/2 is considerably slower [up to 25 times on smaller lists on this benchmark run] than lists:keyfind.</p>
<p>Not sure why this is happening, though I would recommend using lists:keyfind/3 on all speed-critical parts of your code.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ostinelli.net/erlang-listskeyfind-or-proplistsget_value/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Misultin: erlang and websockets</title>
		<link>http://www.ostinelli.net/misultin-erlang-and-websockets/</link>
		<comments>http://www.ostinelli.net/misultin-erlang-and-websockets/#comments</comments>
		<pubDate>Wed, 20 Jan 2010 14:33:12 +0000</pubDate>
		<dc:creator>Roberto Ostinelli</dc:creator>
				<category><![CDATA[erlang]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[comet]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[misultin]]></category>
		<category><![CDATA[websocket]]></category>
		<category><![CDATA[websockets]]></category>

		<guid isPermaLink="false">http://www.ostinelli.net/?p=331</guid>
		<description><![CDATA[Inspired by Joe Armstrong&#8217;s post, I&#8217;ve recently added websocket support to misultin v0.4, my Erlang library for building fast lightweight HTTP servers. Basically, websockets allow a two-way asynchronous communication between browser and servers, filling the gap that some technologies such as ajax and comet have tried to fulfill in these recent years. If you want [...]]]></description>
			<content:encoded><![CDATA[<p>Inspired by Joe Armstrong&#8217;s <a href="http://armstrongonsoftware.blogspot.com/2009/12/comet-is-dead-long-live-websockets.html">post</a>, I&#8217;ve recently added <a href="http://dev.w3.org/html5/websockets/">websocket</a> support to <a href="http://code.google.com/p/misultin/">misultin</a> v0.4, my Erlang library for building fast lightweight HTTP servers.</p>
<p>Basically, websockets allow a two-way asynchronous communication between browser and servers, filling the gap that some technologies such as ajax and comet have tried to fulfill in these recent years. If you want to try this out yourself, you will first need to grab a browser which implements websockets, such as <a href="http://www.google.com/chrome/">Google Chrome</a>.</p>
<p>The typical html page with javascript code to use websockets is as follows:</p>
<pre>
&lt;html>
   &lt;head>
     &lt;script type="text/javascript">
         function addStatus(text){
            var date = new Date();
            document.getElementById('status').innerHTML = document.getElementById('status').innerHTML
               + date + ": " + text + "&lt;br>";
         }
         function ready(){
            if ("WebSocket" in window) {
               // browser supports websockets
               var ws = new WebSocket("ws://localhost:8080/service");
               ws.onopen = function() {
                  // websocket is connected
                  addStatus("websocket connected!");
                  // send hello data to server.
                  ws.send("hello server!");
                  addStatus("sent message to server: 'hello server'!");
               };
               ws.onmessage = function (evt) {
                  var receivedMsg = evt.data;
                  addStatus("server sent the following: '" + receivedMsg + "'");
               };
               ws.onclose = function() {
                  // websocket was closed
                  addStatus("websocket was closed");
               };
            } else {
               // browser does not support websockets
               addStatus("sorry, your browser does not support websockets.");
            }
         }
      &lt;/script>
   &lt;/head>
   &lt;body onload="ready();">
      &lt;div id="status">&lt;/div>
   &lt;/body>
&lt;/html>
</pre>
<p>Here’s the code to use misultin to handle the requests of this script:</p>
<pre>
-module(misultin_websocket_example).
-export([start/1, stop/0]).

% start misultin http server
start(Port) ->
	misultin:start_link([{port, Port}, {loop, fun(Req) -> handle_http(Req, Port) end},
	{ws_loop, fun(Ws) -> handle_websocket(Ws) end}]).

% stop misultin
stop() ->
	misultin:stop().

% callback on request received
handle_http(Req, Port) ->
	% output
	Req:ok([]).

% callback on received websockets data
handle_websocket(Ws) ->
	receive
		{browser, Data} ->
			Ws:send(["received '", Data, "'"]),
			handle_websocket(Ws);
		_Ignore ->
			handle_websocket(Ws)
	after 5000 ->
		Ws:send("pushing!"),
		handle_websocket(Ws)
	end.
</pre>
<p>handle_websocket/1 is spawned by misultin to handle the connected websockets. Data coming from a browser will be sent to this process and will have the message format {browser, Data}, where Data is a string(). If you need to send data to the browser, you may do so by using the parametrized function Ws:send(Data), Data being a string() or an iolist().</p>
<p>Compile and run the example here above with misultin_websocket_example:start(8080). Then, open up your Chrome (or other websocket compliant browser) and point it to an .html file containing the above code.</p>
<p>You should normally see this being gradually printed on your browser:</p>
<pre>
Wed Jan 20 2010 15:18:52 GMT+0100 (CET): websocket connected!
Wed Jan 20 2010 15:18:52 GMT+0100 (CET): sent message to server: 'hello server'!
Wed Jan 20 2010 15:18:52 GMT+0100 (CET): server sent the following: 'received 'hello server!''
Wed Jan 20 2010 15:18:57 GMT+0100 (CET): server sent the following: 'pushing!'
Wed Jan 20 2010 15:19:02 GMT+0100 (CET): server sent the following: 'pushing!'
Wed Jan 20 2010 15:19:07 GMT+0100 (CET): server sent the following: 'pushing!'
</pre>
<p>In normal environments you may consider serving the .html page from misultin directly. You may do so with the following and complete misultin module:</p>
<pre>
-module(misultin_websocket_example).
-export([start/1, stop/0]).

% start misultin http server
start(Port) ->
   misultin:start_link([{port, Port}, {loop, fun(Req) -> handle_http(Req, Port) end}, {ws_loop, fun(Ws) -> handle_websocket(Ws) end}]).

% stop misultin
stop() ->
   misultin:stop().

% callback on request received
handle_http(Req, Port) ->
   % output
   Req:ok([{"Content-Type", "text/html"}],
   ["
   &lt;html>
      &lt;head>
         &lt;script type=\"text/javascript\">
            function addStatus(text){
               var date = new Date();
               document.getElementById('status').innerHTML = document.getElementById('status').innerHTML
                  + date + \": \" + text + \"&lt;br>\";
            }
            function ready(){
               if (\"WebSocket\" in window) {
                  // browser supports websockets
                  var ws = new WebSocket(\"ws://localhost:", integer_to_list(Port) ,"/service\");
                  ws.onopen = function() {
                     // websocket is connected
                     addStatus(\"websocket connected!\");
                     // send hello data to server.
                     ws.send(\"hello server!\");
                     addStatus(\"sent message to server: 'hello server'!\");
                  };
                  ws.onmessage = function (evt) {
                     var receivedMsg = evt.data;
                     addStatus(\"server sent the following: '\" + receivedMsg + \"'\");
                  };
                  ws.onclose = function() {
                     // websocket was closed
                     addStatus(\"websocket was closed\");
                  };
               } else {
                  // browser does not support websockets
                  addStatus(\"sorry, your browser does not support websockets.\");
               }
            }
         &lt;/script>
      &lt;/head>
      &lt;body onload=\"ready();\">
         &lt;div id=\"status\">&lt;/div>
      &lt;/body>
   &lt;/html>"]).

% callback on received websockets data
handle_websocket(Ws) ->
   receive
      {browser, Data} ->
         Ws:send(["received '", Data, "'"]),
         handle_websocket(Ws);
      _Ignore ->
         handle_websocket(Ws)
   after 5000 ->
      Ws:send("pushing!"),
      handle_websocket(Ws)
   end.
</pre>
<p>Please note that the <a href="http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-68">Websocket Protocol</a> still is draft. use with caution.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ostinelli.net/misultin-erlang-and-websockets/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Misultin library</title>
		<link>http://www.ostinelli.net/misultin/</link>
		<comments>http://www.ostinelli.net/misultin/#comments</comments>
		<pubDate>Mon, 27 Jul 2009 11:11:47 +0000</pubDate>
		<dc:creator>Roberto Ostinelli</dc:creator>
				<category><![CDATA[erlang]]></category>
		<category><![CDATA[benchmark]]></category>
		<category><![CDATA[library]]></category>
		<category><![CDATA[lightweight http server]]></category>
		<category><![CDATA[misultin]]></category>

		<guid isPermaLink="false">http://www.ostinelli.net/?p=323</guid>
		<description><![CDATA[Today I&#8217;ve released Misultin (pronounced mee-sul-teen), an Erlang library for building fast lightweight HTTP servers. The first benchmarks are quite satisfying, even though there still is work to do. Here is the simple code for Misultin&#8217;s Hello World. -module(misultin_hello_world). -vsn('0.1'). -export([start/1, stop/0, handle_http/1]). % start misultin http server start(Port) -> misultin:start_link([{port, Port}, {loop, fun(Req) -> [...]]]></description>
			<content:encoded><![CDATA[<p>Today I&#8217;ve released Misultin (pronounced mee-sul-teen), an Erlang library for building fast lightweight HTTP servers. The first <a href="http://code.google.com/p/misultin/wiki/Benchmarks">benchmarks</a> are quite satisfying, even though there still is work to do.</p>
<p>Here is the simple code for Misultin&#8217;s Hello World.</p>
<pre>
-module(misultin_hello_world).
-vsn('0.1').
-export([start/1, stop/0, handle_http/1]).

% start misultin http server
start(Port) ->
    misultin:start_link([{port, Port}, {loop, fun(Req) -> handle_http(Req) end}]).

% stop misultin
stop() ->
    misultin:stop().

% callback on request received
handle_http(Req) ->
    Req:ok("Hello World.").
</pre>
<p>Here&#8217;s the code to echo a GET variable in a XML form.</p>
<pre>
-module(misultin_get_variable).
-vsn('0.1').
-export([start/1, stop/0, handle_http/1]).

% start misultin http server
start(Port) ->
    misultin:start_link([{port, Port}, {loop, fun(Req) -> handle_http(Req) end}]).

% stop misultin
stop() ->
    misultin:stop().

% callback on request received
handle_http(Req) ->
    % get params
    Args = Req:parse_qs(),
    Value = proplists:get_value("value", Args),
    case Value of
        undefined ->
            Req:ok([{"Content-Type", "text/xml"}], "<misultin_test><error>no value specified</error></misultin_test>");
        _ ->
            Req:ok([{"Content-Type", "text/xml"}], "<misultin_test><value>~s</value></misultin_test>", [Value])
    end.
</pre>
<p>Available also are <a href="http://code.google.com/p/misultin/wiki/ExamplesPage">additional code examples</a>, and the <a href="http://code.google.com/p/misultin/wiki/Exports">full list of exports</a>.</p>
<p>You may find Misultin, released under the <a href="http://www.opensource.org/licenses/bsd-license.php">New BSD License</a>, on its <a href="http://code.google.com/p/misultin">project page on Google code</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ostinelli.net/misultin/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Boost message passing between Erlang nodes</title>
		<link>http://www.ostinelli.net/boost-message-passing-between-erlang-nodes/</link>
		<comments>http://www.ostinelli.net/boost-message-passing-between-erlang-nodes/#comments</comments>
		<pubDate>Tue, 07 Apr 2009 21:43:31 +0000</pubDate>
		<dc:creator>Roberto Ostinelli</dc:creator>
				<category><![CDATA[erlang]]></category>
		<category><![CDATA[boost performance]]></category>
		<category><![CDATA[message passing]]></category>
		<category><![CDATA[nodes]]></category>

		<guid isPermaLink="false">http://www.ostinelli.net/?p=273</guid>
		<description><![CDATA[Message passing between Erlang nodes is considerably slower than within the same node. This is normal, and is due to the fact that messages sent between nodes are actually copied from the area of the sender to that of the receiver, then sent over from one node to the other via TCP/IP. In the systems [...]]]></description>
			<content:encoded><![CDATA[<p>Message passing between Erlang nodes is considerably slower than within the same node. This is normal, and is due to the fact that messages sent between nodes are actually <strong>copied </strong>from the area of the sender to that of the receiver, then sent over from one node to the other via TCP/IP.</p>
<p>In the systems I&#8217;m building I need to get as fast as possible in message passing between nodes. Who doesn&#8217;t? :) I was getting frustrated when a server could achieve amazing performance over a single node, performance which got much lower once the server got distributed over two Erlang nodes. I therefore tried a small benchmark test to somehow measure the difference in message passing speed within/across Erlang nodes.</p>
<p>The machine used in this benchmark is an apple macbook running Leopard, with 2.0GHz Intel Core 2 Duo and 2GB of DDR3 RAM memory.</p>
<p>This benchmark is a very simple ping request/pong response test. A process &#8216;A&#8217; sends a ping message to process &#8216;B&#8217;, which replies with a pong message.</p>
<p>Code for the <strong>pong process</strong>:</p>
<pre>% starts pong
start_pong() -&gt;
	register(flood_pong, spawn(fun() -&gt; pong_loop() end)).

pong_loop() -&gt;
	receive
		{{Sender, SenderNode}, Any} -&gt;
			% pong back
			{Sender, SenderNode} ! {pong, Any},
			pong_loop();
		shutdown -&gt;
			io:format("pong shutdown~n",[]);
		_Ignore -&gt;
			pong_loop()
	after 60000 -&gt;
		io:format("pong timeout, shutdown~n",[])
	end.</pre>
<p>This very simple code basically starts a process and registers it with the name <em>flood_pong</em>. You can see that to any request with format:</p>
<pre>{{Sender, SenderNode}, Any}</pre>
<p>flood_pong will reply with a message with format:</p>
<pre>{pong, Any}</pre>
<p>The code for the <strong>ping process</strong>, i.e. the one that starts the ping requests, is the following:</p>
<pre>% start ping
start_ping(PongNode, Num) -&gt;
	register(flood_ping, spawn(fun() -&gt; ping_loop(Num, now(), Num) end)),
	send(PongNode, Num).

send(_PongNode, 0) -&gt;
	ok;
send(PongNode, Num) -&gt;
	% send a spawned ping
	spawn(fun() -&gt; {flood_pong, PongNode} ! {{flood_ping, node()}, ping_request} end),
	send(PongNode, Num - 1).

ping_loop(Num, Start, 0) -&gt;
	T = timer:now_diff(now(), Start),
	io:format("RECEIVED ALL ~p in ~p ms [~p/min]~n",[Num, T, (Num*60000000/T)]);
ping_loop(Num, Start, Count) -&gt;
	receive
		{pong, _PingBack} -&gt;
			ping_loop(Num, Start, Count-1);
		_Received -&gt;
			ping_loop(Num, Start, Count)
	after 10000 -&gt;
		io:format("ping timeout, missing ~p pong, shutdown~n",[Count])
	end.</pre>
<p>This code does two things:</p>
<ul>
<li>Starts and registers a <em>flood_ping</em> process, which will be responsible to await and count the incoming pong replies. This allows it to compute the time needed for all the pong replies to get back to the node where the ping requests where first sent.</li>
<li>Spawns the ping requests [one process per ping request].</li>
</ul>
<p>Let&#8217;s give it a try. First, we have to start up two Erlang nodes, so I fire up terminal and enter:</p>
<pre>:~ roberto$ erl +K true +P 500000 -name 'one@rob.loc' -setcookie asd</pre>
<p>and in another terminal window:</p>
<pre>:~ roberto$ erl +K true +P 500000 -name 'two@rob.loc' -setcookie asd</pre>
<p>This initializes two erlang nodes, &#8216;one@rob.loc&#8217; and &#8216;two@rob.loc&#8217;, both with kernel polling enabled and a maximum number of processes per node set to 500,000.</p>
<p>I need to ensure that the nodes can see each other, so from &#8216;one@rob.loc&#8217; I ping &#8216;two@rob.loc&#8217;:</p>
<pre>(one@rob.loc)1&gt;net_adm:ping('two@rob.loc').
pong
(one@rob.loc)2&gt;nodes().
['two@rob.loc']</pre>
<p>Now let&#8217;s perform a message passing speed benchmark for messages sent and received within the same Erlang node. First, I start up the pong process:</p>
<pre>(one@rob.loc)3&gt; flood1:start_pong().
true</pre>
<p>I then need to start the ping requests, and I do so by issuing the start_ping/2 function, which has per arguments the name of the recipient node of the ping requests, and the number of requests to be performed. I therefore set the first parameter to node() and the second to 200,000 [we'll always try out 200,000 ping requests].</p>
<pre>(one@rob.loc)4&gt; flood1:start_ping(node(), 200000).
ok
RECEIVED ALL 200000 in 2257727 ms [5315080.166911234/min]</pre>
<p>I see therefore that <strong>within the same Erlang node</strong>, this benchmark gives a result of an average of <strong>5.3 million</strong> ping/pong messages per minute. Quite a rush.</p>
<p>Let&#8217;s now try the same thing with pong running on &#8216;two@rob.loc&#8217;, and ping requests coming from &#8216;one@rob.loc&#8217;. I start the pong process on &#8216;two@rob.loc&#8217;:</p>
<pre>(two@rob.loc)1&gt; flood1:start_pong().</pre>
<p>Then I issue the ping request from &#8216;one@rob.loc&#8217;:</p>
<pre>(one@rob.loc)5&gt; flood1:start_ping('two@rob.loc', 200000).
ok
RECEIVED ALL 200000 in 16727643 ms [717375.4246189974/min]</pre>
<p>I see therefore that <strong>on two different Erlang nodes</strong>, this benchmark gives a result of an average of <strong>700 thousands</strong> ping/pong messages per minute.</p>
<p>This is around 7 times a loss in performance when compared to the same benchmark run on a single Erlang node. It is simply unacceptable: it does mean that a system heavily dependant on message passing and running on a single Erlang node would be considerably faster than one running on distributed nodes [one of the things Erlang is great at doing].</p>
<p>At this point, I tried reducing the overhead in message passing, by using UDP instead of Erlang&#8217;s native functionalities. This was no success at all, UDP having all the troubles it&#8217;s known for (packet loss, ordering, double packet sending, &#8230;) without me getting any interesting speed improvement.</p>
<p>It&#8217;s only here that I got this thought: what if Erlang&#8217;s message passing overhead is so demanding, due to TCP/IP, that actually <em>queuing</em> messages sent to processes running on the same node and sending them altogether would increase the overall passing speed? TCP/IP already does provide such mechanisms, but what if performing this queuing at Erlang application level could bring significant improvements to infra-nodes message passing?</p>
<p>This is the picture. On both Erlang nodes I run a gen_server [which I called <em>qr</em>] which performs queuing and routing of messages sent from one node to the other. Instead of sending messages directly from a process A on node &#8216;one@rob.loc&#8217; to a process B on node &#8216;two@rob.loc&#8217;, process A sends a routing request to the <em>qr</em> running on &#8216;one@rob.loc&#8217;, which will then send it to the <em>qr</em> running on &#8216;two@rob.loc&#8217;, which will finally forward it to B. Fact is, the sending <em>qr</em> will queue messages until a certain number of them for the same node have piled up, or a timeout period has expired.</p>
<p><a href="http://www.ostinelli.net/wp-content/uploads/2009/04/qr.jpg"><img class="aligncenter size-full wp-image-276" title="qr" src="http://www.ostinelli.net/wp-content/uploads/2009/04/qr.jpg" alt="" width="350" height="234" /></a></p>
<p>I start by defining the gen_server API to route a message. Here it is:</p>
<pre>% Function() -&gt; void()
% Description: Gets a routing request
route({ToPid, ToNode}, Message) -&gt;
	case ToNode =:= node() of
		true -&gt;
			% send directly
			ToPid ! Message;
		false -&gt;
			% queue
			gen_server:cast(?SERVER, {{queue, ToNode}, {ToPid, Message}})
	end.</pre>
<p>You can see that we need to pass the <strong>Pid </strong>of the destination process, as well as the name of the <strong>Node </strong>where this process is running, together with the <strong>Message </strong>that we need to send.</p>
<p>In case the node is remote, this will cast a message to <em>qr</em>, which will handle it:</p>
<pre>% add incoming routing request to queue
handle_cast({{queue, DestNode}, {ToPid, Message}}, Queue) -&gt;
	% to pid
	Msg = {route, ToPid, Message},
	% get if node exists in queue
	case lists:keysearch(DestNode, 1, Queue) of
		false -&gt;
			% add node
			NewQueue = [{DestNode, {now(), [Msg]}}|Queue];
		{value, {DestNode, {CreationTime, MsgList}}} -&gt;
			% check if queue is long enough
			case length(MsgList) &gt;= ?QUEUELENGTH of
				true -&gt;
					% queue of a node is of maximum lenght, send routing message
					{?QR, DestNode} ! {queue_route, [Msg|MsgList]},
					% empty queue for node
					NewQueue = lists:keydelete(DestNode, 1, Queue);
				false -&gt;
					% add message to queue list and replace node
					NewQueue = lists:keyreplace(DestNode, 1, Queue, {DestNode, {CreationTime, [Msg|MsgList]}})
			end
	end,
	% purge timeout
	PurgedQueue = purge_queue_selective(NewQueue),
	{noreply, PurgedQueue, 200};

[...]

% Function -&gt; PurgedQueue
% Description: Loop queue and purge only nodes on timeout.
purge_queue_selective(Queue) -&gt;
	% check timeout, send and remove element if needed
	FilterFun = fun({DestNode, {CreationTime, MsgList}}) -&gt;
		case timer:now_diff(now(), CreationTime) &gt; ?QUEUETIMEOUT of
			true -&gt;
				% timeout for a node, send routing message
				% io:format("send selective: {?QR, ~p} ! {queue_route, ~p}~n",[DestNode, MsgList]),
				{?QR, DestNode} ! {queue_route, MsgList},
				% delete node from queue
				false;
			false -&gt;
				true
		end
	end,
	% return cleaned queue
	lists:filter(FilterFun, Queue).</pre>
<p>The mecanism is quite simple. When a message to be sent to a remote node arrives to <em>qr</em>, we build a list of key tuples [which will be passed along as gen_server State variable] of format:</p>
<pre>{DestNode, {CreationTime, MsgList}}</pre>
<p>DestNode, i.e. the destination node, is the tuple key. CreationTime is a parameter which allows to know when a timeout for the messages to DestNode has passed. MsgList is a list of tuples of the messages to be sent to DestNode, in format:</p>
<pre>{route, ToPid, Message}</pre>
<p>We handle this key list to check when to send all the queued messages to the other node, which we do:</p>
<ul>
<li>when a certain <strong>timeout </strong>has passed for that node [computed using CreationTime];</li>
<li>when the number of messages to be sent has reached a certain <strong>size</strong>.</li>
</ul>
<p>We see that the gen_server cast also establishes an overall timeout of 200 ms, which will fire when no other messages are received by <em>qr</em> and thus we need to send the remaining messages out. This timeout is handled with a handle_info call:</p>
<pre>% timeout on a cast message, purge queue
handle_info(timeout, Queue) -&gt;
	% purge timeout
	PurgedQueue = purge_queue(Queue),
	% return
	{noreply, PurgedQueue};

[...]

% Function -&gt; PurgedQueue
% Description: Loop queue and purge all nodes.
purge_queue(Queue) -&gt;
	% sent to all remaining
	FilterFun = fun({DestNode, {_CreationTime, MsgList}}) -&gt;
		% send routing message
		{?QR, DestNode} ! {queue_route, MsgList}
	end,
	lists:foreach(FilterFun, Queue),
	% return an empty queue
	[].</pre>
<p>As we can see from here over, a message sent from a <em>qr </em>on one node to a <em>qr </em>of another node has format:</p>
<pre>{queue_route, MsgList}</pre>
<p>With MsgList being a list of the individual messages in format:</p>
<pre>{route, ToPid, Message}</pre>
<p>When a <em>qr </em>of a node receives such a message, it handles it:</p>
<pre>handle_info({queue_route, MsgList}, State) -&gt;
	RouteFun = fun({route, ToPid, Message}) -&gt;
		% local send to node
		ToPid ! Message
	end,
	lists:foreach(RouteFun, MsgList),
	% return
	{noreply, State, 200};</pre>
<p>Ok, this basically is it. Let&#8217;s now see if this does improve message passing between nodes.</p>
<p>For this, we need to redifine the pong_loop so that it does not send messages directly to the process, but routes its requests to <em>qr</em> instead.</p>
<p>New code for the <strong>pong process</strong>:</p>
<pre>% starts pong
start_pong() -&gt;
	register(flood_pong, spawn(fun() -&gt; pong_loop() end)).

pong_loop() -&gt;
	receive
		{{Sender, SenderNode}, Any} -&gt;
			% pong back
			qr:route({Sender, SenderNode}, {pong, Any}),    % &lt; === ONLY LINE CHANGED ===
			pong_loop();
		shutdown -&gt;
			io:format("pong shutdown~n",[]);
		_Ignore -&gt;
			pong_loop()
	after 30000 -&gt;
		io:format("pong timeout, shutdown~n",[])
	end.</pre>
<p>The same goes for the <strong>ping process</strong>:</p>
<pre>% start ping
start_ping(PongNode, Num) -&gt;
	register(flood_ping, spawn(fun() -&gt; ping_loop(Num, now(), Num) end)),
	send(PongNode, Num).

send(_PongNode, 0) -&gt;
	ok;
send(PongNode, Num) -&gt;
	% send a spawned ping                               % === \/ ONLY LINE CHANGED ===
	spawn(fun() -&gt; qr:route({flood_pong, PongNode}, {{flood_ping, node()}, ping_request}) end),
	send(PongNode, Num - 1).

ping_loop(Num, Start, 0) -&gt;
	T = timer:now_diff(now(), Start),
	io:format("RECEIVED ALL ~p in ~p ms [~p/min]~n",[Num, T, (Num*60000000/T)]);
ping_loop(Num, Start, Count) -&gt;
	receive
		{pong, _PingBack} -&gt;
			ping_loop(Num, Start, Count-1);
		_Received -&gt;
			ping_loop(Num, Start, Count)
	after 10000 -&gt;
		io:format("ping timeout, missing ~p pong, shutdown~n",[Count])
	end.</pre>
<p>We are all set. Let&#8217;s try to immediately perform a test on two different Erlang nodes, pong running on &#8216;two@rob.loc&#8217;, and ping requests coming from &#8216;one@rob.loc&#8217;. I start <em>qr</em> and the pong process on &#8216;two@rob.loc&#8217;:</p>
<pre>(two@rob.loc)55&gt; qr:start_link().
{ok,&lt;0.38.0&gt;}
(two@rob.loc)56&gt; flood2:start_pong().
true</pre>
<p>Then I start <em>qr</em> and issue the ping request from &#8216;one@rob.loc&#8217;:</p>
<pre>(one@rob.loc)44&gt; qr:start_link().
{ok,&lt;0.114.0&gt;}
(one@rob.loc)45&gt; flood2:start_ping('two@rob.loc', 200000).
ok
RECEIVED ALL 200000 in 5690225 ms [2108879.7015935224/min]</pre>
<p>I see therefore that <strong>on two different Erlang nodes</strong>, this benchmark gives a result of an average of <strong>2.1 million</strong> ping/pong messages per minute, <strong>3 times as much as without message queuing</strong>!</p>
<p>Just to be on the safe side, I try the same benchmark for messages sent via <em>qr </em>to processes running on the same Erlang node.</p>
<pre>{ok,&lt;0.3562.6&gt;}
(two@rob.loc)50&gt; flood2:start_pong().
true
(two@rob.loc)51&gt; flood2:start_ping(node(), 200000).
ok
RECEIVED ALL 200000 in 2264539 ms [5299091.779828035/min]</pre>
<p>I see therefore that <strong>within the same Erlang node</strong>, this benchmark gives a result of an average of <strong>5.3 million</strong> ping/pong messages per minute, the same that we had without the queuing mechanism.</p>
<p>To summarize:</p>
<ul>
<li><strong>without </strong>queuing mechanism:
<ul>
<li>same Erlang node: 5.3 million messages/min;</li>
<li>different Erlang nodes: <strong>700 K</strong> messages/min.</li>
</ul>
</li>
<li><strong>with </strong>queuing mechanism:
<ul>
<li>same Erlang node: 5.3 million messages/min;</li>
<li>different Erlang nodes: <strong>2.1 million</strong> messages/min.</li>
</ul>
</li>
</ul>
<p>The complete code to run this on your machine is available <a href="http://www.ostinelli.net/wp-content/uploads/2009/04/erlang_mq_boost.zip">here</a>. This whole &#8216;queuing idea&#8217; is still an experiment, and I&#8217;d be more than delighted to hear your feedback, to see whether you are getting the same results, you know how to improve the concept or the code, or you have any considerations at all you would like to share.</p>
<hr />
<p><strong>UPDATE [April 17th, 2009]</strong></p>
<p>&nbsp;</p>
<hr />
<p>Due to a comment here below from <a href="http://adam.bregenzer.net/">Adam Bregenzer</a>, who  performed a test on a Linux box and had very different results, I&#8217;ve decided to perform some testing on 3 different OS. Here is a summary of these tests, but please bear in mind that these results are definitely non exhaustive.</p>
<p>1. macbook running <strong>Leopard OSX</strong>, with 2.0GHz Intel Core 2 Duo and 2GB of DDR3 RAM memory.</p>
<ul>
<li>on the same Erlang node: 5.3 million messages/min;</li>
<li>on different Erlang nodes:
<ul>
<li>without queuing mechanism: 700 K messages/min.</li>
<li><strong>with queuing mechanism: 2.1 million messages/min</strong>.</li>
</ul>
</li>
</ul>
<p>2. <strong>Ubuntu 8.10 Linux</strong>, 64-bit system with 2.5GHz Intel Core 2 Duo [Adam's test]</p>
<ul>
<li>on the same Erlang node: 11.7 million messages/min;</li>
<li>on different Erlang nodes:
<ul>
<li><strong>without queuing mechanism: 4.8 million messages/min.</strong></li>
<li>with queuing mechanism: 3.6 million messages/min.</li>
</ul>
</li>
</ul>
<p>3. <strong>Ubuntu 9.04 beta Linux</strong>, 32-bit system on a VM with 1 CPU 2.0GHz and 512MB of RAM memory.</p>
<ul>
<li>on the same Erlang node: 4.6 million messages/min;</li>
<li>on different Erlang nodes:
<ul>
<li><strong>without queuing mechanism: 1.6 million messages/min.</strong></li>
<li>with queuing mechanism: 960K messages/min.</li>
</ul>
</li>
</ul>
<p>4. <strong>Windows XP</strong>, with 3.0GHz Intel Core 2 Duo E8400 and 2.5GB of DDR3 RAM memory.</p>
<ul>
<li>on the same Erlang node: 24.7 million messages/min;</li>
<li>on different Erlang nodes:
<ul>
<li>without queuing mechanism: 2.2 million messages/min.</li>
<li><strong>with queuing mechanism: 5.1 million messages/min.</strong></li>
</ul>
</li>
</ul>
<p>As it is normal with Erlang, results are extremely different depending on many factor, one of which seems to be the OS. On the non-exhaustive tests here above, the qr mechanism does:</p>
<ul>
<li><strong>improve </strong>message passing performance between Erlang nodes in the <em>OSX </em>and <em>Windows </em>environment;</li>
<li><strong>decrease </strong>message passing performance between Erlang nodes in the <em>Ubuntu Linux</em> environment.</li>
</ul>
<p>I do not have the insights to understand which characteristics of each OS is switching results in this manner: TCP/IP flow, threads, I/O. Though, I&#8217;m currently deploying a similar qr mechanism in my applications, which can be activated if necessary based on individual benchmarking tests.</p>
<hr />
<p><strong>UPDATE [June 9th, 2009]</strong></p>
<p>&nbsp;</p>
<hr />
<p>I have had the availability of two HP ProLiant DL380, running Ubuntu 8.04 Server 32 bit, therefore I decided to take a shot also to test the same bench on different machines.</p>
<p>Here is a summary of the results of these tests. As usual, please bear in mind that these results are definitely non exhaustive.</p>
<ul>
<li>on the same Erlang node: 5.3 million messages/min [on both machines];</li>
<li>on two different Erlang nodes, both running on the <em>same machine</em>:
<ul>
<li>without queuing mechanism: 1.7 K million messages/min.</li>
<li><strong>with queuing mechanism: 3.1 million messages/min</strong>.</li>
</ul>
</li>
<li>on two different Erlang nodes, each running on a <em>different machine</em>:
<ul>
<li>without queuing mechanism: 1.7 K million messages/min.</li>
<li><strong>with queuing mechanism: 3.2 million messages/min</strong>.</li>
</ul>
</li>
</ul>
<p>This seems to state that the qr mechanism does <strong>improve </strong>message passing performance between Erlang nodes, also on the <strong>Ubuntu 8.04 </strong> environment.</p>
<p>I&#8217;ve also updated the original code, so that the destination node identifier is now extracted from the recipient Pid and thus it is not necessary to pass it as variable. This code can be found <a href="http://www.ostinelli.net/wp-content/uploads/2009/06/erlang_mq_boost_2.zip">here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ostinelli.net/boost-message-passing-between-erlang-nodes/feed/</wfw:commentRss>
		<slash:comments>40</slash:comments>
		</item>
		<item>
		<title>Stone Balancing</title>
		<link>http://www.ostinelli.net/stone-balancing/</link>
		<comments>http://www.ostinelli.net/stone-balancing/#comments</comments>
		<pubDate>Sun, 10 Aug 2008 15:58:34 +0000</pubDate>
		<dc:creator>Roberto Ostinelli</dc:creator>
				<category><![CDATA[Main]]></category>
		<category><![CDATA[Stone Balancing]]></category>

		<guid isPermaLink="false">http://www.ostinelli.net/?p=180</guid>
		<description><![CDATA[I find stone balancing an incredible way to concentrate all my mind on one single point of focus, in a vision where distraction cannot appear. It is at the same time relaxing, enriching and very tiring. Here are some attempts at stone balancing.]]></description>
			<content:encoded><![CDATA[<p>I find stone balancing an incredible way to concentrate all my mind on one single point of focus, in a vision where distraction cannot appear. It is at the same time relaxing, enriching and very tiring.</p>
<p>Here are some attempts at stone balancing.</p>
<p><img class="alignleft size-full wp-image-182" title="stone_balancing_01" src="http://www.ostinelli.net/wp-content/uploads/2008/12/stone_balancing_01.jpg" alt="" /><img class="alignright size-full wp-image-182" title="stone_balancing_02" src="http://www.ostinelli.net/wp-content/uploads/2008/12/stone_balancing_02.jpg" alt="" /><br />
<img class="alignnone size-full wp-image-182" title="stone_balancing_03" src="http://www.ostinelli.net/wp-content/uploads/2008/12/stone_balancing_03.jpg" alt="" /><br />
<img class="alignleft size-full wp-image-182" title="stone_balancing_04" src="http://www.ostinelli.net/wp-content/uploads/2008/12/stone_balancing_04.jpg" alt="" /></p>
]]></content:encoded>
			<wfw:commentRss>http://www.ostinelli.net/stone-balancing/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>OpenSpime</title>
		<link>http://www.ostinelli.net/openspime/</link>
		<comments>http://www.ostinelli.net/openspime/#comments</comments>
		<pubDate>Tue, 10 Jun 2008 17:04:13 +0000</pubDate>
		<dc:creator>Roberto Ostinelli</dc:creator>
				<category><![CDATA[Main]]></category>
		<category><![CDATA[Internet Of Things]]></category>
		<category><![CDATA[IoT]]></category>
		<category><![CDATA[OpenSpime]]></category>
		<category><![CDATA[PyOpenSpime]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://www.ostinelli.net/?p=228</guid>
		<description><![CDATA[OpenSpime is a protocol, an open XMPP custom extension enabling physical devices to communicate. It has been written with the Internet of Things in mind. A Technical Introduction to OpenSpime OpenSpime Buzz The whole buzz started when the following video was presented. One of the first persons to blog about this was Bruce Sterling in [...]]]></description>
			<content:encoded><![CDATA[<p>OpenSpime is a protocol, an open <a href="http://www.xmpp.org">XMPP</a> custom extension enabling physical devices to communicate. It has been written with the <a href="http://en.wikipedia.org/wiki/Internet_of_Things">Internet of Things</a> in mind.</p>
<h3>A Technical Introduction to OpenSpime</h3>
<p><object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/j4Q_qpCrkIc&#038;hl=en&#038;fs=1"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/j4Q_qpCrkIc&#038;hl=en&#038;fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed></object></p>
<h3>OpenSpime Buzz</h3>
<p>The whole buzz started when the following video was presented. One of the first persons to blog about this was Bruce Sterling in his blog on Wired, <a href="http://blog.wired.com/sterling/2008/03/spime-watch-the.html">Beyond the Beyond</a>, but OpenSpime has had a worldwide coverage since then (<a href="http://itc.conversationsnetwork.org/shows/detail3587.html">IT Conversations</a>, <a href="http://blogs.cisco.com/virtualworlds/comments/designing_the_shape_of_space_time/">Cisco&#8217;s blogs</a>, <a href="http://www.lunchoverip.com/2008/03/openspimes-turn.html">Lunch Over IP</a>, and <a href=http://www.ugotrade.com/2008/03/03/openspime-instrumentation-for-the-planet/">Ugotrade</a> amongst others).</p>
<p><object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/xmiG2MzPMnA&#038;hl=en&#038;fs=1"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/xmiG2MzPMnA&#038;hl=en&#038;fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed></object></p>
<h3>OpenSpime Developer Network</h3>
<p>Together with Davide &#8216;Folletto&#8217; Casali, I&#8217;ve written a python library called <a href='http://code.google.com/p/pyopenspime/'>PyOpenSpime</a> which will easily get you started to OpenSpime.</p>
<p>If you are feeling curious, you may consider joining the <a href="http://developer.openspime.com">OpenSpime Developer Network</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ostinelli.net/openspime/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>The Composite Intelligence of Virtual Assistants</title>
		<link>http://www.ostinelli.net/the-composite-intelligence-of-virtual-assistants/</link>
		<comments>http://www.ostinelli.net/the-composite-intelligence-of-virtual-assistants/#comments</comments>
		<pubDate>Wed, 10 Oct 2007 14:32:49 +0000</pubDate>
		<dc:creator>Roberto Ostinelli</dc:creator>
				<category><![CDATA[Main]]></category>
		<category><![CDATA[composite intelligence]]></category>
		<category><![CDATA[software intelligence]]></category>
		<category><![CDATA[user experience]]></category>
		<category><![CDATA[virtual assistants]]></category>

		<guid isPermaLink="false">http://www.ostinelli.net/?p=146</guid>
		<description><![CDATA[I have been involved for some time into realizing Intelligent Virtual Assistants that target business applications. Here&#8217;s a concept application that was presented by our team at the Savio Event in London, which clarifies a possible use of virtual assistants in a business environment. As you will see, these scarcely qualify as mere &#8216;talking heads&#8217;. [...]]]></description>
			<content:encoded><![CDATA[<p>I have been involved for some time into realizing Intelligent Virtual Assistants that target business applications. </p>
<p>Here&#8217;s a concept application that was presented by our team at the Savio Event in London, which clarifies a possible use of virtual assistants in a business environment. As you will see, these scarcely qualify as mere &#8216;talking heads&#8217;.</p>
<p><object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="437" height="363" id="viddler"><param name="movie" value="http://www.viddler.com/player/e3407b52/" /><param name="allowScriptAccess" value="always" /><param name="allowFullScreen" value="true" /><param name="wmode" value="transparent"/><embed src="http://www.viddler.com/player/e3407b52/" width="437" height="363" type="application/x-shockwave-flash" allowScriptAccess="always" allowFullScreen="true" wmode="transparent" name="viddler" ></embed></object></p>
<p>My opinions regarding how to approach the realization of such applications is outlined in the following article, originally published on <a href="http://www.uxmatters.com/MT/archives/000224.php">UXmatters</a>.</p>
<hr />
<h3>The Composite Intelligence of Virtual Assistants</h3>
<p>As early as 1968, influenced by visionary movies such as Stanley Kubrick’s <em>2001: A Space Odyssey</em>, with its fictional computer character <strong>HAL 9000</strong>, we envisioned <strong>omniscient</strong>, <strong>intelligent </strong>machines that could easily contain the whole range of human knowledge. Then, in 1987, the <a href="http://www.youtube.com/watch?v=HGYFEI6uLy0">Knowledge Navigator video</a> from Apple Computer struck our imaginations and greatly boosted our expectations of what computers would be able to do for us in a few years’ time.</p>
<p>It is now 20 years later, but technology is still very far from fulfilling such hopes regarding virtual assistants:</p>
<ul>
<li><strong>Voice recognition</strong> isn’t immediate.</li>
<li>People adapt to <strong>machines’ lexicons</strong> rather than the other way around.</li>
<li>Computers cannot easily transcend the <strong>scope </strong>for which they have been programmed.</li>
<li><strong>Self-learning machines</strong> are still experimental.</li>
<li>The generation of high-quality graphics representing emotionally rich, <strong>3-D avatars</strong> is far from being real time, cheap, or extensively available.</li>
</ul>
<p><strong>The technology</strong> for fulfilling such high expectations simply <strong>does not yet exist</strong>. However, while we wait for technology to catch up with our dreams, the gap between our expectations and the reality of what we can now achieve has inspired two important trends in the development of virtual assistants:</p>
<ul>
<li>simulation of <strong>generic </strong>conversations</li>
<li><strong>application-specific</strong> virtual assistants</li>
</ul>
<h3>From the Generic to the Application Specific</h3>
<p>Unfortunately, the first approach—a computer that can simulate a generic conversation with a real person—remains an <strong>unrealized dream</strong>. However, a series of intelligence-simulation experiments has culminated in the <a href="http://www.loebner.net/Prizef/loebner-prize.html">Loebner Prize in Artificial Intelligence</a>—“the first formal instantiation of a <strong>Turing Test</strong>,” which demonstrates a computer’s intelligence and would award a gold medal and a $100,000 prize “for the first computer whose responses were indistinguishable from a human’s.” Every year, Hugh Loebner awards a bronze medal to the computer software that best simulates a generic conversation with a real person. Interestingly, Marvin Minsky, co-founder of MIT’s Artificial Intelligence (AI) Laboratory and author of several texts on AI, is one of the strongest critics of the Loebner Prize. He has even provocatively offered a <a href="http://www.loebner.net/Prizef/minsky.html">monetary reward</a> to anyone who can successfully convince Loebner to revoke his prize.</p>
<p>On the other hand, virtual assistant applications are moving toward becoming <strong>application specific</strong>, with the aim of responding appropriately to specific users’ needs by providing precise and relevant information.</p>
<p>While the Turing Test approach might offer the fastest results in successfully simulating generic human conversations, in reality, these simulations are often nothing more than escamotages, or sleights of hand, and are not able to achieve a <strong>real understanding</strong> of users’ ideas. Such experiments concentrate on the use of various tricks to make users believe a virtual assistant has understood them, while in reality, it is more about</p>
<ul>
<li>turning users’ questions back on them—as a <strong>psychiatrist </strong>would do, for instance</li>
<li>suddenly changing the <strong>mood </strong>of the virtual assistant to surprise—covering the fact that it simply hadn’t understood the user’s input in the first place</li>
<li>switching the <strong>topic of conversation</strong> to one the application can handle better—by pretending not to be interested in what a user has said</li>
<li>building <strong>strong characters</strong> that tend to impose their will—thus getting control of the flow of a conversation to ensure it remains on safe ground</li>
</ul>
<p>On the other hand, the second approach—application-specific virtual assistants—is a more slowly evolving process that would require considerable investment and the use of diverse software technologies. However, its aim is to try to build applications that actually can have a <strong>real understanding of users’ input</strong>. Circumscribing an application’s context simplifies the understanding of users’ needs, thus reducing the amount of intelligence it needs to understand and communicate effectively. This has the double effect of <strong>reducing technology requirements</strong> to a level we can realistically attempt and <strong>increasing the level of specialization</strong> each virtual assistant can achieve. We can concentrate all our efforts on an application’s main purpose rather than trying to support the broad knowledge that responding to generic conversations would require. Since, in comparison to the wide open context of the first approach, this approach limits an application’s context much more, it is generally <strong>less appealing</strong> to users’ imaginations, while at the same time, being much <strong>more effective</strong> in responding to users’ requests.</p>
<p>While the tricks inherent in the first approach are definitely worth considering, with their goal of increasing the level of human-like interaction virtual assistant applications can offer, I believe only the second approach enables us to build applications that really meet users’ needs. Typically, users rather quickly become accustomed to a virtual assistant, but get annoyed by any useless chatter, so the ability to carry on a generic conversation might not be desirable anyway. Also, the goal of the second approach is to build <strong>business applications</strong>, so in my opinion, this will be the approach that leads us down the path toward intelligent virtual assistants.</p>
<h3>The Intelligence of Software</h3>
<p>What we mean by <em>intelligent virtual assistants</em> often points directly to our definition of <em>artificial intelligence</em>. Each of us has some perception of what AI is, but if we try to unambiguously define it, we will rapidly fall into a series of borderless conceptions that bounce from science <strong>fiction reminiscences</strong>—the ability of the HAL 9000 to perceive the emotions of its interlocutors and understand <em>all</em> of their requests—to pragmatic requirements—machines that can automate tasks requiring complex decisions—to cutting-edge technologies—self-learning machines—or to your impressions the first time you ever saw a computer providing an answer to a query of yours. So, as you can see, it is more a matter of people’s perception of what intelligence really is. When an AI application actually succeeds, it is common to hear comments like “It was not that hard after all,” or “It’s not real AI anyway.” According to AI pioneer Raymond Kurzweil, such responses are inherent in the nature of AI itself. As he said in a <a href="http://news.com.com/2008-1082-254344.html">c|net interview</a>:</p>
<p>&#8220;It turns out to be easy to replicate most adult achievements, like playing chess or guiding cruse missiles, etcetera. At least a lot of them we can replicate in machines. Every time a machine does that, it’s the nature of artificial intelligence to say, “Well, that wasn’t very difficult after all.” The hard things are what children do, recognizing parents or playing with a dog.&#8221;</p>
<p>You can easily imagine, therefore, why the definition of artificial intelligence has been cause for discussion for decades now.</p>
<p>However, it is <em>not</em> the purpose of this article to discuss <em>what</em> artificial intelligence is or how we can emulate human intelligence. Rather, my intent is to understand <em>how</em> virtual assistants can <em>approach</em> intelligence—strictly from a <strong>pragmatic </strong>point of view.</p>
<p>Since software is the primary factor in making a machine act intelligently, I prefer to use the term <strong><em>software intelligence</em></strong> instead of <em>artificial intelligence</em>. This avoids people’s being misled by the expectations surrounding the latter and allows us to concentrate on the practical considerations that are involved in the creation of intelligent virtual assistants.</p>
<p>I have grouped the software intelligence we need to build virtual assistants into five different levels of intelligence, which together compose an intelligence users perceive as a monolithic, composite intelligence, within the context of their experience (thus, the use of the term <em>composite intelligence</em> in this article’s title). The five levels of software intelligence are:</p>
<ul>
<li><strong>input </strong>intelligence</li>
<li><strong>emotional </strong>intelligence</li>
<li><strong>logical </strong>intelligence</li>
<li><strong>knowledge </strong>intelligence</li>
<li><strong>output </strong>intelligence</li>
</ul>
<p><strong>Input Intelligence</strong></p>
<p>There are numerous input devices that enable a user to input his requests to a virtual assistant—for instance, keyboards, touch screens, microphones, even motion capture systems. Various types of <em>input intelligence</em>—the first level of software intelligence—enable a virtual assistant to immediately interpret such inputs. Some examples include the following:</p>
<ul>
<li><strong>semantic intelligence</strong>—A semantic engine can immediately parse the text a user enters via a keyboard and identify the user’s needs by disambiguating the semantic meaning of the user’s words, thus avoiding the misinterpretation of ambiguous requests.</li>
<li><strong>voice-recognition intelligence</strong>—Software can interpret the speed or change of tone in a user’s speech as emotional values that the other levels of intelligence can then use to more properly adapt to the user’s requests. Thus, voice recognition encompasses not only the ability to capture our words as we speak, but the intelligence enabling the software to perceive and interpret changes in speed and tone.</li>
<li><strong>facial-recognition intelligence</strong>—Software can also perceive a user smiling and interpret a smile as an emotional value that the other levels of intelligence can use.</li>
</ul>
<p>Input intelligence is, therefore, able to add a lot of <strong>metadata </strong>to the software’s understanding of a user’s intended inputs—the kinds of metadata that typically enhance human conversations.</p>
<p><strong>Emotional Intelligence</strong></p>
<p>Input intelligence can understand both a user’s actual communications and the metadata relating to a user’s requests, which have <strong>intrinsic emotional value</strong> that emotional intelligence can interpret. For example, if a user angrily shook his arms while pronouncing the sentence “Yeah, you helped me alright,” emotional intelligence would correctly disambiguate the sentence. Rather than perceiving the remark to be of a positive and satisfied nature, which the user’s words alone would suggest, it would understand that, in reality, the user is unsatisfied with his experience.</p>
<p>Moreover, by keeping <strong>track </strong>of a discussion’s evolution, software with emotional intelligence would gain a better understanding of the overall direction in which the dialogue was going—whether satisfying or dissatisfying to a user. Finally, emotional intelligence can also <strong>communicate </strong>a virtual assistant’s emotional status, which sets the ground for a more human-like type of interaction.</p>
<p>Thus, <em>emotional intelligence</em> can disambiguate mixed input signals, while providing an emotional dimension to the user experience by tracking the emotional status of both the user and the virtual assistant.</p>
<p><strong>Logical Intelligence</strong></p>
<p>The software that provides logical intelligence evaluates <em>all</em> available information and analyzes a user’s requests. It then continues the flow of the discussion by providing the virtual assistant’s <strong>next comment or question</strong>, or the <strong>answer </strong>to the user’s query, if it has already gathered all required information from the user.</p>
<p><em>Logical intelligence</em> comprises the set of technologies that a virtual assistant uses to perform the necessary troubleshooting operations and manage the flow of discussion—such as rule-based engines, case-based reasoning, and bayesian or neural networks.</p>
<p><strong>Knowledge Intelligence</strong></p>
<p>While logical intelligence performs the core tasks of troubleshooting and managing dialogue, it often needs to rely upon data to successfully perform such tasks. It is not enough to merely analyze a user’s needs and identify the related solution. It is of utmost importance that the data a virtual assistant gathers from its knowledge bases matches the information the logical intelligence requests.</p>
<p>For example, if the logical intelligence has identified that a user wants to know about Polish furniture—that is,  furniture manufactured in Poland—if the knowledge base were to reply with information on how to polish furniture—that is, clean it—it would have indeed failed to provide an intelligent response to the user’s query. In this case, the integration of a semantic search solution with the logical intelligence would have instead provided the correct information.</p>
<p><em>Knowledge intelligence</em> lets a virtual assistant <strong>correctly gather data from knowledge bases</strong>. Not every interaction requires knowledge intelligence be consulted. For example, a single user input might be just a greeting, which logic intelligence alone could handle very well.</p>
<p><strong>Output Intelligence</strong></p>
<p><em>Output intelligence</em> determines how a virtual assistant <strong>presents its response</strong> to a user’s request. It has at its disposal both the information the logical intelligence generated and that which the knowledge intelligence ultimately gathered. This information might be something the virtual assistant should say, but also might relate to documents or videos the user should view. Output intelligence also knows the emotional status of both the user and the virtual assistant.</p>
<p>Therefore, output intelligence integrates <em>every</em> bit of information and metadata that the other levels of software intelligence have computed, in order to build the best possible representation of the information. This includes graphic representations of facial expressions and gestures, voice patterns—which might reflect, for instance, the rush a user is in or the emotional status of the virtual assistant—and all of the interface design issues relating to the optimization of this representation.</p>
<h3>Using Software Intelligence</h3>
<p>Attentive readers will already have figured out that these five levels of software intelligence occur <strong>sequentially</strong>. The progressive elaboration on a user’s input becomes enriched through the successive steps, until the software intelligence finds the data that matches the information the user has requested and presents it to the user. All <em>necessary </em>levels of intelligence process every user request, to progressively identify what data the user is asking for. It is a process of <em>input targeting</em>, which relates to identifying and disambiguating a user’s requests, while gradually performing a process of <em>output targeting</em>, or computing the emotional and informational response that the software presents to satisfy a user’s request.</p>
<p>These five levels of software intelligence can, in my opinion, make the dream of virtual assistants a reality. Collectively, they make up the concept of <em>composite intelligence</em>, which comprises various software components—each gifted with some moderate degree of intelligence. Under the appropriate creative and technological conditions, this composite intelligence could provide a <strong>coherent solution</strong> that enables a degree of intelligence that might even be superior to the sum of its components. To fulfill the potential of such a solution, the individual components require a means of communication—including a common communications <strong>protocol</strong>—that can optimize and boost their overall performance.</p>
<p>Hopefully, my attempt to classify the software components that together support the perceived intelligence of virtual assistants contributes to the development of an understanding of the diverse professional domains the realization of such applications touches. Most people can readily understand and accept that software that can compute and rationally respond to a user’s requests is a vital part of the composition of a virtual assistant. However, it rapidly becomes apparent that we can achieve this capability only by first deeply understanding the nature of a user’s needs by</p>
<ul>
<li>using a <strong>combination </strong>of input technologies and emotional algorithms</li>
<li>ensuring the appropriate <strong>integration </strong>of technology and data sources</li>
<li>providing a <strong>rich user experience</strong> that gives users an overall feeling of confidence in virtual assistants</li>
</ul>
<p>Ultimately, if we can achieve all of this, users will gain the necessary degree of familiarity with virtual assistants that will, in the end, open their minds to letting virtual assistants meet their needs.</p>
<p><em>Originally published on <a href="http://www.uxmatters.com/MT/archives/000224.php" target="_blank">UXmatters</a>, October 8th, 2007.</em></p>
]]></content:encoded>
			<wfw:commentRss>http://www.ostinelli.net/the-composite-intelligence-of-virtual-assistants/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>The Incommunication Series</title>
		<link>http://www.ostinelli.net/the-incommunication-series/</link>
		<comments>http://www.ostinelli.net/the-incommunication-series/#comments</comments>
		<pubDate>Mon, 10 Sep 2007 14:02:45 +0000</pubDate>
		<dc:creator>Roberto Ostinelli</dc:creator>
				<category><![CDATA[Main]]></category>
		<category><![CDATA[Incommunication]]></category>
		<category><![CDATA[photo]]></category>

		<guid isPermaLink="false">http://www.ostinelli.net/?p=109</guid>
		<description><![CDATA[Is anybody speaking your same language?]]></description>
			<content:encoded><![CDATA[<p>Is anybody speaking your same language?</p>
<p><img src="http://www.ostinelli.net/wp-content/uploads/2008/12/incommunication_01.jpg" alt="" title="incommunication_01" class="alignleft size-full wp-image-111" /><img src="http://www.ostinelli.net/wp-content/uploads/2008/12/incommunication_02.jpg" alt="" title="incommunication_02" class="alignleft size-full wp-image-111" /><br />
<img src="http://www.ostinelli.net/wp-content/uploads/2008/12/incommunication_03.jpg" alt="" title="incommunication_03" class="alignnone size-full wp-image-111" /></p>
]]></content:encoded>
			<wfw:commentRss>http://www.ostinelli.net/the-incommunication-series/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>PhotoShakr</title>
		<link>http://www.ostinelli.net/photoshakr/</link>
		<comments>http://www.ostinelli.net/photoshakr/#comments</comments>
		<pubDate>Tue, 10 Oct 2006 16:37:26 +0000</pubDate>
		<dc:creator>Roberto Ostinelli</dc:creator>
				<category><![CDATA[Main]]></category>
		<category><![CDATA[photo]]></category>
		<category><![CDATA[PhotoShakr]]></category>
		<category><![CDATA[widget]]></category>

		<guid isPermaLink="false">http://www.ostinelli.net/?p=213</guid>
		<description><![CDATA[PhotoShakr is a widget to display your Flickr sets in a fun way, realized by Leandro &#8216;Leeander&#8217; Agrò, Davide &#8216;Folletto&#8217; Casali and Dario &#8216;CribbioMicio&#8217; Violi. Trailer Here is the audio trailer i did for this project :) PhotoShakr Demo Check out the example below, directly from a leeander Flickr set.]]></description>
			<content:encoded><![CDATA[<p>PhotoShakr is a widget to display your Flickr sets in a fun way, realized by <a href="http://www.leeander.com/">Leandro &#8216;Leeander&#8217; Agrò</a>, <a href="http://www.digitalhymn.com/">Davide &#8216;Folletto&#8217; Casali</a> and <a href="http://dariovioli.it/">Dario &#8216;CribbioMicio&#8217; Violi</a>.</p>
<h3>Trailer</h3>
<p>Here is the audio trailer i did for this project :)</p>
<p></p>
<h3>PhotoShakr Demo</h3>
<p>Check out the example below, directly from a <a href="http://www.leeander.com">leeander</a> Flickr set.</p>
<p><!-- \/ PhotoShakr --><br />
<embed style="width:720px; height:480px;" id="PhotoShakr-8a54d07c9140fbabd5f100e9674cd98e" type="application/x-shockwave-flash" src="http://photoshakr.com/vaskr/vaskr.swf?set=72157594392715083&#038;basecolor=%23999966" flashvars=""> </embed><br />
<!-- /\ PhotoShakr --></p>
]]></content:encoded>
			<wfw:commentRss>http://www.ostinelli.net/photoshakr/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

