<?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-8897180777295067814</id><updated>2012-01-02T06:30:02.026-08:00</updated><category term='Haskell'/><category term='Scala'/><category term='bugs'/><category term='bokeh'/><category term='programming'/><category term='Closures'/><category term='Benchmark'/><category term='Photography'/><category term='MapExplorer'/><category term='testing'/><category term='multithreaded'/><category term='Loongson'/><category term='JavaScript'/><category term='Java'/><category term='Android'/><category term='Oracle'/><title type='text'>about:random</title><subtitle type='html'>Thoughts about programming, photography, and sometimes life</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://bokesan.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8897180777295067814/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://bokesan.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Christoph Breitkopf</name><uri>https://profiles.google.com/112823570007766118485</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-nsRxuSQuGfY/AAAAAAAAAAI/AAAAAAAAADo/-1nxb5bWdaw/s512-c/photo.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>18</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8897180777295067814.post-5343722284078416322</id><published>2012-01-02T06:29:00.000-08:00</published><updated>2012-01-02T06:30:02.032-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Haskell'/><title type='text'>Haskell Interval Maps</title><content type='html'>I just released my first package on Hackage: a library similar to &lt;b&gt;Data.Map&lt;/b&gt;, but taking intervals as keys and allowing efficient search for all keys containing a point or contained in an interval, for example.&lt;br /&gt;
&lt;br /&gt;
I needed a data structure - in Java - to search in a set of overlapping appointments, that is, intervals of timestamps. I found nothing suitable on the web, and so I started to implement it on my own. Wikipedia yielded augmented search trees as the basic idea. I often use Haskell for prototyping&amp;nbsp;stuff I'll eventually have to implement in Java, C, or whatever.&lt;br /&gt;
&lt;br /&gt;
After that I had a leftover Haskell implementation, and thought that completing it might be a good project&amp;nbsp;to get a bit more into Haskell again. I've been following Haskell for a long time (since before there were type classes, actually), but never used it for larger projects, and I've not kept up with recent developments.&lt;br /&gt;
&lt;br /&gt;
I used &lt;a href="http://www.haskell.org/haskellwiki/How_to_write_a_Haskell_program"&gt;How to Write a Haskell Program&lt;/a&gt;&amp;nbsp;as a guideline.&lt;br /&gt;
&lt;br /&gt;
The first thing to do was to implement a reasonably full-featured interface.&amp;nbsp;&lt;b&gt;Data.Map&lt;/b&gt; was the obvious guideline to use, and I was dismayed by the number of functions it offers.&amp;nbsp;It really seems a bit too rich. It's certainly nice to have all these functions, but on the other hand&amp;nbsp;the pure mass of them also makes it harder to use the library (now, which function should I use...) and&amp;nbsp;to read code using it. In the end I did implement most of them, but it was really a tough decision&amp;nbsp;not to go for a leaner interface.&lt;br /&gt;
&lt;br /&gt;
Next step was going for better test coverage. QuickCheck is great, so that did not take too long&amp;nbsp;(but my test code looks ugly and could use some refactoring). What did take much longer was fixing the&amp;nbsp;bugs this uncovered, especially in the delete... functions.&lt;br /&gt;
&lt;br /&gt;
Next was the standard Haskell build system: cabal. This also took some time. Despite the good user manual, I still had trouble with many aspects. For starts: which version of &lt;b&gt;base&lt;/b&gt; do I need? To my surprise,&amp;nbsp;I did not find reasonable documentation about this anywhere. Integrating the tests was also a bit tricky.&lt;br /&gt;
&lt;br /&gt;
I also wrote some performance tests using&amp;nbsp;&lt;a href="http://hackage.haskell.org/package/criterion"&gt;criterion&lt;/a&gt;,&amp;nbsp;but found that the results are very unreliable on my system. But at least I was able to see that the performance was reasonably close to Data.Map for the basic functions, and that fromDistinctAscList seemed indeed to be linear.&lt;br /&gt;
&lt;br /&gt;
Here's the projects home page: &lt;a href="http://www.chr-breitkopf.de/comp/IntervalMap/"&gt;http://www.chr-breitkopf.de/comp/IntervalMap/&lt;/a&gt;&lt;br /&gt;
Hackage:&amp;nbsp;&lt;a href="http://hackage.haskell.org/package/IntervalMap-0.2.0"&gt;http://hackage.haskell.org/package/IntervalMap-0.2.0&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8897180777295067814-5343722284078416322?l=bokesan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://bokesan.blogspot.com/feeds/5343722284078416322/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://bokesan.blogspot.com/2012/01/haskell-interval-maps.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8897180777295067814/posts/default/5343722284078416322'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8897180777295067814/posts/default/5343722284078416322'/><link rel='alternate' type='text/html' href='http://bokesan.blogspot.com/2012/01/haskell-interval-maps.html' title='Haskell Interval Maps'/><author><name>Christoph Breitkopf</name><uri>https://profiles.google.com/112823570007766118485</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-nsRxuSQuGfY/AAAAAAAAAAI/AAAAAAAAADo/-1nxb5bWdaw/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8897180777295067814.post-6003956408659675637</id><published>2011-09-28T01:05:00.000-07:00</published><updated>2011-09-28T01:05:26.653-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Bitten by Implicits</title><content type='html'>I just wasted half a day tracking down a &lt;code&gt;NullPointerException&lt;/code&gt; in a mixed Scala/Java project.&lt;br /&gt;
&lt;br /&gt;
The original problem was a NPE iterating through a list returned by a java method:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;    import scala.collection.JavaConversions._

    for (x &amp;lt;- javaMethod())
       ...
&lt;/pre&gt;&lt;br /&gt;
I found the reason quickly enough: the java method was still null-infected - it&amp;nbsp;returned &lt;code&gt;null&lt;/code&gt; instead of the empty list when no results were found.&lt;br /&gt;
I was in a bit of a hurry, so instead of refactoring the Java method, I went though a helper:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;for (x &amp;lt;- fixNull(javaMethod()))
       ...

    def fixNull(xs: Iterable[String]): Iterable[String] = {
        if (xs == null) Nil else xs
    }
&lt;/pre&gt;&lt;br /&gt;
To my utter astonishment, this did not fix the NPE. The reason is probably obvious to more seasoned scala programmers, but took me quite some time to see. Actually, after some futile debugging experiments, I just gave up and went home. Quite typically, the critical insight came 5 minutes after leaving the office. Work is just not conductive to creative thinking :-)&lt;br /&gt;
&lt;br /&gt;
Actually, this is a type problem. &lt;code&gt;javaMethod&lt;/code&gt; returns a &lt;code&gt;java.util.List[String]&lt;/code&gt;, but &lt;code&gt;fixNulls&lt;/code&gt; wants a Scala &lt;code&gt;Iterable&lt;/code&gt;. So the Scala compiler inserts an implict conversion from &lt;code&gt;JavaConversions&lt;/code&gt;. Unfortunately, the conversion wraps a returned &lt;code&gt;null&lt;/code&gt; into an object, so &lt;code&gt;xs == null&lt;/code&gt; always returns false!&lt;br /&gt;
&lt;br /&gt;
Changing the argument type fixes the problem:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;    def fixNull(xs: java.util.List[String]): Iterable[String] = ...
&lt;/pre&gt;&lt;br /&gt;
I think that this would have been easier to find if the JavaConversions wrappers would throw a NPE when asked to wrap a &lt;code&gt;null&lt;/code&gt;. Then the problem would have been obvious from the stack trace.&lt;br /&gt;
&lt;br /&gt;
For me, that is another example why having "invisible" things in your code is problematic. Scala implicits can be extremely helpful, but you must be aware of them when debugging.&lt;br /&gt;
&lt;br /&gt;
Of course, the best solution is to refactor the Java code to return an empty list instead of &lt;code&gt;null&lt;/code&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8897180777295067814-6003956408659675637?l=bokesan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://bokesan.blogspot.com/feeds/6003956408659675637/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://bokesan.blogspot.com/2011/09/bitten-by-implicits.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8897180777295067814/posts/default/6003956408659675637'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8897180777295067814/posts/default/6003956408659675637'/><link rel='alternate' type='text/html' href='http://bokesan.blogspot.com/2011/09/bitten-by-implicits.html' title='Bitten by Implicits'/><author><name>Christoph Breitkopf</name><uri>https://profiles.google.com/112823570007766118485</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-nsRxuSQuGfY/AAAAAAAAAAI/AAAAAAAAADo/-1nxb5bWdaw/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8897180777295067814.post-7500266836855457901</id><published>2011-08-08T06:30:00.000-07:00</published><updated>2011-08-08T06:30:15.642-07:00</updated><title type='text'>A short-lived misfortune</title><content type='html'>Last night, there was break-in into my employers offices, and some notebooks were stolen, among them my Lemote Yeeloong.&lt;br /&gt;
&lt;p&gt;When the police arrived, they mentioned that some notebooks had been found in a garbage can at a nearby kebab place. They even had a list of models and serial numbers.&lt;br /&gt;
&lt;p&gt;Given that the Lemote is more of a curiosity here in Germany, it was fairly obvious that it was mine even without checking the serial number. I was directed to the appropriate police office, just a few hundred meters away.&lt;br /&gt;
After a short wait, and signing a receipt, I had my notebook back. The battery was empty, but otherwise, not a scratch (and, thankfully, no kebab).&lt;br /&gt;
&lt;p&gt;All in all, it took just about 3 hours from the discovery of the theft, to having the notebook back on my desk. The was some luck involved, but still, I was quite impressed by the effectiveness of the police.&lt;br /&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8897180777295067814-7500266836855457901?l=bokesan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://bokesan.blogspot.com/feeds/7500266836855457901/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://bokesan.blogspot.com/2011/08/short-lived-misfortune.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8897180777295067814/posts/default/7500266836855457901'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8897180777295067814/posts/default/7500266836855457901'/><link rel='alternate' type='text/html' href='http://bokesan.blogspot.com/2011/08/short-lived-misfortune.html' title='A short-lived misfortune'/><author><name>Christoph Breitkopf</name><uri>https://profiles.google.com/112823570007766118485</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-nsRxuSQuGfY/AAAAAAAAAAI/AAAAAAAAADo/-1nxb5bWdaw/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8897180777295067814.post-3627448273294605974</id><published>2011-06-19T17:29:00.000-07:00</published><updated>2011-06-21T23:07:08.500-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>ICFP Programming Contest 2011</title><content type='html'>Whew! Finally over. I liked the task, because of much prior experience with lambda calculus and SK combinators (but not MTG). That didn't help much though - I did not find a way to compose functions until a few hours ago. By then I was too tired to try and implement it. More detailed write-up soon.

