Wednesday, March 25, 2009

Followup on Stateful Skinning

We got in touch with Adobe about our problems with stateful skinning. Their response was that all the enter frame handlers are necessary for, "tracking size changes, states, playing transitions, and the general overhead involved with implementing IUIComponent." They gave us a special version of the UIMovieClip class that removed logic for handling size changes since that's not necessary in skins. However, even with this change the state-based skins still took up far too much CPU for us to use them in production. In the end we moved to old stateless skins and now our application idles ~10% CPU usage, as is more typical for AIR applications. The take away message: state-based skins are really cool, but they probably aren't suitable for use in applications that are expected to be left open while the user does anything else on their computer. They probably aren't ever suitable for large applications, either.

Thursday, March 5, 2009

Flex Component Kit: CPU black hole

On a recent AIR project we tried to use state-based skins using the Flex Component Kit, as recommended by Adobe. This route was much cleaner and faster than the old, stateless method. And everything seemed great at first. However, as the app grew we noticed that our CPU usage while idle was getting ridiculous (70-80%) and made the disturbing discovery that removing our CSS allowed our CPU usage to plunge back to standard AIR levels (5-10%).

With a little more research we determined that the stateful skins seemed to be the culprit, so we created a simple test program to test our theory. In this program we have a single MXML component that is a standard WindowedApplication component that contains 500 checkboxes. We put together a simple checkbox skin with the stateful method and another that is stateless.

To establish a baseline we ran the application without loading either CSS file. The resulting CPU usage was within the typical range for AIR applications (5-10%). The 500 boxes themselves did not seem to add any CPU usage, as expected.

Then we loaded the stateless skin's CSS file and saw identical CPU usage. Again the behavior was what we expected -- skinning does not add any extra CPU usage. Since there is no activity or animation on our check boxes, having a skin loaded should not require ongoing computation. So far so good.

Finally, we launched the application loading the stateful CSS and this time our CPU usage was a staggering 50% and it stayed there. We ran the profiler to see what was going on. A few seconds after the application started we saw 377 EnterFrameEvents, which is quite a few but not drastically more than other calls in the application. 40 seconds later the count was 5190. Clearly something in the stateful skinning was causing our application to redraw continuously.

Now that we had established that the stateful skinning was the problem we wondered whether it was something about our SWC itself or if it was something about each individual skin. To test this we ran the application with different numbers of checkboxes. Running with 100 boxes we saw a CPU usage of 19% -- twice that of a normal application, but still relatively low. 250 boxes used 30% CPU, and, as noted above, 500 boxes used 50%. This seems to indicate that there is some error in each skin. We didn't see our checkboxes animating through states, so the state separation seems to be working correctly. There is something in each state's generated skin that doesn't stop playing once its drawn.

This discovery explains why a Google search doesn't turn up a myriad of complaints about Adobe's new recommended workflow -- the average application probably doesn't have hundreds of skinned components instantiated at once. Many applications probably have 100 or fewer, meaning that their increased CPU usage may not have set off any red flags. Furthermore, many applications include running animations or additional processing which would take the blame for increased CPU usage. No matter the reason, it appears that this bug has largely gone unnoticed but can have devastating effects on large applications. Hopefully Adobe will have a fix out quickly, otherwise it will be back to stateless skinning misery for us.

Read more about stateful skinning from Patrick Hansen, one of the designers at EffectiveUI who worked on this project with me.