Friday, January 22, 2010

Reproducing bugs on complicated webpages

A while back, I was running into hangs on Facebook with the html5 parser. I wanted to reproduce the problem locally and try to minimize it. However, Facebook is pretty complicated and loads content using ajax, so the traditional approach of saving the page didn't work. I needed a different approach, so I hacked up a http proxy to be able to record and replay server interactions. It works by writing out the result of each GET request to a file named after the Request-URI. After you're done recording an interaction with the server, you can switch to replay mode and instead of proxying, the recording will be played back to the browser.

I should mention a couple of limitations to this approach. First, it assumes that the resources specified at particular urls don't change over the recording session. Second, it assumes that the resources requested are dependent only on the data recorded and not on the time or anything like that. Even with these limitations, the proxy seems to work well enough.

It's currently pretty hacky, but you can grab it from git://anongit.freedesktop.org/~jrmuizel/http-recording-proxy. There's a README in the repository explaining how to run and replay. I'd love to hear if this of any use to anyone else or if you have patches for improving it.

Graphics performance in Firefox 3.6

One of the performance improvements included in Firefox 3.6 is a new path rasterizer for use on Windows. This new rasterizer improves vector graphics performance substantially.

The previous rasterizer is designed for a XRender trapezoid model of rasterization. In this model, to fill a polygon, we first tessellate it into a collection of trapezoids. Next, each of these trapezoids is rasterized and the result added to mask image. Finally, this mask is used to composite the filled polygon. This design can work well if we rasterize multiple trapezoids in parallel as could be done on a GPU. However, when we're using the CPU to sequentially rasterize and blend each trapezoid it's not the most efficient approach.

Scanline rasterization is the textbook method for filling polygons and when using a CPU it can be more efficient than tessellating. Instead of breaking the polygon into trapezoids we iterate over each scanline of the mask image. For each scanline, we iterate over the edges that it intersects and fill the pixels in-between the edges to produce the mask image.

M Joonas Pihlaja contributed a scanline rasterizer to cairo as part of a Google Summer of Code project and it's included in Firefox 3.6. This new rasterizer makes a pretty significant difference when filling complex paths. For example, this test draws a spinning map of the world using canvas. In Firefox 3.5, I get about 6-7fps. Using Firefox 3.6, it's nearly 4x faster with about 19-24fps.