&lt;p&gt;
&lt;hr align="center" width="50%" &gt;
Ok, here it goes:

&lt;p&gt;
The contest started at 2:00 in the night, so I decided get a decent sleep and looked at the task only
some 6 hours after the start. I liked the task at first sight: lambda calculus and combinators!
Cool card images, too.

&lt;p&gt;
To be able react to the game state during play, it was necessary to
implement the game mechanics, so I wrote a straightforward implementation
in Haskell.
For the logic, I first wrote code to generate a number in a given slot, using
the &lt;i&gt;zero&lt;/i&gt;, &lt;i&gt;succ&lt;/i&gt;, and &lt;i&gt;dbl&lt;/i&gt; cards. For a start into strategy,
I used that to decrement the opponents slot with
the lowest vitality. Obviously not a winning strategy, but I wasn't ready
to tackle &lt;i&gt;help&lt;/i&gt; and &lt;i&gt;attack&lt;/i&gt; yet.
&lt;p&gt;
Before the submission to the unofficial tournament server, I dutifully tested
the executable on my Debian Squeeze VM. It did not run, because of
shared library problems. So I tried static linking, but to my surprise
discovered that ghc does not support that on Linux :-(
So I had to compile on the Debian VM. A bit of a hassle, but not &lt;i&gt;that&lt;/i&gt; bad.
&lt;p&gt;
I submitted my server, and soon got some "submission failed" problems.
Not too many - about one failure every few games. Some of those were
due to timeouts, so I did some code tuning. I also noted a problem
with the zero card not being converted to a number in some places
(0-ary functions are bad), and fixed those, too.
&lt;p&gt;
After that, I was quite optimistic that my submission would work.
But no such luck - I still got "invalid format" errors.

Lacking a more informative error message, at this point I could only review
all pattern matches that ended with a &lt;code&gt;_ -&gt; error ("can't happen")&lt;/code&gt;
clause, but I did not find the cause of the problem.
&lt;p&gt;
Now, the best resource would probably have been to try harder to reproduce the bug,
but what I did instead (out of desperation, really) was to re-implement
my player in another language: C. This did not take long, and I actually discovered
the mistakes in the Haskell version while coding. As it turns out, being mentally in
"pure mode", I had not faithfully implemented the order of side-effects resulting
from the call-by-value evaluation. Also, there was a problem in my implementation
of the help and attack cards, where I would produce an error if the &lt;var&gt;j&lt;/var&gt; parameter
was not a valid slot number too early, without first decrementing the vitality of
slot &lt;var&gt;i&lt;/var&gt;. While I thought that the actual game logic would be easier
to implement in Haskell, the core of the C version looked much cleaner at that
point, so I continued developing that version. It worked without problems
on the first attempt. Another nice thing was that I could submit statically linked
executables directly from my 32-bit desktop system instead of having to use the 64-bit VM
on my notebook. Nicer for my eyes and back, that is. Even though I allocated
memory for some applications, I did not release it, figuring that 500M go a long way
(with a value struct being 12 bytes in size in 32-bit mode). I could always use
the Boehm GC if necessary.

&lt;p&gt;
At that point is was Saturday evening, and I had made no progress toward
a good game strategy. So I finally sat down with pen and paper, and tried to drag up
my old SKI and lambda-calculus knowledge. That used to be quite good - I still 
have a toy functional language implemented by combinator reduction lying around,
and once knew S, K, I and friends (B, C, B', C' and so on) by heart.
But, as more than one contest participant has noticed, doing the implementation
first and the creative "brain-work" later in the contest is often the wrong order -
by the time you've finished the necessary groundwork and maybe a few tools,
you're likely out of sleep and not in the best frame of mind for creative thinking.

&lt;p&gt;
I was stumped for a long time trying to find a general way to compose functions. That I solved a few hours 
before the contest's end (using slot 0 and K _, S _, _ get, _ zero).

&lt;p&gt; As for strategy, it seemed obvious, that one should use &lt;i&gt;help&lt;/i&gt; to build up vitality
and use that to &lt;i&gt;attack&lt;/i&gt; the opponent. I did not manage to implement such a scheme 
in the remaining time.
&lt;p&gt;
&lt;a href="http://www.chr-breitkopf.de/tmp/bokesan.1.tar.gz"&gt;My submission&lt;/a&gt;.

&lt;p&gt;


&lt;hr align="center" width="50%" &gt;

&lt;b&gt;After the contest&lt;/b&gt;
&lt;p&gt;

Given that I had prior experience with combinators, I was quite frustrated at my bad
performance. 

In retrospect, what has held me up most was, I think, that the contest theme got me in
a pure functional mindset, and I mostly blanked out the side-effects arising from
call-by-value semantics. Combinators just scream "lazy" and "pure" to me, which caused my mind
to ignore the glaringly obvious possibility of executing several vitality-affecting
operations in one action (simple example: _ inc, S _, _ inc, _ zero). That, together with
&lt;i&gt;get&lt;/i&gt; to make copies for later use, would have got me in the right direction for
a better result. That still would not have been a top result, as I doubt that I would
have figured out how to use &lt;i&gt;zombie&lt;/i&gt; effectively, but it would have been into
the "ok" instead of "also running" category. The same problem, thinking pure, was also
responsible for the bugs in my earlier Haskell implementation. So getting that right from
the start would have saved me at least 12 hours of debugging and the C implementation, too.

&lt;p&gt;
I also completely ignored the approach NOT to do a simulation.
Thus, I missed implementing some simple players that would later
have helped me to debug my non-working implementation.

In particular, the echo player, the random Player are absurdly easy to implement and
might have helped in debugging. Also, writing and evaluating a few functions by hand
might have gotten me around my mental "only one side-effect per action" block.

&lt;p&gt;
But as usual, I had much fun and greatly enjoyed the contest. Many thank to the organizers
for the interesting task! I'm looking forward to see all the cool strategies the top contestants
are sure to have devised. In particular, I'm curious what really can be done with &lt;i&gt;zombie&lt;/i&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8897180777295067814-3627448273294605974?l=bokesan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://bokesan.blogspot.com/feeds/3627448273294605974/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://bokesan.blogspot.com/2011/06/icfp-programming-contest-2011.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8897180777295067814/posts/default/3627448273294605974'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8897180777295067814/posts/default/3627448273294605974'/><link rel='alternate' type='text/html' href='http://bokesan.blogspot.com/2011/06/icfp-programming-contest-2011.html' title='ICFP Programming Contest 2011'/><author><name>Christoph Breitkopf</name><uri>https://profiles.google.com/112823570007766118485</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-nsRxuSQuGfY/AAAAAAAAAAI/AAAAAAAAADo/-1nxb5bWdaw/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8897180777295067814.post-553461981913708503</id><published>2011-05-24T08:39:00.000-07:00</published><updated>2011-05-25T08:19:13.415-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Benchmark'/><category scheme='http://www.blogger.com/atom/ns#' term='Loongson'/><title type='text'>Lemote Yeelong Benchmarks</title><content type='html'>A few weeks ago, I got my Lemote Yeeloong netbook.
After a veritable odyssey of OS upgrades / rescues and reinstallations,
caused by stupidity (mine), unfamiliarity with Debian, and unstable to non-existent
connectivity to the Chinese download sites, I was finally able to run some benchmarks.


&lt;p&gt;
According to the
&lt;a href="http://www.loongson.cn/EN/product_info.php?id=34"&gt;Loongson 2F website&lt;/a&gt;, the CPU should
 &lt;i&gt;"Outperform 1GHz Pentium III"&lt;/i&gt;.

&lt;p&gt;
I do not have access to a 1GHz PIII, so I used an Asus EeePc 701 for comparison.
It has an Intel Celeron-M ULV 353 underclocked to 630 MHz. 

Taking 
&lt;a href="http://laptoping.com/intel-atom-benchmark.html"&gt;these SuperPI benchmark results&lt;/a&gt;, which
are probably best case for frequency scaling, would place the CPUs about equal (Pentium III 1 GHz at 130 sec., and Celeron-M 630 MHz at 126 sec.)

&lt;p&gt;
System comparison:
&lt;p&gt;
&lt;table border="1" cellpadding="4" cellspacing="0"&gt;
&lt;tbody&gt;
&lt;tr&gt; &lt;th&gt;System&lt;/th&gt; &lt;th&gt;CPU&lt;/th&gt; &lt;th&gt;MHz&lt;/th&gt; &lt;th&gt;L2 Cache&lt;/th&gt; &lt;th&gt;Memory&lt;/th&gt; &lt;th&gt;OS&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;
     &lt;td&gt;Lemote Yeeloong 8089&lt;/td&gt;
     &lt;td&gt;Loongson 2F&lt;/td&gt;
     &lt;td align="center"&gt;800&lt;/td&gt;
     &lt;td align="center"&gt;512 KB&lt;/td&gt;
     &lt;td align="center"&gt;1 GB&lt;/td&gt;
     &lt;td&gt;Fedora 13&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
     &lt;td&gt;EeePc 701&lt;/td&gt;
     &lt;td&gt;Celeron-M ULV 353&lt;/td&gt;
     &lt;td align="center"&gt;630&lt;/td&gt;
     &lt;td align="center"&gt;512 KB&lt;/td&gt;
     &lt;td align="center"&gt;2 GB&lt;/td&gt;
     &lt;td&gt;Scientific Linux 6&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;
I used Fedora instead of Debian on the Lemote because it uses the MIPS n32 ABI, for potentially much better performance.



&lt;h2&gt;
Stream TRIAD bandwidth&lt;/h2&gt;
Stream results are rather bad:&lt;p&gt;
&lt;table border="1" cellpadding="4" cellspacing="0"&gt;
&lt;tbody&gt;
&lt;tr&gt; &lt;th&gt;System&lt;/th&gt; &lt;th&gt;TRIAD MB/sec&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt; &lt;td&gt;Yeeloong&lt;/td&gt; &lt;td align="center"&gt;601&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt; &lt;td&gt;EeePc&lt;/td&gt; &lt;td align="center"&gt;1220&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

&lt;h2&gt;bzip2 compression&lt;/h2&gt;
As an integer benchmark, I used bzip2 to decompress and compress the
gcc 4.6.0 source tarball (71,579,535 bytes). Time is user time in seconds.
&lt;p&gt;
&lt;table border="1" cellpadding="4" cellspacing="0"&gt;
&lt;tbody&gt;
&lt;tr&gt; &lt;th&gt;System&lt;/th&gt; &lt;th&gt;Decompress&lt;/th&gt; &lt;th&gt;Compress&lt;/th&gt; &lt;th&gt;bzip2 version&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt; &lt;td&gt;Yeeloong&lt;/td&gt; &lt;td align="right"&gt;145.69&lt;/td&gt; &lt;td align="right"&gt;767.74&lt;/td&gt;
     &lt;td&gt;from OS&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt; &lt;td&gt;Yeeloong&lt;/td&gt; &lt;td align="right"&gt;140.90&lt;/td&gt; &lt;td align="right"&gt;521.15&lt;/td&gt;
     &lt;td&gt;bzip 1.0.6, compiled with gcc 4.6.0 with default optimization&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt; &lt;td&gt;EeePc&lt;/td&gt; &lt;td align="right"&gt;114.09&lt;/td&gt; &lt;td align="right"&gt;507.09&lt;/td&gt;
     &lt;td&gt;from OS&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

&lt;h2&gt;Radiance rendering&lt;/h2&gt;
Using &lt;a href="http://markjstock.org/pages/rad_bench.html"&gt;Mark Stock's benchmark test&lt;/a&gt;.
Unfortunately, on the Yeeloong, &lt;code&gt;-O3 -ffast-math&lt;/code&gt; delivered invalid results, so I had to
compile with the flags listed below. I'll try to rerun this with a newer version of gcc, as
this gives a big improvement on some platforms (AMD64, for example, but not on the Celeron-M).
&lt;p&gt;
&lt;table border="1" cellpadding="4" cellspacing="0"&gt;
&lt;tbody&gt;
&lt;tr&gt; &lt;th&gt;System&lt;/th&gt; &lt;th&gt;User time&lt;/th&gt; &lt;th&gt;Compiler&lt;/th&gt; &lt;th&gt;Flags&lt;/th&gt; &lt;/tr&gt;
&lt;tr&gt;
    &lt;td&gt;Yeeloong&lt;/td&gt;
    &lt;td align="right"&gt;17915&lt;/td&gt;
    &lt;td&gt;gcc 4.4.4&lt;/td&gt;
    &lt;td&gt;-march=native -O3 -fno-math-errno -funsafe-math-optimizations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
    &lt;td&gt;EeePc&lt;/td&gt;
    &lt;td align="right"&gt;15884&lt;/td&gt;
    &lt;td&gt;gcc 4.7.0 20110501&lt;/td&gt;
    &lt;td&gt;-march=native -Ofast&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;Hint&lt;/h2&gt;
The systems are almost identical at about 67 MQuips, but, as indicated by the
Stream result, the Loongson is hampered by bad main memory and, apparently, L2 cache, performance.
&lt;a href="http://3.bp.blogspot.com/-0xRz5jZFphk/TdvQUQ5YgaI/AAAAAAAAABo/aSa-F4XjesA/s1600/hint.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://3.bp.blogspot.com/-0xRz5jZFphk/TdvQUQ5YgaI/AAAAAAAAABo/aSa-F4XjesA/s320/hint.png" width="320" /&gt;&lt;/a&gt;

&lt;p&gt;
&lt;hr&gt;
&lt;b&gt;Updates:&lt;/b&gt;&lt;br/&gt;
2011-05-25 updated bzip2 results&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8897180777295067814-553461981913708503?l=bokesan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://bokesan.blogspot.com/feeds/553461981913708503/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://bokesan.blogspot.com/2011/05/lemote-yeelong-benchmarks.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8897180777295067814/posts/default/553461981913708503'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8897180777295067814/posts/default/553461981913708503'/><link rel='alternate' type='text/html' href='http://bokesan.blogspot.com/2011/05/lemote-yeelong-benchmarks.html' title='Lemote Yeelong Benchmarks'/><author><name>Christoph Breitkopf</name><uri>https://profiles.google.com/112823570007766118485</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-nsRxuSQuGfY/AAAAAAAAAAI/AAAAAAAAADo/-1nxb5bWdaw/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-0xRz5jZFphk/TdvQUQ5YgaI/AAAAAAAAABo/aSa-F4XjesA/s72-c/hint.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8897180777295067814.post-7478805285893835671</id><published>2011-05-03T07:27:00.000-07:00</published><updated>2011-05-03T23:00:35.765-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Which JVM for Scala?</title><content type='html'>After noticing that Scala programs usually run much faster with the HotSpot server VM than with
the client VM, I wanted to test a few more VMs and options.

&lt;p&gt;
I used a single small Scala program for testing: a variation of the n-Queens puzzle.
You can download source and jars
&lt;a href="http://www.chr-breitkopf.de/comp/scala-queens.zip"&gt;here&lt;/a&gt;.
Scala version was 2.8.1.final.

&lt;p&gt;
The program was run with default VM options, except for &lt;code&gt;-client&lt;/code&gt; / &lt;code&gt;-server&lt;/code&gt;
(&lt;code&gt;-Xem:client&lt;/code&gt; / &lt;code&gt;-Xem:server&lt;/code&gt; for harmony), e.g.:

&lt;pre&gt;
    &lt;i&gt;jvm&lt;/i&gt;\bin\java -server -cp scala-library.jar;Queens.jar Queens
&lt;/pre&gt;

&lt;p&gt;
The test were run on a Core 2 Duo E8500 (3.16GHz, 6MB L2) in Windows XP 32-Bit.
The runtime is the best time of the three 12 Queens runs, in seconds.
&lt;p&gt;

&lt;table border="1" cellpadding="4" cellspacing="0"&gt;

  &lt;tr&gt;
    &lt;th&gt; opt &lt;/th&gt; &lt;th&gt; default &lt;/th&gt; &lt;th colspan="2"&gt;JVM&lt;/th&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td align="right"&gt;1.32&lt;/td&gt;
    &lt;td align="right"&gt;1.79&lt;/td&gt;
    &lt;td&gt;java7-server&lt;/td&gt;
    &lt;td&gt;Java HotSpot(TM) Server VM (build 21.0-b10, mixed mode)&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td align="right"&gt;1.37&lt;/td&gt;
    &lt;td align="right"&gt;1.83&lt;/td&gt;
    &lt;td&gt;hotspot-server&lt;/td&gt;
    &lt;td&gt;Java HotSpot(TM) Server VM (build 20.0-b11, mixed mode)&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td align="right"&gt;1.95&lt;/td&gt;
    &lt;td align="right"&gt;2.04&lt;/td&gt;
    &lt;td&gt;jrockit-client&lt;/td&gt;
    &lt;td&gt;Oracle JRockit(R) (build R28.1.3-11-141760-1.6.0_24-20110301-1429-windows-ia32, compiled mode)&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td align="right"&gt;2.24&lt;/td&gt;
    &lt;td align="right"&gt;2.25&lt;/td&gt;
    &lt;td&gt;jrockit-server&lt;/td&gt;
    &lt;td&gt;Oracle JRockit(R) (build R28.1.3-11-141760-1.6.0_24-20110301-1429-windows-ia32, compiled mode)&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td align="right"&gt;6.89&lt;/td&gt;
    &lt;td align="right"&gt;&lt;i&gt;6.59&lt;/i&gt;&lt;/td&gt;
    &lt;td&gt;java7-client&lt;/td&gt;
    &lt;td&gt;Java HotSpot(TM) Client VM (build 21.0-b10, mixed mode, sharing)&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td align="right"&gt;6.91&lt;/td&gt;
    &lt;td align="right"&gt;7.34&lt;/td&gt;
    &lt;td&gt;hotspot-client&lt;/td&gt;
    &lt;td&gt;Java HotSpot(TM) Client VM (build 20.0-b11, mixed mode, sharing)&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td align="right"&gt;86.64&lt;/td&gt;
    &lt;td align="right"&gt;crashed&lt;/td&gt;
    &lt;td&gt;harmony-server&lt;/td&gt;
    &lt;td&gt;Apache Harmony DRLVM (1.6.0-r991881)&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td align="right"&gt;92.50&lt;/td&gt;
    &lt;td align="right"&gt;&lt;i&gt;90.60&lt;/i&gt;&lt;/td&gt;
    &lt;td&gt;harmony-client&lt;/td&gt;
    &lt;td&gt;Apache Harmony DRLVM (1.6.0-r991881)&lt;/td&gt;
  &lt;/tr&gt;

&lt;/table&gt;

&lt;p&gt;
So, for best performance, stay with the HotSpot VM, and always use &lt;code&gt;-server&lt;/code&gt;. You probably need to
install a full JDK for this - the JRE only includes the client VM.
&lt;p&gt;
Using the &lt;code&gt;-optimize&lt;/code&gt; flag when compiling seems to be a win, too, but I would try
it on a few more programs before relying on it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8897180777295067814-7478805285893835671?l=bokesan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://bokesan.blogspot.com/feeds/7478805285893835671/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://bokesan.blogspot.com/2011/05/which-jvm-for-scala.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8897180777295067814/posts/default/7478805285893835671'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8897180777295067814/posts/default/7478805285893835671'/><link rel='alternate' type='text/html' href='http://bokesan.blogspot.com/2011/05/which-jvm-for-scala.html' title='Which JVM for Scala?'/><author><name>Christoph Breitkopf</name><uri>https://profiles.google.com/112823570007766118485</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-nsRxuSQuGfY/AAAAAAAAAAI/AAAAAAAAADo/-1nxb5bWdaw/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8897180777295067814.post-8497128799144782908</id><published>2011-04-28T08:38:00.000-07:00</published><updated>2011-04-28T08:38:52.690-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Closures'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Scala and Java</title><content type='html'>I finally decided to write a new module for an existing Java application in Scala.

&lt;p&gt;
There were several reasons to use Scala instead of Java:

&lt;ol&gt;
  &lt;li&gt;Coding speed because of much shorter code.&lt;/li&gt;
  &lt;li&gt;The only way to really learn a language is to use it for a real project&lt;/li&gt;
  &lt;li&gt;I was bored and looking for some excitement :-)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;
