Bluish Coder

Programming Languages, Martials Arts and Computers. The Weblog of Chris Double.


2009-05-01

Simple Nanojit Example

I've been playing around with Nanojit, thinking about using it in a toy project of mine.

Nanojit is a library for generating machine code with backends for x86 and ARM. It's used by Tamarin) and TraceMonkey for their just in time compilers.

The Mozilla documentation contains some documentation which gives an overview of what's there:

Currently Nanojit seems to be directly included in both the Tamarin and Mozilla repositories. To make it easy to reuse in my various test projects I split out the nanojit code and put it in a github repository. The build is a simple makefile and is only setup for x86 since that's that platform I'm trying it on for now.

In the 'example' directory of the nanojit github repository is the example from the Mozilla documentation. This is what I'm basing my usage of it from.

As a simple test of using it I wrote an expression evaluator. You enter simple mathematical expressions using addition, subtraction, multiplication and division at the command line and it compiles the expression into machine code using nanojit and calls it to get the result.

I started with an interpreter first and added the compiling once that was working. To parse the expressions I used Ian Piumarta's Parsing Expression Grammar library. I tweaked it a bit to be able to use it from C++. The grammar is simple and produces a basic Abstract Syntax tree:

Expr      = lhs:Product (  "+" rhs:Product  { lhs = new Add(lhs, rhs); }
                         | "-" rhs:Product  { lhs = new Subtract(lhs, rhs); }
                        )*                  { $$ = lhs }
Product   = lhs:Value   (  "*" rhs:Value    { lhs = new Multiply(lhs, rhs); }
                         | "/" rhs:Value    { lhs = new Divide(lhs, rhs); }
                        )* _                { $$ =lhs }
Value     = Number _
Number    = < [0-9]+ ('.' [0-9]+)?>     { $$ = new Number(atof(yytext)); }

Running this through the 'leg' program produces C code that can be included in the project to compile the expression entered by the user. The interpreter just walks over the AST, calling an 'eval' method, to produce the result. Code looks like:

float Number::eval()  { return value; }
float Add:eval()      { return lhs->eval() + rhs->eval(); }
float Subtract:eval() { return lhs->eval() - rhs->eval(); }
float Multiply:eval() { return lhs->eval() * rhs->eval(); }
float Divide:eval()   { return lhs->eval() / rhs->eval(); }
int main() {
  Object* result = parse();
  cout &lt;&lt; "Result: " &lt;&lt; result->eval() &lt;&lt; endl;  
  return 0;
}

Converting this to generate machine code and call it is pretty easy. Instead of an 'eval' method I created a 'compile' method. 'compile' takes an object as an argument that I call methods on to generate Nanojit intermediate representation (LIR). It returns the resulting generated LIR instruction. The code for the Number AST object looks like:

LIns* Number::compile(LirWriter* writer) {
  return writer->insImmf(value);
}

The LirWriter object contains methods to generate LIR code. For Number we generate an immediate float value and return a pointer to the generated instruction.

The operators are implemented in a similar manner. I'll just show the code for Add:

LIns* Add::compile(LirWriter* writer)
{
  LIns* a = lhs->compile(writer);
  LIns* b = rhs->compile(writer);
  return writer->ins2(LIR_fadd, a, b);
}

Here we compile the left and right hand sides of the expression, saving pointers to the generated instructions. Then we generate a 'float add' LIR instruction. This is passed the instructions that were generated for the left and right parts of the expression. By calling compile on the topmost AST object we end up generating the code for the entire expression.

The code required to set up Nanojit and create the LirWriter is a bit more complicated. Most of what I did was copy and pasted from the example code. Basically I create a Fragmento object and a LirBuffer. Then each time an expression is entered I create a Fragment object which will contain the final generated code and a LirBufferWriter which is the base LirWriter object used by the 'compile' methods.

LirWriter's can be added to a LirBufferWriter to form a pipeline that instructions go through to do different things like optimisation or output debugging code before ending up in the LirBuffer. After this I generate a 'start' instruction, call the 'compile' method to do the rest, and generate a required epilogue instruction:

