I read a few posts about how good fit Ruby is for building DSLs, Domain Specific Languages. Ever the curious I have been waiting for the opportunity to build a very simple one for a particular problem.

Well, I did not have to wait very long (when you have a hammer everything looks like a nail). I needed a quick method which generates nice html graphs for my post about browser javascript engine benchmarking. After spending a few minutes searching for a free tool (I did not want anything fluffy, just something very basic) I hit the nail in the head with my hammer. Only the nail was the generated HTML charts for my post and the hammer, (my desire to build) a DSL in Ruby.

I would like to say it was difficult but in fact it was a piece of cake with Ruby (and armed with the knowledge of previous DSL builders). The solution is composed of the following three parts:

  1. The DSL file which defines the charts
  2. The interpreter which understands the definitions in the DSL file
  3. The “controller” which just passes the data contained in the DSL file to the interpreter

So let’s see each part separately:

browser_js_benchmarks.dsl (the DSL)

chart "Score" do |c|
	c.add "Safari 3.1.2" => 164
	c.add "Firefox 3.0.1" => 156
	c.add "Shiretoko" => 145
	c.add "Google Chrome" => 1589
end

chart.rb (the interpreter)

require "math_aux"
 
class ChartDSL
 
	Template = %(<table border="0" cellspacing="5" cellpadding="5"><caption>%%CAPTION%%</caption>%%ITEMS%%</table>)
	Background_colors = %w(red blue green yellow grey)
 
	attr_reader :values
	def initialize
		@charts = Array.new
		@values = Hash.new
	end
 
	def chart(name)		
		@name = name
		yield self
		@charts.push(make_html)
	end
 
	def add(name_and_value)
		@values ||= Hash.new
 		@values.merge!(name_and_value)
	end
 
	def load(filename)
		# c = new
		instance_eval(File.read(filename), filename)
		write_output
	end
 
	def make_html
		sorted_pairs = @values.sort_by { |v| - v[1] }
		vals = sorted_pairs.map { |p| p[1] }
		norm_values = MathAux::normalize(vals, 100.0)
		html = Array.new
		sorted_pairs.each_with_index do |pair, i|
			name, value = pair
			html.push(%Q(<tr><td>#{name}</td><td><div style="width:#{norm_values[i]}px;background-color:#{ChartDSL::Background_colors[i]}">&nbsp;</div></td><td>#{value}</td></tr>))
		end
		filled_chart = ChartDSL::Template.sub("%%CAPTION%%", @name)		
		filled_chart.sub("%%ITEMS%%", html.join)
	end
 
	def write_output
		File.open("generated_charts.html", "w") do |f|
			f.write(@charts)
		end
	end
end

chart_loader.rb (the controller)

require "chart"
class ChartLoader
	def self.load_chart(dsl_filename)
		c = ChartDSL.new
		c.load(dsl_filename)
	end
end
 
if __FILE__ == $0
	ChartLoader.load_chart(ARGV[0])
end

For the sake of completeness here is math_aux.rb:

module MathAux
	def self.normalize(numbers, to=1.0)
		norm_rat = to / numbers.max
		numbers.map { |n| n * norm_rat }
	end
end

To generate the charts, one only has to run “the interpreter” with a dsl file as the first parameter:

ruby chart_loader.rb browser_js_benchmarks.dsl

The output is called generated_charts.html and contains the following:

<table border="0" cellspacing="5" cellpadding="5">
<caption>Score</caption>
 <tr>
  <td>Google Chrome</td>
  <td><div style="width:100.0px;background-color:red">&nbsp;</div></td>
  <td>1589</td>
 </tr>
 <tr>
  <td>Safari 3.1.2</td>
  <td><div style="width:10.3209565764632px;background-color:blue">&nbsp;</div</td>  <td>164</td></tr>
 <tr>
  <td>Firefox 3.0.1</td>
  <td><div style="width:9.81749528005034px;background-color:green">&nbsp;</div</td> <td>156</td>
</tr>
<tr>
 <td>Shiretoko</td>
 <td><div style="width:9.12523599748269px;background-color:yellow">&nbsp;</div</td><td>145</td>
</tr>
</table>

Note that in ~30-40 code lines we have a “language interpreter”, one that understands the chart DSL and spits out some HTML code that represents the charts. Of course there is plenty of room for improvement, like having the same color denote the same actor between charts (Firefox 3.0.1 should always be the blue bar, for example, unlike in my post), using a better solution for the template strings, adding the possibility of pie charts (although “standard” HTML is not very flexible on different chart forms, one would probably have to use a <canvas> ), and so on.

The essential thing is that it works and it does what the particular situation demanded. It took me a couple of interrupted hours plus the time to read through two related posts which is not that much given that I now have a “tool” (once again, I feel a bit conceited to call it that) which I can use for my future posts whenever the need arises. A custom hammer for my custom nail.

(If you care, feel free to download, use and modify the source code located here)

A few weeks back when I read about Chrome I became interested in V8, a javascript engine that Google integrated in their browser and that they claimed to be very fast due to the following reasons:

  • Hidden class transitions that enable dynamic optimizations since objects will use the same (hidden) class
  • generating machine code instead of interpreting the source code each time
  • incremental garbage collection which reduces the time needed for the cleanup to milliseconds and eliminates “second long pauses”

All that sounded very promising but as an engineer by profession it left me with a desire to find out how much faster all these features made V8 (and any browser that might use it). Even more so since I love running benchmarks and compare numbers. Well, maybe Google sensed that since they provided all the necessary tools to run these tests on the V8 benchmark page and to run them very easily.

There are 5 different algorithms in the testing suite exercising different qualities of the javascript engine. To be fair I closed all other tabs in browsers during the testing attempting to minimize operations that can have an effect on test performance. Also, the V8 tests were run from the command line so that might skew the results a bit towards V8. Anyyway, here are the results (numbers mean execution time so smaller is better):

Richards
Google Chrome
 
2072
Firefox 3.0.1
 
152
Shiretoko
 
116
Safari 3.1.2
 
91
DeltaBlue
Google Chrome
 
1753
Firefox 3.0.1
 
171
Safari 3.1.2
 
127
Shiretoko
 
123
Crypto
Google Chrome
 
1415
Firefox 3.0.1
 
150
Shiretoko
 
150
Safari 3.1.2
 
135
RayTrace
Google Chrome
 
1021
Safari 3.1.2
 
232
Firefox 3.0.1
 
126
Shiretoko
 
114
EarleyBoyer
Google Chrome
 
1933
Safari 3.1.2
 
328
Shiretoko
 
259
Firefox 3.0.1
 
188
Score
Google Chrome
 
1589
Safari 3.1.2
 
164
Firefox 3.0.1
 
156
Shiretoko
 
145

The superiority of V8 stunned me so much even to push me to ask whether all this is possible. Googe Chrome that uses V8 is on average (see Score) 10 times faster than all the other browsers (that pretty much flock together). I expected to find the speed of Firefox 3.1 (codename Shiretoko) close to that of Chrome but to my surprise it does not even surpass that of the other browsers. That made me a bit disappointed since I am a big Firefox fan.

Can it be that these benchmarks are somehow tailored to show V8’s dominance? (like some political polls are skewed to give the “correct” answer). That this is not such a far-fetched idea is supported by Mozilla’s announcement that TraceMonkey, Firefox’s javascript engine will be 16-28% faster than V8. And they have their own benchmarking solution, SunSpider to prove their point.

So the life of javascript engine developers has got a lot harder. Not only they have to implement a fast engine but also a benchmarking system that shows there is nothing as fast as theirs!

The first beta version (for now only for Windows) of Google’s browser is out, but I don’t think Google needs the marketing power of my post so that’s not what I want to talk about. The browser is introduced by a ingenious comics of 39 pages. However, the navigator is too simple, in my opinion in that you cannot skip a page so if you read until say page 19 and you have to start over (e.g you closed the browser), you have to click on the “Next” link 18 times. There is no unique URL for each page, the whole navigation is done with a javascript snippet changing the image (the cartoon strip) when the user clicks “Prev” or “Next”.

So I took a peep at the source of the page and reverse-engineered the navigation which is simply a javascript call to goPage(’next’) when the user clicks the Next link. So now I can simply write

javascript:for (var i=0; i < 10; i++) goPage('next');

to the location bar to skip 10 pages ahead and do the same with ‘prev’ to rewind 10 pages.

I know “reverse-engineering” is way too conceited a term for this but this kind of hacking tickles my brain in a very joyful way and feels a bit like outsmarting Google. And that’s not bad at all.

UPDATE: I now realize the comics’s navigation has been redesigned so my above fix became obsolete. At least I cherish the knowledge my hack addressed a real UI problem (and did that faster than Google :) ).