The time that I could pick up a new language just by reading a book seem to be gone.
I think (hope!) that the reason is not age or lack of focus, but rather that the languages
have changed.

Say, for example, that you know Java and want to learn C#.
That should be fairly simple - both are object-oriented languages with very similar
syntax and semantics. Actually, even a relatively simple OO language is much more
complex than, say, Pascal. Scala is harder, especially if you've never done functional
programming, but still, the language is the smaller problem.
The big problem are ever-growing libraries and frameworks. You need to become familiar
with at least part of this for any real program. And the libraries are often less well designed
and coherent than the language.

&lt;p&gt;
For me, the downsides of using Scala are mostly in the development environment.
I use Eclipse for Java development and am very happy with it. Not so much
when writing new code - I can do that just fine in Emacs or even a simple text editor.
It's when maintaining and extending a larger codebase written by multiple developers
where the features of a good IDE - for example type-based autocompletion, hovering to see Javadoc comments,
or refactoring - really pay off.
&lt;p&gt;
The sad fact is that I could not get the Scala IDE for Eclipse to work. I tried on two different systems,
even on a older Galileo Eclipse, but to no avail. Sometimes just adding the Scala nature would completely break a java project. And often Eclipse will just hang. And even if it sort of works, no refactorings,
not even rename!

&lt;p&gt;
So I wrote the new module as a separate Scala-only project using Emacs with
scala-mode and &lt;a href="http://ensime.blogspot.com/"&gt;ENSIME&lt;/a&gt;. This worked reasonably well.