Fragmento *fragmento = new (gc) Fragmento(&core, 20);
LirBuffer *buf = new (gc) LirBuffer(fragmento, NULL);
...
Object* result = parse();
...
Fragment *f = new (gc) Fragment(NULL);
LirBufWriter writer(buf);
...
writer.ins0(LIR_start);
writer.ins1(LIR_fret, result->compile(&writer));
...
f->lastIns = writer.insGuard(LIR_loop, writer.insImm(1), rec_ins);

// Compile the fragment.
compile(fragmento->assm(), f);

// Call the compiled function.
typedef JS_FASTCALL float (*ExprFunction)();
ExprFunction fn = reinterpret_cast<ExprFunction>(f->code());
cout << "Result: " << fn() << endl;

The expression evaluator interpreter and compiler example can be downloaded and played with by cloning my 'play' repository on github. Once cloned you'll need to initialize and update the submodules to pull in the nanojit and peg third party libraries that it uses:

$ git clone git://github.com/doublec/play.git
$ cd play
$ git submodule init
$ git submodule clone

Run 'make' in the 'expr-interpreter' and 'expr-compiler' directories and run the 'expr' program that results. If you compile both nanojit and expr-compiler with DEBUG defined you get some debug output. It show's the LIR and the assembler code generated. For example, the LIR for: 2+3+4*2 is:

