TargettingGnash

From Gnash Project Wiki

Jump to: navigation, search

This tutorial is intended to help developers learn how to profile Gnash, focusing on the renderer in order to identify bottlenecks in the Gnash source code. The hope is that by removing these bottlenecks we should be able to improve the playback of animations, and make Gnash a more valid alternative to Adobe's Flash Player.

I work for a company named eyemagnet[1] and we use Gnash to display advertisements with animations on digital signage displays[2].

This tutorial was written using an Ubuntu 8.10 distribution, and some commands may differ slightly on other distributions. I encourage anyone to help improve this tutorial if they believe they have a smarter solution than any of the ones I have used here, or they would like to share their distribution specific commands.

I will cover how to compile and install Gnash for this purpose and, secondly, I will describe how to carry out the profiling.


1. Building Gnash for profiling

For the profiling, we'll use Gnash revision 10692 as it includes a fix in FPS profiling support whilst still being closely related to the 0.8.5 release. So let's download the source code:

  mkdir gnash-source
  cd gnash-source/
  bzr branch http://bzr.savannah.gnu.org/r/gnash/trunk -r 10692

Once this is completed we want to apply some patches. My colleagues and I at eyemagnet have developed some patches to increase the functionality of Gnash slightly. Let's include those as well:

  cd trunk/
  wget https://savannah.gnu.org/patch/download.php?file_id=17617
  patch -p0 < 0.8.5-window-position-FIXED.patch\?file_id\=17617 
  wget https://savannah.gnu.org/patch/download.php?file_id=17914
  patch -p0 < swf-scale-rev.10692-fixed.patch?file_id=17914

Once the patches are applied, we need to configure the build. Here I am building for GNOME. If you use KDE you should change the --enable-gui=gtk to either --enable-gui=kde3 or --enable-gui=kde4, depending on which version you use. You will also need some OpenGL development libraries to compile against. If you do not have these, the configure command should be able to help you figure out which OpenGL development libraries you need to install (just use your favorite package manager). So here we go:

  sudo apt-get build-dep gnash
  ./autogen.sh
  ./configure --enable-gui=gtk --enable-fps-debug --disable-shared CXXFLAGS="-pg -g"

Now we're ready to build:

  make

If all is going well, you will now find an executable in your directory which you could use for profiling. To make things easier for myself, I normally install the executable by:

  sudo make install

2. Profiling

For this example we will compare the two files:

SFI003A3-logo-bitmap.swf

SFI003A3-logo-vector.swf

So, let's download them:

  wget http://www.eyemagnet.com/files/SFI003A3-logo-bitmap.swf
  wget http://www.eyemagnet.com/files/SFI003A3-logo-vector.swf

[Theory] When we're profiling we will be looking for things like:

  1. How much CPU is Gnash requiring to play the file? This gives us an indication of how much the CPU is being tied up.
  2. Is Gnash maintaining the intended frame rate of the file?
  3. Which functions is the CPU spending all of its time in? The details are in the profile report.

We can then start to look at how to improve on the structure that's making gnash overwork certain functions, and make patches for it.

You can monitor the CPU usage by launching this command in a terminal:

  top | grep gnash

And then in another terminal I launch Gnash:

  gnash --max-advance=400 --debug-fps 1 SFI003A3-logo-bitmap.swf

Once the file has finished playing you can produce a report by:

  libtool --mode=execute gprof ../gnash-source/trunk/gui/gtk-gnash > SFI003A3-logo-bitmap.profile

The path given, in this case: "../gnash-source/trunk/gui/gtk-gnash", needs to point to where you built Gnash in order to produce the report (as a relative path... I imagine absolute will work as well). The profile report will be put into the file SFI003A3-logo-bitmap.profile which you can inspect using your favorite text editor. I would recommend using nano or vim instead of gedit or other GUI-based text editors as the latter will load the entire file into RAM before displaying it. Since the file is often 10MB or so, this can take a while. nano and vim only load what they show you so they're much faster.

Returning to the terminal window where we launched "top | grep gnash", the CPU usage is the 9th column in, after the S's and R's. Averaging these numbers should give you a good indication of how much processing is required to play a particular file.

The frame rate (FPS) is output by Gnash in the terminal window where it was launched.

This procedure is then repeated for the next file. Afterward you can compare the different reports and profiles.

Upon inspecting the profiles you can see that Gnash spends most of its time in the following processes:

Extract of the file SFI003A3-logo-bitmap.profile:

 Each sample counts as 0.01 seconds.
   %   cumulative   self              self     total
  time   seconds   seconds    calls   s/call   s/call  name
  27.06     50.29    50.29   318773     0.00     0.00  agg::span_image_filter_rgb_bilinear<agg::image_accessor_clone<agg::pixfmt_alpha_blend_rgb<agg::blen...
   9.19     67.36    17.07 1080996420   0.00     0.00  agg::dda2_line_interpolator::operator++()
   6.97     80.31    12.95 540498210    0.00     0.00  agg::span_interpolator_linear_subdiv<agg::trans_affine, 8u>::operator++()

The gprof output contains total time spent by the process (one of the columns of the flat profile is the cumulative time, so its last row shows the total time spent).

Extract of the file SFI003A3-logo-bitmap.profile:

 Each sample counts as 0.01 seconds.
   %   cumulative   self              self     total
  time   seconds   seconds    calls   s/call   s/call  name
  19.91      2.60     2.60   317367     0.00     0.00  agg::pixfmt_alpha_blend_rgba<agg::blender_rgba_pre<agg::rgba8, agg::order_bgra>, agg::row_accessor<unsigned char...
  18.30      4.99     2.39   317721     0.00     0.00  agg::pixfmt_alpha_blend_rgba<agg::blender_rgba_pre<agg::rgba8, agg::order_bgra>, agg::row_accessor<unsigned char...
  15.16      6.97     1.98    70348     0.00     0.00  agg::span_image_filter_rgb_bilinear<agg::image_accessor_clone<agg::pixfmt_alpha_blend_rgb<agg::blender_rgb_...

In this case, it's clear that the vector graphics render much faster than the bitmap showing Gnash has issues rendering bitmaps quickly. We can see that Gnash spent most of it's time in agg::span_image_filter_rgb_bilinear indicating that transparency is a very hard operation for Gnash to perform when there are bitmaps involved. This especially becomes noticeable when you compare the cumulative seconds involved with that of the vector version.

The CPU usage was much the same on both files--basically maxing out at close to 100%--so not much difference there. I did, however, observe a huge difference in frame rates (FPS) with SFI003A3-logo-bitmap.swf recording:

 Effective frame rate: 0.62 fps (min 0.28, avg 0.62, max 1.07, 402 frames in 652.7 secs total)

and SFI003A3-logo-vector.swf recording:

 Effective frame rate: 11.44 fps (min 6.43, avg 10.61, max 11.62, 391 frames in 36.8 secs total)

Again, we see that there are some real issues around rendering bitmaps with transparencies as the frame-rate is hugely different.

This should, hopefully, be enough to introduce you to profiling the renderer in Gnash. I hope you enjoyed the tutorial :)

3. Designing content for Gnash

Depending on what capabilities of the SWF format an animator chooses to use for animation effect or how an animator chooses to create a particular effect Gnash may start slowing down when playing the animation. At Gnash's current stage of development there are some performance issues around various parts of the software that causes a slow down in the frame rate of playing a file. This section was written for animators, to provide some tips on how you might be able to speed up your animations playback in Gnash, hopefully in a short and useful way.

Tips on using images:

  1. Use vector fill rendering whenever possible, it's much faster.
  2. Resolution of images should ideally be kept a small as possible.
  3. The file size of the bitmap being loaded is largely irrelevant in terms of rendering, so don't worry about compressing bitmaps before adding to animation, instead focus on reducing the image resolution size.
  4. Modify images that have large areas not being shown. Sometimes you may want to use a large image, only to show certain parts of it. If this is the case try shaping the image to the parts that you do want to show, and remove parts not shown.
  5. Images with alpha channels should be avoided whenever possible, or kept small in resolution. They are particularly slow with the Gnash renderer so use with caution.
  6. Disable bitmap fill smoothing, also known as *hard* edges bitmap fills. This an be done at the SWF level setting _root._quality to "MEDIUM" or "LOW".


General tips:

  1. Frame rate = 12 fps. Currently the generally used frame-rate for Gnash is 12 frame per second, and it is also my recommendation to use this rate. Depending on your animation and the hardware it will be played back on, you may be able to increase the frame-rate, but as a general rule of thumb; try 12 first.
  2. Stick to SWF version 7. Although some of the features from SWF8 and up are available, many are missing, and the one that are implemented may also reduce the frame-rate because they require more processing power than features of SWF7.

Gnash is a piece of software still under heavy development, and as such not everything is working perfectly yet. Unfortunately we have to work with what we have, which does carry a creative challenge for animators, as many of the SWF8-10 features which are industry standard by now, are simply not feasible in Gnash yet. Hopefully the Gnash project will be able to catch up to Adobe's Flash Player eventually, and these tips will become obsolete, but for now I hope you found them useful.