&lt;hr align="center" width="30%"&gt;

&lt;p&gt;
After finishing the first version, I asked myself this
question: "Are there just a few features that Java would need so I would not
be tempted to use Scala instead?".

&lt;p&gt;
My first (probably obvious) answer: "Closures".

&lt;p&gt;
Being able to write

&lt;pre&gt;
    gotIt = aList.exists(x =&gt; x.isFoo &amp;&amp; !x.isBar &amp;&amp; x.baz == myBaz)
&lt;/pre&gt;

instead of

&lt;pre&gt;
    gotIt = existsFoo(aList, myBaz);
    ...
    private static boolean existsFoo(Iterable&amp;lt;Thingy&amp;gt; xs, Thingy y) {
        for (Thingy x : xs) {
            if (x.isFoo() &amp;&amp; !x.isBar() &amp;&amp; x.getBaz().equals(y))
                return true;
        }
        return false;
    }
&lt;/pre&gt;

or, using &lt;a href="http://code.google.com/p/guava-libraries/"&gt;Guava&lt;/a&gt;

&lt;pre&gt;
    gotIt = Iterables.any(aList, new Predicate&amp;lt;Thingy&amp;gt;() {
                                      public boolean apply(Thingy x) {
                                          return x.isFoo() &amp;&amp; !x.isBar() &amp;&amp; x.getBaz().equals(myBaz);
                                      }
                                 });
&lt;/pre&gt;
is a huge win.

&lt;p&gt;
In Java with JSR 335 this would look like this (assuming type inference for the lambda argument):

