Thursday, August 14, 2008

Moonlight Performance Enhancements

Spent today working with Sebastien "Master Profiler" Pouliot on finding and resolving one of our longest outstanding performance bottlenecks in Moonlight for which the GlyphMap Utility is a perfect test case.

Months ago, I had rewritten the font caching a bit so that we prevented (in most cases) the loading of the same font file that were shared between multiple textual XAML elements (Glyphs and TextBlock). At the time, font loading was at the top of the performance profile. While this fix did help a little as far as rendering speed went, it was barely noticeable visually. It wasn't a waste, however, because it greatly reduced memory overhead and later allowed for some better font scaling optimization tricks that I implemented.

Next up, I rewrote the Glyphs XAML element's ::ComputeBounds() routine such that not only did it calculate the rendering extents of the Glyphs element, but also cached the glyph string layout in a Cairo path such that later calls to ::Render() could simply blit the path rather than having to do its own layout.

Still, visual rendering performance seemed barely affected.

Then, today, Sebastien decided to take a look into the problem again and had discovered that sorting UIElements based on ZIndex was toward the top of the list as far as time-eaters went. The fix for this was to delay sorting the newly added UIElements until the engine went to render the next frame.

This bumped the sorting code right out of the time-eaters list but still no visual improvement :(

Sebastien reported back to me that we seemed to be idling between Glyphs draws which immediately made me recall that our Downloaders asyncronously download the referenced font files that each Glyphs element references and that at each render tick, we only popped a single request from our async queue.

I immediately went to work and fixed the async queue logic to pop as many frames as we could in 1/30th of a second (this value may need to be tweaked a slight bit, but it should typically be acceptable).

The GlyphMap table now renders instantly.

6 comments:

Anonymous said...

You guys are doing amazing work, keep it up!

Anonymous said...

I've been poking at the moonlight source code and it is some of the most beautiful c++ code I've ever had the pleasure of reading.

I've been thinking about adding some flash graphics to rythmbox using moonlight at some point. I just need to find the time (between work and kids, it's tough!).

Thank you guys tremendously for all your amazing work.

Anonymous said...

Have you guys thought about suggesting moonlight as GNOME's new canvas widget?

mdi said...

Kristoff,

We did some work to make Moonlight reusable from C for people interested, and we do have a more complete .NET binding that will be uesful for anyone doing Gtk# applications, but both are still in flux.

Once things settle, we would love to see more people adopt these as platforms for creating great looking applications.

Miguel.

Anonymous said...

Hi,
can you please explain what kind of profiler did you use to get those kind of measurements?

Thanks

Jeffrey Stedfast said...

Stefano:

We use a variety of profilers, typically sysprof, cachegrind and callgrind.

Code Snippet Licensing

All code posted to this blog is licensed under the MIT/X11 license unless otherwise stated in the post itself.