Archive for March, 2009

Mar 26 2009

Exploded Schematic View of Flash and Flex Apps

Published by Corey under Technology, Toys

I am not sure who wrote FlexSpy back in the day but it struck me that such a tool could benefit from an interactive schematic view of the display list it’s introspecting. If anything it’s useful to see sometimes just how a component or UI is composed.

 

Included along with this post is a sketch (proof of concept) I put together over coffee this morning. Give it a run (just click on the image below to launch the sample, requires Flash Player 10):


LayoutSchematic

 

Initially you’ll see a vanilla Flex 4 dialog based UI. Push the ‘E’ key and the UI will transition to an interactive exploded view of the display tree. Push ‘E’ again to tuck things back where they started.

 

I’d imagine the approach would work with any 2D Flash or Flex content, though it really doesn’t make much sense with 2.5D centric apps. The basic idea is to just walk the display list and assign an appropriate z value to each depth level. I’ve offset siblings so they can be differentiated a bit, and injected a surrogate parent for the application so that I can adjust the registration point of the main application itself.

 

I have some ideas for use cases but I’d prefer to leave it to your imagination. The source is included in the SWF, please use at your own risk. If anyone feels like continuing to play with it please do, just let me know what other interesting ideas you come up with.

There are certainly bugs. When returning to the default 2D view for example, most nodes end up with zombie matrix3D instances, which cause Flex a few headaches and make the UI appear anti-aliased. As I have time I may toss a few fixes into the sample.

4 responses so far

Mar 25 2009

Some System.gc() and System.totalMemory Tips

Published by Corey under Technology, Work

When profiling a Flash or Flex application it’s sometimes useful to explicitly request that the player VM perform garbage collection. When used correctly this can help identify and track down memory leaks.

Some quick tips:

  • System.gc() is asynchronous! I can’t tell you how many times I’ve seen developers make the call to gc() and then immediately query System.totalMemory! I’ve also seen people call it twice in a row (just to make sure it sticks ??) . Internally System.gc() simply queues up a garbage collection pass for the next frame interval. So make sure you query totalMemory on the next frame (listen for enterFrame), or use callLater if within a Flex application.
  • System.gc() only works in a debugger player, and is a noop in the release build of the player. If you must do release mode profiling (which I highly recommend), you can utilize a well-known hack to force the player to garbage collect. Of course you do not want to make use of this in a production application, and the usual disclaimer applies, specifically this hack is not guaranteed to work in future versions of the player runtime.
     

    Keep in mind that the release mode GC hack is in fact synchronous, however in this case the internal player code also queues up additional collection for the next frame interval so it’s best practice to wait a frame even then, such that anything pinned in memory due to just being on the callstack can be cleaned up.

  •  
    1
    2
    3
    4
    5
    // Release mode gc().
    try {
        new LocalConnection().connect('_noop');
        new LocalConnection().connect('_noop');
    } catch (e:*) {}
  • System.totalMemory does not reflect all of the memory the player instance allocates. totalMemory is useful in most cases, since it reflects all of the memory that the internal player’s custom allocator has been asked to allocate for the bulk of the internal player constructs (inclusive of all script objects). Keep in mind however that not everything allocated in the player is allocated by the internal allocator, nor reported through totalMemory…namely anything allocated by OS system calls, memory associated with platform bitmap data, and the JIT buffer associated with the Actionscript VM.
     

    At times it’s useful to make use of other tools to glean the total memory used by the player. I recommend testing within a standalone release player and leveraging Process Explorer and its ‘private bytes’ metric when on Windows, or Activity Monitor’s ‘private memory’ metric on OS X. Steer clear of Task Manager, as it incorporates uncommitted virtual memory that may or may not be used and is lazily reclaimed by the OS.

     

    The next major release of the player will provide a new API which will more accurately reflect the cumulative memory in use by the player.

  • Not all players and SWFs are created equal. Memory usage of a debugger player rendering a debug SWF will be significantly higher than the same player rendering a release build of the same SWF. It also holds true that the memory usage of a debugger player rendering a release SWF will be significantly higher than a release player rendering the same release SWF. So long story short, it’s always best to do your profiling and performance testing in a release player (against a release SWF) when at all possible.

3 responses so far

Mar 25 2009

Player 10 Performance Gotcha - Sneaky Surfaces

Published by Corey under Technology, Work

When optimizing a production application, regardless of the SDK or technology used to build it, it’s important to understand the performance characteristics of the various APIs, primitives, and data structures that make up your SDK. When becoming proficient with a given platform it’s inevitable that you stumble upon nuances, inefficiencies, or just plain bugs…and over time your learn to “work with” (or around) said limitations.

Here’s one of the “plain ol’ bugs” you should be aware of when scrubbing your Flash or Flex application of performance issues.

Take the following code snippet towards the end of this post… Pretty simple, just creates a couple hundred Sprite instances, applies a quick opaque fill, and adds them to the stage. Taking a look at System.totalMemory, memory increases by about ~500K. Nothing mysterious.

Now, imagine we were to ask the player to cache each Sprite instance as a bitmap, e.g. via:

    currentSprite.cacheAsBitmap = true;