&lt;pre&gt;
    gotIt = Iterable.any(aList, #{ x -&gt; x.isFoo() &amp;&amp; !x.isBar() &amp;&amp; x.getBaz().equals(myBaz) });
&lt;/pre&gt;
&lt;p&gt;
&lt;hr align="center" width="30%"&gt;
&lt;p&gt;
Of course, Scala has a lot more to offer than just closures. I also used implicits to implement
wrappers for so number-like classes, so I can write

&lt;pre&gt;
    if (c &amp;lt; a + b) ...
&lt;/pre&gt;

instead of

&lt;pre&gt;
    if (c.compareTo(a.add(b)) &amp;lt; 0) ...
&lt;/pre&gt;

&lt;p&gt;
List comprehensions (for) also came in handy, as well as pattern matching.
Currying, together with closures makes for unobtrusive and readable resource
cleanup (or closing HTML tags, in my case):

&lt;pre&gt;
    log.in("Foo") {
      ...
    }
&lt;/pre&gt;

instead of

&lt;pre&gt;
    log.openTag("Foo");
    try {
        ...
    } finally {
        log.closeTag("Foo");
    }
&lt;/pre&gt;


&lt;p&gt;

&lt;hr align="center" width="30%"&gt;
&lt;p&gt;
All in all, I probably would not have used Scala if Java had only closures.
But I'm not sorry I did. The code is much shorter and nicer to read than a Java version could ever be.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8897180777295067814-8497128799144782908?l=bokesan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://bokesan.blogspot.com/feeds/8497128799144782908/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://bokesan.blogspot.com/2011/04/scala-and-java.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8897180777295067814/posts/default/8497128799144782908'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8897180777295067814/posts/default/8497128799144782908'/><link rel='alternate' type='text/html' href='http://bokesan.blogspot.com/2011/04/scala-and-java.html' title='Scala and Java'/><author><name>Christoph Breitkopf</name><uri>https://profiles.google.com/112823570007766118485</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-nsRxuSQuGfY/AAAAAAAAAAI/AAAAAAAAADo/-1nxb5bWdaw/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8897180777295067814.post-8704677015922086631</id><published>2011-02-12T04:21:00.000-08:00</published><updated>2011-02-12T04:21:42.083-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Photography'/><title type='text'>Beach after Storm</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/-NCrvgpKAe7w/TVZ6wDSwaqI/AAAAAAAAABg/tT72rEIQsgI/s1600/beach_after_storm.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="296" src="http://1.bp.blogspot.com/-NCrvgpKAe7w/TVZ6wDSwaqI/AAAAAAAAABg/tT72rEIQsgI/s400/beach_after_storm.jpg" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8897180777295067814-8704677015922086631?l=bokesan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://bokesan.blogspot.com/feeds/8704677015922086631/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://bokesan.blogspot.com/2011/02/beach-after-storm.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8897180777295067814/posts/default/8704677015922086631'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8897180777295067814/posts/default/8704677015922086631'/><link rel='alternate' type='text/html' href='http://bokesan.blogspot.com/2011/02/beach-after-storm.html' title='Beach after Storm'/><author><name>Christoph Breitkopf</name><uri>https://profiles.google.com/112823570007766118485</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-nsRxuSQuGfY/AAAAAAAAAAI/AAAAAAAAADo/-1nxb5bWdaw/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-NCrvgpKAe7w/TVZ6wDSwaqI/AAAAAAAAABg/tT72rEIQsgI/s72-c/beach_after_storm.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8897180777295067814.post-4002617226179690180</id><published>2011-01-28T01:10:00.000-08:00</published><updated>2011-01-28T01:12:36.817-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='multithreaded'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Oracle'/><title type='text'>Name my Class, please</title><content type='html'>The bug was hard to reproduce. At least it was obvious that it was
a deadlock issue, because the Oracle said so: 
&lt;tt&gt;ORA-00060: deadlock detected while waiting for resource&lt;/tt&gt;

&lt;p&gt;
Of course, the customers had access to multiprocessor machines
earlier than we developers did. 
So we could not reproduce the problem in-house.

&lt;p&gt;
Once we had access to multiprocessor-machines,
we still were not able to reproduce the problem.
But later, as cores became more abundant, and with real customer data, it would sometimes happen.


&lt;p&gt;
The root cause of the problem was parallel execution of transactions
that did a mixture of updates and inserts on the same table and possible
the same primary key.

&lt;p&gt;
To prevent this error, two approaches seemed possible to me:

&lt;ul&gt;
  &lt;li&gt;  Switch Oracle to &lt;em&gt;Serializable&lt;/em&gt; isolation level and retry the transactions
  in case of &lt;em&gt;Cannot serialize access&lt;/em&gt; errors. &lt;/li&gt;
  &lt;li&gt;Never execute transactions affecting the same primary key in parallel. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
The latter approach seemed to offer higher performance (which was, after all, the reason
to go parallel in the first place), because it would also reduce index block contention.

&lt;p&gt;
So what I did was implement a variant of 
&lt;a href="http://download.oracle.com/javase/6/docs/api/java/util/concurrent/ExecutorService.html"&gt;ExecutorService&lt;/a&gt;
that is given a function
to extract a key from a &lt;tt&gt;Callable&amp;lt;?&amp;gt;&gt;&lt;/tt&gt; object on construction.
It behaves like a fixed thread pool, with the additional constraint that it will never run
tasks with the same key in parallel.

&lt;p&gt;
That was easy enough to implement, at least given my modest scalability requirements, and the rather coarse-grained tasks.
It would probably take rather more time to implement an industrial strength version that would
also offer high performance on very fine-grained tasks and implement the full &lt;tt&gt;ExecutorService&lt;/tt&gt; interface.

&lt;p&gt;
But anyway, it solved the problem, so I'm quite satisfied with this solution. The only
problem is that I've
not been able to come up with a good name. It is currently called &lt;tt&gt;LimitedThreadPool&lt;/tt&gt;.
&lt;tt&gt;RestrictedThreadPool&lt;/tt&gt; was also an option. Both of these names suggest that the
class is a kind of thread pool that is somehow limited or restricted.
But the exact way in which it is restricted - never running certain tasks with the same key in parallel
- is not expressed at all.
&lt;tt&gt;KeySerializedThreadPool&lt;/tt&gt; or &lt;tt&gt;PartlySerializedThreadPool&lt;/tt&gt; seem to go in the right direction,
but I can't say that I'm really satisfied with either of them.


&lt;p&gt;So, if anyone can come up with a better name, please let me know!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8897180777295067814-4002617226179690180?l=bokesan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://bokesan.blogspot.com/feeds/4002617226179690180/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://bokesan.blogspot.com/2011/01/name-my-class-please.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8897180777295067814/posts/default/4002617226179690180'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8897180777295067814/posts/default/4002617226179690180'/><link rel='alternate' type='text/html' href='http://bokesan.blogspot.com/2011/01/name-my-class-please.html' title='Name my Class, please'/><author><name>Christoph Breitkopf</name><uri>https://profiles.google.com/112823570007766118485</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-nsRxuSQuGfY/AAAAAAAAAAI/AAAAAAAAADo/-1nxb5bWdaw/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8897180777295067814.post-8016035255126283377</id><published>2011-01-18T06:27:00.000-08:00</published><updated>2011-01-18T06:27:52.039-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='Benchmark'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Cache sizes visible in JavaScript?</title><content type='html'>Given the recent advances in JavaScript engines, I wanted
to know whether cache effects come into play.
So I wrote a simple
&lt;a href="http://www.chr-breitkopf.de/comp/jsmem/index.html"&gt;memory benchmark&lt;/a&gt;.
Results look interesting at first:
&lt;p&gt;

&lt;img src="http://www.chr-breitkopf.de/comp/jsmem/js_mem.png"
     alt="memory bandwith graph"
     width="526" height="326" /&gt;

&lt;p&gt;From this graph you might guess that my system has 64K L1, 512K L2,
and 6M L3 cache. Which turns out to be correct (Phenom X6).&lt;/p&gt;

&lt;p&gt;So the memory hierarchy &lt;em&gt;is&lt;/em&gt; visible, but if you look at the
absolute numbers (GB/sec), you see that there is less than 10 % difference between
L1 cache and main memory. Plotting the results against the same
benchmark written in Java makes this obvious:&lt;/p&gt;

&lt;img src="http://www.chr-breitkopf.de/comp/jsmem/memperf.png"
     width="491" height="417"
     alt="memory bandwidth Java vs JavaScript" /&gt;

&lt;p&gt;Of course, JavaScript is much harder to optimize than Java.
It has only heterogeneous arrays of values, and only one number type.
&lt;/p&gt;

&lt;p&gt;At the moment, it seems that you can safely ignore locality
in JavaScript. The effect is there, but so small as to be irrelevant,
even in the fastest JavaScript implementations.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8897180777295067814-8016035255126283377?l=bokesan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://bokesan.blogspot.com/feeds/8016035255126283377/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://bokesan.blogspot.com/2011/01/cache-sizes-visible-in-javascript.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8897180777295067814/posts/default/8016035255126283377'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8897180777295067814/posts/default/8016035255126283377'/><link rel='alternate' type='text/html' href='http://bokesan.blogspot.com/2011/01/cache-sizes-visible-in-javascript.html' title='Cache sizes visible in JavaScript?'/><author><name>Christoph Breitkopf</name><uri>https://profiles.google.com/112823570007766118485</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-nsRxuSQuGfY/AAAAAAAAAAI/AAAAAAAAADo/-1nxb5bWdaw/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8897180777295067814.post-1817917069163938645</id><published>2010-12-13T03:36:00.000-08:00</published><updated>2010-12-13T03:36:33.349-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bugs'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Bugs: Let's call it a day</title><content type='html'>A customer reported a bug: Printing a certain report would sometimes crash.
Of course, we could not reproduce it, not even in the customers own environment.
The stack trace was not helpful, either. A conversion from string to number failed,
but we could not see how the string could contain an invalid format.
It took some time digging around the code to find the problem in a module
of utility functions.
&lt;p&gt;
Today, learning a new programming language is usually not that difficult.
It's quite likely that you've already seen most of the concepts in a language you
know.
The trouble is in the libraries and frameworks.
Just knowing whether a certain function might be provided by a library is
not easy. Really getting to know a framework and the way it's supposed to be used
can really take some time.
&lt;p&gt;
Our outsourcing partner in Asia had only done Java projects so far, and our
VB 6 to VB.NET port was their first .NET project.
So it's not surprising that the .NET framework was not as fully used as possible.
&lt;p&gt;
In the case of the bug mentioned above, during development we had reported
that the program did not work in Germany because the localized decimal separator was not used.
Obviously, the framework just has to have some way to access this,
but the programmer was not aware of this, had trouble specifying the right search
terms, or whatever. So instead of just using
&lt;pre&gt;
  CultureInfo.CurrentCulture.NumberFormat.CurrencyDecimalSeparator
&lt;/pre&gt;

he or she implemented this wierd solution: 

&lt;pre&gt;
  If Date.Now.ToString("dddd").Contains("tag") Then
     sep = ","
  Else
     sep = "."
  End If
&lt;/pre&gt;

The programmer must have snarfed up enough German somewhere to think
that German weekday names all end with "tag".
As soon as we saw this code, we set the system date to a Wednesday ("Mittwoch" in German), and promptly
could reproduce the bug.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8897180777295067814-1817917069163938645?l=bokesan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://bokesan.blogspot.com/feeds/1817917069163938645/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://bokesan.blogspot.com/2010/12/bugs-lets-call-it-day.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8897180777295067814/posts/default/1817917069163938645'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8897180777295067814/posts/default/1817917069163938645'/><link rel='alternate' type='text/html' href='http://bokesan.blogspot.com/2010/12/bugs-lets-call-it-day.html' title='Bugs: Let&apos;s call it a day'/><author><name>Christoph Breitkopf</name><uri>https://profiles.google.com/112823570007766118485</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-nsRxuSQuGfY/AAAAAAAAAAI/AAAAAAAAADo/-1nxb5bWdaw/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8897180777295067814.post-3262901810331486242</id><published>2010-08-23T02:24:00.000-07:00</published><updated>2010-08-23T02:24:41.861-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Photography'/><category scheme='http://www.blogger.com/atom/ns#' term='bokeh'/><title type='text'>Bokeh in the Mainstream</title><content type='html'>Only a few years ago, using the term "Bokeh" would get you questioning looks from
most photographers. This has changed by now. Not only do most photographers know
what bokeh means - it's even arrived in the marketing departments. The announcement
of the new version of the Nikkor 1.4/85, is a good example:
Bokeh is mentioned not only in side-notes, but features prominently in several places.
&lt;p&gt;
Of course, whenever marketing's involved, there is the possibility that it's &lt;em&gt;only&lt;/em&gt;
marketing, and there's no way to know if good bokeh was in the actual lens designers requirements.
We'll have to see whether the lens delivers that promise, and in particular,
if it is as good or even better than its immediate predecessor.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8897180777295067814-3262901810331486242?l=bokesan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://bokesan.blogspot.com/feeds/3262901810331486242/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://bokesan.blogspot.com/2010/08/bokeh-in-mainstream.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8897180777295067814/posts/default/3262901810331486242'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8897180777295067814/posts/default/3262901810331486242'/><link rel='alternate' type='text/html' href='http://bokesan.blogspot.com/2010/08/bokeh-in-mainstream.html' title='Bokeh in the Mainstream'/><author><name>Christoph Breitkopf</name><uri>https://profiles.google.com/112823570007766118485</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-nsRxuSQuGfY/AAAAAAAAAAI/AAAAAAAAADo/-1nxb5bWdaw/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8897180777295067814.post-7800559399754064363</id><published>2010-08-10T10:19:00.000-07:00</published><updated>2010-08-10T10:20:56.630-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Scala Microbenchmarks</title><content type='html'>I did some microbenchmarks of scala loops using
&lt;a href="http://code.google.com/p/caliper/"&gt;caliper&lt;/a&gt;.
The goal was to find out just how high the penalty for using higher level
constructs vs imperative-style loops is.
Of course, all the usual caveats about microbenchmarks do apply, so
take the results with a bag of salt.

&lt;p&gt;The microbenchmark I used was counting odd numbers in an array
of integers.
The array was initialized with ascending numbers starting from 0,
that is, numbers(i) = i.

&lt;p&gt;The different ways to count:

&lt;table border="1" cellpadding="4" cellspacing="0"&gt;
  &lt;tr&gt;
   &lt;th&gt;Method&lt;/th&gt; &lt;th&gt;Description&lt;/th&gt; &lt;th&gt;code snippet&lt;/th&gt;
  &lt;/tr&gt;

  &lt;tr valign="top"&gt;
    &lt;td&gt;WhileBits&lt;/td&gt;
    &lt;td&gt;while loop with bitwise op&lt;/td&gt;
    &lt;td&gt;
&lt;pre&gt;
  while (i &amp;lt; n) {
    count += (numbers(i) &amp;amp; 1)
    i += 1
  }&lt;/pre&gt;
    &lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr valign="top"&gt;
    &lt;td&gt;WhileIf&lt;/td&gt;
    &lt;td&gt;while loop with conditional&lt;/td&gt;
    &lt;td&gt;
&lt;pre&gt;
  while (i &amp;lt; n) {
    if ((numbers(i) &amp;amp; 1) != 0) { count += 1 }
    i += 1
  }&lt;/pre&gt;
    &lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr valign="top"&gt;
    &lt;td&gt;ForeachBits&lt;/td&gt;
    &lt;td&gt;iterator&lt;/td&gt;
    &lt;td&gt;
&lt;pre&gt;
  for (i &lt;- numbers) {
    count += (i &amp; 1)
  }&lt;/pre&gt;
    &lt;/td&gt;
  &lt;/tr&gt;


  &lt;tr valign="top"&gt;
    &lt;td&gt;Count&lt;/td&gt;
    &lt;td&gt;count method&lt;/td&gt;
    &lt;td&gt;
&lt;pre&gt;
  numbers.count((n) =&amp;gt; (n &amp;amp; 1) != 0)&lt;/pre&gt;
    &lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr valign="top"&gt;
    &lt;td&gt;Filter&lt;/td&gt;
    &lt;td&gt;filter and length&lt;/td&gt;
    &lt;td&gt;
&lt;pre&gt;
  numbers.filter((n) =&amp;gt; (n &amp;amp; 1) != 0).length&lt;/pre&gt;
    &lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr valign="top"&gt;
    &lt;td&gt;MapSum&lt;/td&gt;
    &lt;td&gt;map and sum using foldLeft&lt;/td&gt;
    &lt;td&gt;
&lt;pre&gt;
  numbers.map((n) =&amp;gt; n &amp;amp; 1).foldLeft(0){(a,b) =&amp;gt; a+b}&lt;/pre&gt;
    &lt;/td&gt;
  &lt;/tr&gt;

&lt;/table&gt;


&lt;p&gt;Here are the results. Scala version was 2.8.0.final. The VM used was Sun HotSpot 1.6.0_20, running on Windows XP 32-bit on a Core 2 8500. Times are in microseconds, but the exact times
are not that important - what matters is the relative speed.&lt;/p&gt;


&lt;table border="1" cellpadding="4" cellspacing="0"&gt;
  &lt;tr&gt;
   &lt;th&gt;Method&lt;/th&gt; &lt;th&gt;client vm&lt;/th&gt; &lt;th&gt;server vm&lt;/th&gt;
  &lt;/tr&gt;

  &lt;tr valign="top" &gt;
    &lt;td&gt;WhileBits&lt;/td&gt;
    &lt;td align="right"&gt;1.92&lt;/td&gt;
    &lt;td align="right"&gt;1.20&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr valign="top"&gt;
    &lt;td&gt;WhileIf&lt;/td&gt;
    &lt;td align="right"&gt;2.54&lt;/td&gt; &lt;td align="right"&gt;2.66&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr valign="top"&gt;
    &lt;td&gt;ForeachBits&lt;/td&gt;
    &lt;td align="right"&gt;29.14&lt;/td&gt; &lt;td align="right"&gt;14.71&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr valign="top"&gt;
    &lt;td&gt;Count&lt;/td&gt;
    &lt;td align="right"&gt;36.96&lt;/td&gt; &lt;td align="right"&gt;24.23&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr valign="top"&gt;
    &lt;td&gt;Filter&lt;/td&gt;
    &lt;td align="right"&gt;50.02&lt;/td&gt; &lt;td align="right"&gt;24.70&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr valign="top"&gt;
    &lt;td&gt;MapSum&lt;/td&gt;
    &lt;td align="right"&gt;97.18&lt;/td&gt; &lt;td align="right"&gt;39.95&lt;/td&gt;
  &lt;/tr&gt;

&lt;/table&gt;

&lt;p&gt;Using the scalac &lt;code&gt;-optimise&lt;/code&gt; flag does almost
nothing for this code (actually, it makes it a bit slower, but not &lt;em&gt;that&lt;/em&gt; much).


&lt;p&gt;&lt;b&gt;My conclusions:&lt;/b&gt;

&lt;ul&gt;
  &lt;li&gt;For inner loops with arithmetic, using low-level code may be a good idea.&lt;/li&gt;
  &lt;li&gt;The performance of the iterator (&lt;em&gt;ForeachBits&lt;/em&gt;) is especially disappointing. I would have expected this to be as fast as the while loop.
  But &lt;code&gt;scalac -print&lt;/code&gt; shows that no kind of optimization or inlining is done.
  &lt;/li&gt;
  &lt;li&gt;Use the server VM, if you can. Typically, this does more for Scala than for Java code. Corollary: Scala performance will be especially bad on simple VMs (Android, for example).&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8897180777295067814-7800559399754064363?l=bokesan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://bokesan.blogspot.com/feeds/7800559399754064363/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://bokesan.blogspot.com/2010/08/scala-microbenchmarks.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8897180777295067814/posts/default/7800559399754064363'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8897180777295067814/posts/default/7800559399754064363'/><link rel='alternate' type='text/html' href='http://bokesan.blogspot.com/2010/08/scala-microbenchmarks.html' title='Scala Microbenchmarks'/><author><name>Christoph Breitkopf</name><uri>https://profiles.google.com/112823570007766118485</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-nsRxuSQuGfY/AAAAAAAAAAI/AAAAAAAAADo/-1nxb5bWdaw/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8897180777295067814.post-7238205362245528455</id><published>2010-07-27T06:08:00.000-07:00</published><updated>2010-07-27T06:11:24.058-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Website Monitoring</title><content type='html'>I recently discovered by accident that a simple Ajax app on my website did not work any more.
Bugs happen, I fixed the bug, and everything's ok again.

&lt;p&gt;
Or is it?

&lt;p&gt;
The problematic words above are "by accident". If I hadn't decided to see how
the site looks on my Android phone, I might not have discovered this at all.

&lt;p&gt;The problem was that the webservice was running under PHP 4 instead of PHP 5, due to
a missing .htaccess file. I did not find out how I deleted that file, but using old
access logs, I found out when: 8 months ago!

&lt;p&gt;
But, why didn't the users complain? In this case, the app hardly had any users,
which explains why I did not get any emails about the site not working.
But relying on your users is of dubious value at best - most won't take the trouble to
email you and will just go elsewhere.

&lt;p&gt;
So, this was a lesson for me: if you care about your websites, you have to monitor them on
a regular basis.

&lt;p&gt;Now the questions is: how? I firmly believe in the rule "If you really want something done,
you have to automate it". So far, my monitoring was "look at the logs from time to time"
(once per week or less often).
I probably would have noticed a major problem on a more popular page, such as
&lt;a href="http://www.bokeh.de/en/index.html"&gt;bokeh.de&lt;/a&gt; this way, the chance for seeing
the problem in the
little-used &lt;a href="http://www.chr-breitkopf.de/mapexplorer-online/index.html"&gt;MapExplorer&lt;/a&gt;
was close to zero. And even if I'd seen it, that still would have been after a week or
more of downtime.

&lt;p&gt;For this particular problem, the webservice itself could have reported it,
if it had better error handling - an exception like the missing (in PHP 4) 
&lt;code&gt;json_encode&lt;/code&gt; function clearly justifies sending a notification
mail, or at least logging a fatal error somewhere. So good error handling is a necessity, too,
but I'll never catch all possible problems, and, more important, it does not
handle the case that my provider has an outage or something like that.

&lt;p&gt;I think that a good solution would be to use a tool like
&lt;a href="http://webtest.canoo.com/webtest/manual/WebTestHome.html"&gt;webtest&lt;/a&gt;
to write automated test for the sites, run that as a daily cron job, and send mail
if something breaks.

&lt;p&gt;I wonder how other people monitor their sites, especially if there is
dynamic content or Ajax apps. Are there any easier ways to do this?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8897180777295067814-7238205362245528455?l=bokesan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://bokesan.blogspot.com/feeds/7238205362245528455/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://bokesan.blogspot.com/2010/07/website-monitoring.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8897180777295067814/posts/default/7238205362245528455'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8897180777295067814/posts/default/7238205362245528455'/><link rel='alternate' type='text/html' href='http://bokesan.blogspot.com/2010/07/website-monitoring.html' title='Website Monitoring'/><author><name>Christoph Breitkopf</name><uri>https://profiles.google.com/112823570007766118485</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-nsRxuSQuGfY/AAAAAAAAAAI/AAAAAAAAADo/-1nxb5bWdaw/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8897180777295067814.post-2175596120893291710</id><published>2010-06-21T01:07:00.000-07:00</published><updated>2010-06-24T02:41:56.330-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>ICFP Contest 2010</title><content type='html'>The contest started on 14:00 local time.
&lt;p&gt;
First thing to do was getting the specifications for
factory circuits.

There were two aspects: gate function, and circuit logic
(what does "backwards" mean?).

&lt;p&gt;
I submitted three trivial factories (1 and 2 gates only) to get
their output, and then did a brute force search for the gate logic
and input stream.

&lt;p&gt;
This was quite unsuccessful, because I started off with the "obvious" 
definition of backwards (topological ordering starting from X gate).

&lt;p&gt;Finally was frustrated enough to look for some hints on the web,
and found another definition of backwards (by gate number), that
I would never have considered. (&lt;i&gt;Is that cheating? I'm divided
on that - hints like that would have been dropped on the official
IRC channels or mailing lists of previous contests, too.
The post that mentioned gate order actually also contained the gate logic,
but I decided not to use that.&lt;/i&gt;)
&lt;p&gt;
With the correct definition of "backwards", finding the gate logic
and input took about 1 hour of brute-force search.

&lt;p&gt;That was my only real achievement in this contest, because
after that I was stumped. I never found a way to construct circuits
by hand.

&lt;p&gt; So again the only thing to try was exhaustive search,
and I found the smallest circuit (6 gates) that would
yield the key prefix after some hours.
By then it was Sunday afternoon.

&lt;p&gt;I did not try very hard to solve the next riddle - 
car and fuel encoding - the parser error messages were not helpful,
and nothing obvious came to mind. So I did not submit any
cars or fuel for other cars.

&lt;p&gt;
Given that I did not get to the main part of the task at all,
it's hard to make a final conclusion about this years contest.
I sucked at it, obviously, but that's nothing new.
What turned me off a bit is that the "riddles" at the start
(circuit/gate semantics and car/fuel encoding) did seem to
require a certain amount of lucky guessing - at least, I'm
not aware of a purely systematic way to solve them.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8897180777295067814-2175596120893291710?l=bokesan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://bokesan.blogspot.com/feeds/2175596120893291710/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://bokesan.blogspot.com/2010/06/icfp-contest-2010.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8897180777295067814/posts/default/2175596120893291710'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8897180777295067814/posts/default/2175596120893291710'/><link rel='alternate' type='text/html' href='http://bokesan.blogspot.com/2010/06/icfp-contest-2010.html' title='ICFP Contest 2010'/><author><name>Christoph Breitkopf</name><uri>https://profiles.google.com/112823570007766118485</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-nsRxuSQuGfY/AAAAAAAAAAI/AAAAAAAAADo/-1nxb5bWdaw/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8897180777295067814.post-2188366286648356525</id><published>2010-06-18T03:26:00.000-07:00</published><updated>2010-06-18T03:26:31.233-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scala'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Why I haven't learned to love Scala yet</title><content type='html'>Scala should be my favorite programming language. It's a natural - everything important
fits: 
&lt;p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Functional:&lt;/strong&gt; can program in functional style without jumping through any hoops&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Static typing:&lt;/strong&gt; powerful type system with just enough automatic inference to not get into the way&lt;/li&gt;
&lt;li&gt;going non-functional for IO, efficiency, or logging/tracing is easy&lt;/li&gt;
&lt;li&gt;runs on JVM&lt;/li&gt;
&lt;li&gt;closely integrated with Java - use all those libraries I may not love but know&lt;/li&gt;
&lt;li&gt;performance is usually good enough&lt;/li&gt;
&lt;/ul&gt;

So why don't I get that warm fuzzy feeling when reading or writing Scala code?
I've tried more than usual for a new language. I even bought the book:
&lt;a href="http://www.artima.com/shop/programming_in_scala"&gt;Programming in Scala&lt;/a&gt;.

&lt;p&gt;

There are probably some more intangible features that don't match
my preferences:

&lt;ul&gt;
&lt;li&gt; syntax seems complicated and sometimes wierd&lt;/li&gt;
&lt;li&gt; multiparadigm - there's always more than one way to do it (TMTOWTDI)&lt;/li&gt;
&lt;li&gt;and, of course: a language with built-in XML support can't be up to no good ;-)&lt;/li&gt;
&lt;/ul&gt;

You might ask why I'm looking for a new language.

&lt;p&gt;
It's mostly a dissatisfaction with Haskell, my "official" favorite language -
that is, until I try to write a real program in it. Then I switch to
a "work" language most of the time. If you
spend 40 hours per week hacking in you not-so-favorite language A and
and at most 2 hours in your favorite language B, it's highly likely
that you'll be more productive in A, just because of great familiarity
with the language and its libraries. It especially hurts when something
that is easy in A seems harder and longer-winded in B.

&lt;p&gt;
So I often prototype things in Haskell, and write simple scripts, too, but as
soon as there's more IO, a database, or even (horror) a GUI, it's back to
Java or C. A Haskell program that has the IO monad in every nook and cranny
does not feel that elegant to me any more. Maybe I'm just too inexperienced
to properly encapsulate side effects, but sometimes the choice between pure
and impure seems very hard, especially when I just want to add some logging
or something comparable. Also, the Haskell libraries seem continually in a state
of flux, and the library docs is much worse than for many other languages.

&lt;p&gt;
So there that's the reason for my search: I want my "must have" features (static typing,
functional style) and some "nice to haves" (JVM, stable library) in a language I can use
for real projects.