start
#40000000:0 /* 2 */
#40080000:0 /* 3 */
fadd1 = fadd #0x40000000:0, #0x40080000:0
#40100000:0 /* 4 */
#40000000:0 /* 2 */
fmul1 = fmul #0x40100000:0, #0x40000000:0
fadd2 = fadd fadd1, fmul1
ret fadd2</pre>The assembly code generated for this is:<pre>mov -8(ebp),0                  
mov -4(ebp),1073741824         
mov -16(ebp),0                 
mov -12(ebp),1074266112        
fldq -16(ebp)                  
fadd -8(ebp)                    f0(#0x40080000:0)
fstpq -8(ebp)                   f0(fadd1)
mov -16(ebp),0                 
mov -12(ebp),1074790400        
mov -24(ebp),0                 
mov -20(ebp),1073741824        
fldq -24(ebp)                  
fmul -16(ebp)                   f0(#0x40000000:0)
fadd -8(ebp)                    f0(fmul1)

It's easy to change the code to use integer math instead of floating point. Use LIR_ret instead of LIR_fret for the return, and use LIR_add, LIR_sub, etc. This is the assembly code generated for 2+3+4*2 using integer math:

mov eax,2                      
add eax,3                       eax(2)
mov ebx,4                       eax(add1)
mov ecx,2                       eax(add1) ebx(4)
mul ebx,ecx                     eax(add1) ecx(2) ebx(4)
add eax,ebx                     eax(add1) ebx(mul1)</pre>
Tags: nanojit  mozilla 

2009-04-10

Another tinyvid.tv update

I've made some more changes and fixes to tinyvid.tv since my last update.

I've updated to the latest Factor version, picking up some bug fixes and improvements to the libraries that I use.

The look and feel of the site has a new logo and banner thanks to Hans Schmucker. There have been some great contributions and bug reports in the feedback part of the site from Hans and others.

Support for converting Daily Motion videos is now in place. This gives three sites that can be converted from now. The other two being YouTube and Vimeo. In all cases it tries to convert the highest quality video available from the site.

A number of bugs in the file uploads have been fixed. There still are a few annoyances in this area, mainly to do with not very good error reporting when an upload fails. I'm still playing around with this area.

Previously logging in was done with Facebook Connect. Now I've added support for Open ID as well as Facebook and others.

This support was easily added using the great service from RPX Now. I implemented server support in Factor very easily and it gives a nice authentication login interface. If you don't want to associate an existing account with your tinyvid.tv videos you can use a service like myopenid.com to get an Open ID login and use that to authenticate with tinyvid.

I'm trialing the bookmarklet written by Hans Schmucker as the main player on the site. It provides visibility of the controls outside the video area so you can always see them without obscuring the video, has a volume control, and allows resizing the video. If you want to try the browser's standard controls you can click on the 'download' link on the video page to do that. I may switch between this player and the native controls based on feedback or if problems are found.

I added an 'embed snippet' on the video page so you can copy/paste it into your own pages to have the video embedded.

If you have any ideas for things to add or improve let me know.

Tags: video  tinyvid 

2009-04-03

The Linux Link Tech Show on HTML 5 Audio and Video

Yesterday I was a guest on The Linux Link Tech Show talking about Firefox and HTML 5 audio/video support. It was a great show with lots of interesting questions and discussions about video in the browser, the choice of Theora for the video codec, and different ways video can be used on the web.

The show is archived and you can download and listen to episode 292 recorded on the 1st April 2009. Vorbis and MP3 versions are available.

Tags: video  mozilla 

2009-03-26

oggplayer - A simple Ogg player using liboggplay

To help track down performance issues, and fix some a/v synchronisation bugs, I wrote a simple Ogg player in C++ using the same libraries and a similar approach to what I use in the Firefox video implementation.

The source to 'oggplayer' is available on github.

I've setup the repository to facilitate my experimenting with different approaches and different library versions. What this means is I've taken the, probably unusual, approach of having a 'thirdparty' directory containing git submodules for each of the Ogg based libraries I'm using. I configure and build these and link statically to them. This lets me use experimental versions of the Ogg libraries without dealing with 'shared library hell'.

This is all explained in the README, but just quickly these are the steps to clone oggplayer, and get the third party libraries from git:

$ git clone git://github.com/doublec/oggplayer.git
$ cd oggplayer
$ git submodules init
$ git submodules update

Once that's done you need to build the third party libraries:

$ cd thirdparty
$ sh build.sh

Run 'make' to build oggplayer itself. The third party libraries are built and installed in a 'local' subdirectory.

You'll notice the unix-centric leaning of these commands. I've only built on Linux. I'm using cross platform libraries so it should build with minor changes on Mac OS X. Mainly changing the audio library to link against in the Makefile. For Windows you'll probably need to use Cygwin or MSYS.

To run, just pass the filename on the command line:

$ ./oggplayer foo.ogg

Press ESC to exit the playback, and space bar to toggle full screen on supported platforms (those that SDL supports full screen).

These are the third party libraries I use, and include as submodules:

  • libogg
  • libvorbis
  • libtheora
  • liboggz
  • libfishsound
  • liboggplay
  • libsydneyaudio

You'll need the following system libraries to build:

  • Boost C++ libraries
  • SDL

There's not much error checking, I mostly use 'assert' to bail on an error. I don't want to spend time creating an awesome player, rather something I can use to try test out the way I'm using the third party libraries.

Interestingly with this example player I can play back the problematic HD video I mentioned previously. Part of this is the newer YUV conversion routines in liboggplay and the more lower level optimized SDL libraries for blitting the video data. I'm also not seeing audio buffer underruns which I see with some videos in Firefox. Time to do some investigating!

Tags: video  mozilla 

2009-03-23

Very nice web technology demo

This 'glimpse of future web technologies', all in one document is pretty nifty. Lots of different web stuff in there, including rotated videos, fancy CSS, and DFXP captions for videos.

Thanks to Sam Ruby for pointing to Philippe Le Hegaret's work.

Tags: mozilla 


This site is accessable over tor as hidden service 6vp5u25g4izec5c37wv52skvecikld6kysvsivnl6sdg6q7wy25lixad.onion, or Freenet using key:
USK@1ORdIvjL2H1bZblJcP8hu2LjjKtVB-rVzp8mLty~5N4,8hL85otZBbq0geDsSKkBK4sKESL2SrNVecFZz9NxGVQ,AQACAAE/bluishcoder/-61/


Tags

Archives
Links