Migratory Foul: Performance Problems Migrating From Flex 3.x To Flex 4.x

Some folks migrating 3.x projects to 4.x have run into noticeable
performance degradation, especially if they are using the default skins that
ship with each SDK. This article attempts to explain why and propose
alternative implementations.

The main reason for the difference is that the the default skins/theme for
4.x is Spark and the default skins/theme for 3.x is Halo. Spark skins are
simply not as fast as the Halo skins. The Halo skins are written as highly
optimized ActionScript and are based on a lightweight Flex class called
ProgrammaticSkin. And partly because of those optimizations, the way you
would write or modify a skin for a MX Button could be drastically different
than the way you’d write a skin for MX DataGrid or MX ComboBox.

In Spark, we wanted a consistent approach to writing every skin. And we
wanted interoperability with the MX components. For reasons like that, the
Spark skins are based on a Skin class that in turn is based on UIComponent.
That instantly makes your skin heavier and slower than a Halo skin. Then,
we wanted every skin to be written in MXML so that the tools can more easily
understand the parts of the skin and assist in the modification and
development of a skin. Most folks know that MXML tends to be slower than
ActionScript, but we chose MXML to enable non-programming designers to be
involved in the skinning workflow without those designers having to worry
about mucking up a bunch of ActionScript code.

The cost per-skin of this extra weight is on the order of a few milliseconds
per skin, but it adds up. A recent test case was putting 250 checkboxes on
the screen. A somewhat unrealistic case since it is hard to cram 250
checkboxes on a screen and make it usable, but it took another 500ms in the
debugger player so the developer noticed right away when he went from 3.x
with Halo to 4.x with Spark. Even if the goal was 100 checkboxes, the extra
200ms would cause some animation to freeze noticeably.

Now, if you are migrating a 3.x project for which you have already written
your own custom theme based on ProgrammaticSkin and you are going to use the
same theme in 4.x, you shouldn’t see problems of this magnitude. It really
has only been an issue when you were using the Halo theme and you now try to
use an MXML-based theme like Spark. So what should you do? Consider not
using MXML-based themes for now. We are looking at ways to optimize an
MXML-based skin hopefully in time for our 2012 releases so hopefully this is
just a short-term issue. We must admit, though, that it is enough of an
issue that the mobile theme for the new mobile components in Flex 4.5 are
written in ActionScript and not in MXML, and that’s why we’re working on
MXML skin performance post-Flex 4.5.

You have choices: You can only swap in ActionScript-based skins for a few
components, or swap in a whole theme. Just replacing the Spark MXML
checkbox skin with the Halo checkbox skin (but leaving the Application and
other skins as MXML-based Spark skins) made a huge difference in performance
since the majority of work was in those 250 checkbox skins that were being
drawn.

Another new capability of Flex 4.x that can cause noticeable performance
degradation when compared to a 3.x application is what we call Advanced CSS.
In Flex 4 we support more CSS selector types but they require more
processing and less caching. If you create enough components in one chunk,
you might notice the extra time spent. We are looking at optimizations
post-Flex 4.5 as well. You can turn off Advanced CSS by setting the
compiler’s compatibility-version flag to 3, but that turns off lots of other
things as well and makes it harder to incrementally add or swap in Spark
components.

It is possible to subclass components and turn off Advanced CSS
for entire classes of components. The following link shows how I turned off
Advanced CSS in a subclass of CheckBox.
Download Sample Source

In analyzing these test cases, it became apparent that the “natural” way to
build up display object “trees” in ActionScript is not the most optimal in
terms of performance. Lots of folks dynamically create dialogs and other
sub-sections of their UI via code like this:


var loginUI:VBox = new VBox();
var loginText:TextInput = new TextInput();
loginUI.addChild(loginText);
var loginButton:Button = new Button();
loginUI.addChild(loginButton);
app.addChild(loginUI);

It turns out this is terribly inefficient compared to this almost identical
code:


var loginUI:VBox = new VBox();
app.addChild(loginUI);
var loginText:TextInput = new TextInput();
loginUI.addChild(loginText);
var loginButton:Button = new Button();
loginUI.addChild(loginButton);

All I did was addChild the outer container before adding its children. In
other words, it is faster to parent the parent before parenting the
children. Why? Because the CSS style calculations that involve inheriting
styles cannot be calculated until you have a parent. So in the first
example, when adding the TextInput and Button to the Vbox, a bunch of
temporary work gets done that gets tossed and re-done when the Vbox is
finally added to the child. If you use the second pattern, the CSS style
calculations don’t have to do any temporary, throw-away, work. It turns out
if you look at the code generated for an MXML file, you’ll see that parents
are parented before parenting their children. In the 250 checkbox cases,
the code was using the first pattern. By changing it to the second pattern
(and using the Halo theme) the test case on 4.x actually runs faster than
the 3.x test case. Yes, if the same optimization had been done on the 3.x
test case then 3.x would still be faster, but there is less degradation for
the second pattern because that is the common MXML-generated path and some
work was done to optimize it. Another new feature of 4.x is per-module
styles and the overhead of that capability (which had the main benefit of
greatly reducing probability that modules will get stuck in memory) carries
less penalty if you parent the parent first.

Remember that the underlying Flash Player is a deferred renderer. Adding an
empty Vbox to the app first won’t cause it to show up on the screen until
the rest of the code finishes running so there is no danger of flicker or
other visual artifacts.

In conclusion, if you are seeing performance degradation when migrating from
3.x to 4.x, and it is related to these topics in this article, then it was a
decided trade-off we made to involve designers in the development process
and produce better user experiences, or provide more CSS capabilities, or
reduce the chance memory leaks. But you can choose to use ActionScript
skins, do some subclassing to turn off Advanced CSS on components that are
created often, and build your dynamic UI more optimally and reduce the
degradation or in some cases, get even better performance than what you had
experienced in 3.x.