&lt;p&gt;
I hope my current dissatisfaction will vanish when I get more familiar with Scala -
some things, especially syntax, you just have to get used to.
TMTOWTDI can be fixed by adopting a programming style and some patterns, and sticking to it.

&lt;p&gt;
 In a few hours,
the ICPF programming context 2010 starts.
Unless it's clearly a complete mismatch for the task, I'll use Scala this year.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8897180777295067814-2188366286648356525?l=bokesan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://bokesan.blogspot.com/feeds/2188366286648356525/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://bokesan.blogspot.com/2010/06/why-i-havent-learned-to-love-scala-yet.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8897180777295067814/posts/default/2188366286648356525'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8897180777295067814/posts/default/2188366286648356525'/><link rel='alternate' type='text/html' href='http://bokesan.blogspot.com/2010/06/why-i-havent-learned-to-love-scala-yet.html' title='Why I haven&apos;t learned to love Scala yet'/><author><name>Christoph Breitkopf</name><uri>https://profiles.google.com/112823570007766118485</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-nsRxuSQuGfY/AAAAAAAAAAI/AAAAAAAAADo/-1nxb5bWdaw/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8897180777295067814.post-8236419556418759465</id><published>2010-06-14T03:52:00.000-07:00</published><updated>2010-06-16T03:58:42.271-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Android'/><category scheme='http://www.blogger.com/atom/ns#' term='MapExplorer'/><title type='text'>Android Performance</title><content type='html'>I recently got a Motorola Milestone (aka Droid),
and I'm testing whether it's fast enough for a straight
port of &lt;a href="http://www.bokeh.de/ddm/mapexplorer/"&gt;MapExplorer&lt;/a&gt;.

