Sunday, 14 February 2010

Optimising Modular Flex Applications using Link Reports

The benefits of creating a modular architecture for large Flex applications has been widely discussed.  When using such an architecture it is important to ensure that your compile process is correctly optimised. The risk with using multiple modules is that classes are compiled into more than one module which results in an unnecessary overhead.  Remember that once the definition for a class has been loaded, any future definitions will be ignored when using a single ApplicationDomain or child ApplicationDomains.  This means that if your main application includes a given classes, a definition for it in any modules you load will never be used. The simple fix for this is to compile all of your modules against the link report of your main application.  This is obviously only suitable if your modules are not going to be loaded by any other application.  The link report is an XML file that describes every class that has been compiled into a SWF, it includes information on the unoptimised and optimised size of every class. To generate a link report you need to apply the following compiler argument: -link-report=myReport.xml.  To compile against a link report and hence optimise your modules, use the following compiler argument: -load-extern=mainAppReport.xml.

The basic optimisation described above may suffice for simple use cases, but sometimes a better understanding of the compiled output is required.  If you compile a main application and multiple modules, analysing the compiled output can help you to understand where optimisation can be achieved.  The following shell script can be run over a directory of link reports, so simply apply the compiler argument given above to your main application and all your modules and run this script (*nix based OS, not Windows).  The output of this is a list of every class compiled into your SWFs and the number of times each class is compiled in.

grep -o "(.*)" *.xml | sed -e 's/\//./g' | sed -e 's/[()]//g' | sort | uniq -c | sort -r

Here's a brief explanation of how it works:  Extract all of the class names (contained between brackets) from the xml link report files, replace the slashes with dots (to give standard fully qualified class names), remove the brackets, sort the list (required by uniq), output a list of unique names with a count and then sort the list in reverse order.

The resulting list should help you to identify classes that are compiled in lots of times.  The libraries that these classes are in will most likely make good candidates for RSLs.  By using the library as an RSL you will load all of the class definition at application startup, which means that that you can externalise these dependancies from all of your modules.  After doing this if you run the script again you should find that these classes are not duplicated.  The first obvious choice for RSLs are the framework, RPC and visualisation RSLs, as these are provided ready to use (see this). It is vital that you externalise any RSLs for SWFs you load, be that compiled style sheets or modules.  To do this use the -external-library-path argument, or in Flex Builder in the project properties set the link type to external.  You can do this with Flex ant as follows:

<mxmlc ...>
   <external-library-path dir="path/to/lib_directory" includes="parlsey.swc"/>
</mxmlc>

It may be a matter of trial and error, but by looking at your link reports you can learn a lot about the classes included in your application and how this affects your file sizes.  Keeping an eye on these statistics over the lifetime of your application is vital so that you can see when things change and understand how to put them right.  A class that is compiled in more than once isn't necessarily a bad thing, you shouldn't expect to see a list of classes where there is only one occurrence of each.  Using RSLs adds a startup overhead of both time and memory.  If you only use 10% of the classes in a library you are undoubtedly better to compile in a few duplicate classes across your modules rather than load the whole library as an RSL at startup.

No comments:

Post a Comment