So for 250 display object instances, one would expect that the resulting ~ 3MB of memory usage sounds about right (32 bpp RGBA buffers). Again, nothing mysterious.

  

Now, let’s run the same test, but instead of setting cacheAsBitmap… what if we simply read the value of cacheAsBitmap for each Sprite instance:

    var test:Boolean = currentSprite.cacheAsBitmap;

Whoa! Again, we see ~ 3MB worth of surface allocations! For simply reading the property?!

Beware, this issue also affects a few other properties, some that may make it even more likely you’ll run into this… For example, simply asking a display object whether or not it has a scrollRect will cause a back buffer to be allocated for that object. Testing the opaqueBackground property also results in a similar fate.

Note: The problem as described currently affects the production Player 10 versions (10.0.12.36 and 10.0.22.87). The issue itself has been addressed and should be taken care of in the next non-incremental release of the player. Just tread lightly. :)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical"
    creationComplete="updateMem()">
 
    <mx:Script>
    <![CDATA[
        [Bindable]
        private var totalMem:String;
 
        private function startTest():void
        {
            for (var i:int = 0; i < 250; i++)
            {
                var currentSprite:Sprite = new Sprite();
                currentSprite.graphics.beginFill(0x000000);
                currentSprite.graphics.drawRect(0,0,300,100);
                currentSprite.graphics.endFill();
               
                // Uncomment to allocate surfaces for each Sprite instance (+ ~3MB).
                //currentSprite.cacheAsBitmap = true;
               
                // Uncomment to (surprisingly) take the same surface hit (+ ~3MB)
                //var test:Boolean = currentSprite.cacheAsBitmap;
                //var test2:Object = currentSprite.scrollRect;
                //var test3:Object = currentSprite.opaqueBackground;
               
                canvas.rawChildren.addChild(currentSprite);
            }
            System.gc();
            callLater(updateMem);
        }
       
        private function updateMem():void
        {
            totalMem = String(System.totalMemory / 1024) + " KB";
        }
    ]]>
    </mx:Script>
 
    <mx:Canvas id="canvas" width="300" height="100" />
    <mx:Button label="Start Test" click="startTest()" />
    <mx:Label text="Total Memory: {totalMem}"/>

</mx:Application>

One response so far

Mar 24 2009

Improving Perceived Layout Performance in Flex

Published by Corey under Technology, Work

The Problem

For a typical browser-based Flex application, as the brower is resized by the end user, it’s very common to see the Flex content lag behind the browser frame. As the Flex app is resized very often you can see the Stage background paint, before the Application background can catchup.

Take the following example SWF (click to open):


Layout Sample

After launching the sample, resize the browser frame quickly left and right, and up and down from the bottom right corner of the browser chrome. You’ll notice that along the right and bottom edge of the viewport, the green stage background can be seen, as the content tries to keep up with the resize events. This “lag” is most commonly seen on Mac OSX 10.4 and later when running in the standalone Flash 10 player, Safari, or Firefox. On Windows, the lag is most commonly seen within the Firefox browser, but depending on your hardware configuration, can also occur in IE, AIR, and the standalone player.

The Solution

Whenever the player Stage is resized, the Stage issues a ‘resize’ event. In Flex, our top level Application object listens for the resize event. When it’s received Flex invalidates the display list, then queues up a layout request. Only later, when we eventually receive a ‘render’ event from the Stage, or an ‘enterFrame’ do we actually layout and update our display list.

Flash delivers stage resize events pretty much in lock step with the browser or parent container, but render and enterFrame events are tied to the player’s natural update interval. Since Flex waits until the following update interval to actually paint, we’ll always see this lag.

In the sample above, I’ve added a checkbox, which when enabled, demonstrates a smoother resize approach. Essentially we just ensure that we ‘validate’ our display list upon receipt of every Stage resize event. The solution is to ensure that when our root application is resized, that we follow suit with a validation (layout) as soon as we can, rather than deferring as is the typical case when child elements are resized on their own. Perceived performance can be greatly enhanced.

The Catch

Why don’t we make this change within the core SDK itself? Unfortunately, there’s a catch - an existing player bug we would have to work around, primarily on Windows. When the plug-in version of the player has its WMODE rendering mode set to “transparent”, or any other non-default value for that matter, display list corruption with TextFields can occur (specifically those using system text). When WMODE is set to transparent for example, and TextFields are present in the display tree, the raster representation of these text elements becomes visibly corrupt when they are moved and updated within a Stage resize event handler. A player bug is logged and the issue is being addressed.

In the mean time, if you know your interactive will never be using a non-standard WMODE, feel free to take the approach outlined. The results will be a much smoother, more responsive layout experience in most cases. Some cookbook code follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?xml version="1.0" encoding="utf-8"?>

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
    applicationComplete="appComplete();">

    <mx:Script>
        <![CDATA[
           
            private function appComplete():void {
                stage.addEventListener(Event.RESIZE, onStageResize);
            }

            private function onStageResize(e:Event):void
            {
                validateNow();   
            }
        ]]>
    </mx:Script>
</mx:Application>

2 responses so far