&lt;p&gt;On the slowest PC I have available (a first-generation EeePc 701
- Intel Celeron-M ULV 353 underclocked to 630 MHz), with the HotSpot Client VM,
LoS computation takes 1 - 2 seconds on average.

&lt;p&gt;
For integer code, the Milestone's CPU (TI OMAP3430 ARM Cortex A8 running at 550 Mhz)
should at least be in the same ballpark as the Celeron, even though
it's in-order. For FP, I don't even have a clue. It could be anywhere from
about as fast to 20 times slower.

&lt;p&gt;
So I wrote a small wrapper app containing just the LoS computation
with results written to a text view. I didn't have the patience to
do a full-map benchmark run yet, but LoS computation seems to take
from 15 to 30 seconds. More than an order of magnitude slower
than the Celeron, and probably a bit too slow for practical use.

&lt;p&gt;
On the other hand, it's also not that slow that it &lt;em&gt;forces&lt;/em&gt; a
different approach like using precomputed LoS. Newer phones have faster
CPUs and then there's Android 2.2 (Froyo) which has a JIT that presumably
speeds up CPU-intensive code (including floating-point) by at least
a factor of two. Combined, that would result in times below 10 seconds.

&lt;p&gt;Unfortunately, I can't test whether the JIT will speed up the LoS
computation using the SDK, because it emulates a CPU without hardware
FP support, where the JIT won't have any effect.

&lt;p&gt;Given that I have limited time to work on this, performance
seems promising enough to prefer a straight port. While the features
of the online computation as opposed to precomputed LoS, namely being
able to modify the map on the fly, are probably rarely used, switching
to precomputed would still require some more work (checksums for maps,
how to handle used-supplied maps).

&lt;p&gt;
Even with the JIT, the Dalvik VM will remain far behind HotSpot or
optimizing compiler
performance for some time. For example, there's usually no difference between using
getters/setters and direct field access in HotSpot, but
&lt;a href="http://developer.android.com/guide/practices/design/performance.html#internal_get_set"&gt;a factor of 7 in Froyo&lt;/a&gt;.
Actually, I have to admit that I sort of like the current situation.
I'm a coder at heart, and performance tuning is a really gratifying
excercise (especially if it works). When was the last time you actually gained
performance by doing CSE by hand? In Android, that's the thing to do in 
tight loops.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8897180777295067814-8236419556418759465?l=bokesan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://bokesan.blogspot.com/feeds/8236419556418759465/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://bokesan.blogspot.com/2010/06/android-performance.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8897180777295067814/posts/default/8236419556418759465'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8897180777295067814/posts/default/8236419556418759465'/><link rel='alternate' type='text/html' href='http://bokesan.blogspot.com/2010/06/android-performance.html' title='Android Performance'/><author><name>Christoph Breitkopf</name><uri>https://profiles.google.com/112823570007766118485</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-nsRxuSQuGfY/AAAAAAAAAAI/AAAAAAAAADo/-1nxb5bWdaw/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8897180777295067814.post-2151466733316752218</id><published>2010-06-08T09:14:00.000-07:00</published><updated>2010-06-08T09:14:26.388-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Trouble with True</title><content type='html'>&lt;p style="margin: 2em"&gt;
But let your communication be, Yea, yea; Nay, nay: for whatsoever is more than these cometh of evil.
&lt;br/&gt;&lt;i&gt;Matthew 5,37&lt;/i&gt;
&lt;/p&gt;

&lt;p&gt;
Could there be anything more basic and obvious to a computer programmer that the data
type of truth values, commonly known as boolean? 

With just two values, it's not only much easier that, say integers, but it also
is the foundation for the most basic of control structures.

It's even in the bible (the one cited above, &lt;em&gt;not&lt;/em&gt; TAOCP).

&lt;/p&gt;

&lt;p&gt;So, constructs like this&lt;/p&gt;

&lt;pre&gt;
  if (logging == true) {
     log.info("I said so!");
  }
&lt;/pre&gt;

&lt;p&gt;or this&lt;/p&gt;

&lt;pre&gt;
  if (&amp;lt;condition&amp;gt;) {
    var = true;
  } else {
    var = false;
  }
&lt;/pre&gt;

&lt;p&gt;always leave my quite irritated. What's going on here? Why was it written this way?&lt;/p&gt;

&lt;p&gt;In the first example, assuming it's Java, there's nothing operationally wrong with the code.
In Java, comparing to &lt;em&gt;true&lt;/em&gt; is the identity operation on booleans, so adding it
it does not hurt. What irks me is that I have no idea what brings a programmer
to writing it this way - I always have the disturbing feeling that the programmer
who writes this way may not really have understood about booleans.&lt;/p&gt;

&lt;p&gt;I'm always tempted to suggest either adding a few more &lt;code&gt;"== true"&lt;/code&gt;
to be &lt;em&gt;really&lt;/em&gt; sure not to accidentally miss a true value:&lt;/p&gt;

&lt;pre&gt;
  if ((((logging == true) == true) == true) == true) {
    ...
  }
&lt;/pre&gt;

&lt;p&gt;or to also add a few identity operations to other data types - if it's good
for booleans, it can't hurt doing it for int, no?&lt;/p&gt;

&lt;pre&gt;
  for (i = 0 + 0; i + 0 &lt; n; i = i + 0 + 1) {
    ...
  }
&lt;/pre&gt;

&lt;p&gt;For some reason, no one is willing to do that.&lt;/p&gt;

&lt;p&gt;What makes the example really irritating is that there are many languages, for example
C, Lisp, or VB6, where comparing to true is &lt;em&gt;not&lt;/em&gt; the identity operation on booleans, because in
these languages there are many values that are regarded as true in the if statement.
The constant true equals only one of these values. So, if the code above were not
Java but C, what was the intention of the programmer? Did he really want to compare
the variable to only one specific true value, and treat others as false?
Or did he know that in this case the variable can only have the values true and false?
Or is the code simply wrong?
&lt;/p&gt;

&lt;p&gt;In the second example there is no problem with correctness. It's only the
style that's completely hilarious. Why is the expression not assigned directly?&lt;/p&gt;

&lt;pre&gt;
  var = &amp;lt;condition&amp;gt;;
&lt;/pre&gt;


&lt;p&gt;
My feeling is that there is a tendency not to view boolean as a "first class type" like
numbers. It is viewed as somehow "special" and some programmers are unsure just where
a boolean variable or expression may be used. I've actually spoken to people who think
the direct assignment above just looks unnatural, and who find the version with &lt;code&gt;if&lt;/code&gt; to be more
readable. How can that be?
&lt;/p&gt;

&lt;p&gt;Maybe it's just that numbers are much deeper ingrained. A multiplication table, even only
for the natural numbers from 1 to 10, is much larger than the table for the boolean functions,
but most of us learned the multiplication table in elementary school, but the boolean functions
much later, if at all.&lt;/p&gt;


&lt;p&gt;Still this spells trouble for the trend to more functional and expression-based languages.
If even boolean is hard to grasp as a first class type, what about higher-order functions and
other things decidedly more complex than that?&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8897180777295067814-2151466733316752218?l=bokesan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://bokesan.blogspot.com/feeds/2151466733316752218/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://bokesan.blogspot.com/2010/06/trouble-with-true.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8897180777295067814/posts/default/2151466733316752218'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8897180777295067814/posts/default/2151466733316752218'/><link rel='alternate' type='text/html' href='http://bokesan.blogspot.com/2010/06/trouble-with-true.html' title='Trouble with True'/><author><name>Christoph Breitkopf</name><uri>https://profiles.google.com/112823570007766118485</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-nsRxuSQuGfY/AAAAAAAAAAI/AAAAAAAAADo/-1nxb5bWdaw/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry></feed>
