Understanding Flash Player with Adobe Scout
22 January 2013
Adobe Scout is an incredibly powerful tool for optimizing your Flash content, because it lets you see what's really going on behind the scenes in Flash Player. But having this information is most useful if you understand why Flash Player does what it does. Only then can you efficiently figure out how to fix the problems that Scout tells you about!
The purpose of this article is to give you a basic understanding of how Flash Player works, and to relate this to the information you see in Scout. It's also a reference guide to the terminology used by Scout, so that you can look up the meaning of the different activities performed by Flash Player. If you've used Scout and thought "I can see I'm spending too much time doing x, but what does x mean?", then this article is for you!
Note that this isn't a guide to the user interface of Scout. If you don't know how to use Scout, or what the different panels do, then you should begin by reading the getting started guide.
An overview of Flash Player
Flash Player is like a personal assistant in that it arranges complicated stuff on your behalf, and acts as an interface between you and the real world. But Flash Player can't do anything useful by itself–it needs you to tell it what to do! There are two ways of doing this:
- Timelines, authored in Flash Professional. These are frame-by-frame animations, which are represented as a series of tags. Tags are simple instructions that describe what to do in each frame, like moving objects around the screen. Everything that you do visually in Flash Professional, like adding an object to a frame or setting up a tween, gets encoded as a tag in the SWF file.
- Scripts, written in pure ActionScript. These are executed by Flash Player at certain points in time, for example when a SWF is loaded, a timer fires, or a mouse click occurs. You can also attach scripts to individual frames in Flash Professional.
When Flash Player executes your scripts, or the tags in your timeline, they tell it to perform various activities. These can be roughly classified into four types:
- Immediate activities. These are tasks that you tell Flash Player to do straight away, and your content won't continue executing until the operation has finished; for example, creating a new bitmap or initiating an HTTP request.
- Ongoing activities. After you initiate these tasks, Flash Player continues to perform them in the background until they finish or you stop them. Examples include playing a sound or downloading a file.
- Deferred activities. Some operations that you perform in a script or tag don't appear to do very much, but cause Flash Player to schedule a bigger operation sometime later. For example, changing the position of a display object will mark it as "dirty", meaning that sometime later it has to be re-rendered by Flash Player.
- Implicit activities. These are in-built operations that Flash Player does without you having to request it, such as garbage collection, or receiving mouse and keyboard events from the operating system.
It's important to keep this in mind as you're reading this article. Flash Player isn't just about executing ActionScript; it does many other activities too! If you think of Flash Player as your personal assistant, then executing ActionScript is like being in a meeting. Even if it's a really short meeting, Flash Player still has to go off afterwards and do all the paperwork you gave it. Rendering your fancy animation takes time, and much of the actual work happens outside of your ActionScript!
Player instances and sessions
You may be wondering how Flash Player manages the execution of all these different activities.
When you run Flash content in a web browser, Flash Player typically runs in a separate operating system process. There's only one process for all the SWFs running in that browser, including any related worker threads, and Flash Player manages the execution of these SWFs so that it looks like they're running independently. Each running SWF is known as a player instance, and this corresponds to a session in Scout. Worker threads are player instances too. For AIR content, there's only one main player instance, plus any workers it uses.
Execution of a player instance
As Flash Player runs, it switches between different activities. It might do a little script execution, then some video playback, then render some graphics, and so on. The exact mix depends on what events are happening, what ongoing activities are in progress, and what activities have been requested by the SWF's scripts and timelines. While all of this is going on, Flash Player keeps a record of what it does, and measures the resources it consumes, including CPU time, CPU memory, and GPU memory. These measurements are sent to Scout, so that you can see what's going on. To keep the overhead of these measurements to a minimum, Flash Player only measures and reports activities that take a significant amount of time or memory.
At the most basic level, Flash Player can be in one of two modes at any moment in time:
- Active – it's doing something productive, which could be anything from executing ActionScript, to rendering, to handling a mouse event.
- Inactive – it's having a tea break (disclaimer: do not pour liquids onto Flash Player). It could be blocking on some external condition, like the GPU, or it could have simply run out of work to do.
In Scout, the total time (the sum of active and inactive time) is indicated by the grey bars in the Frame Timeline. To make it easier to visualize what proportion of time Flash Player spends doing different types of activity, Scout breaks down the active time into four top-level categories:
- ActionScript (blue) – the time spent executing ActionScript code, and inside ActionScript APIs.
- DisplayList Rendering (green) – time spent performing operations on the display list, such as rasterizing and drawing to screen. Note that this doesn't include Stage3D rendering, which uses a different ActionScript API.
- Network and Video (yellow) – time spent downloading via the network, and streaming and decoding video.
- Other (orange) – time spent doing everything else, such as garbage collection, processing events, and parsing SWFs.
It's important to understand that Scout shows you elapsed time, and not CPU time. Think of Flash Player as sitting there with a stopwatch, timing each activity. If the operating system interrupts Flash Player in the middle of the activity, and lets another application run for a while, then Flash Player will measure a longer elapsed time. To get the most accurate data, you should close other applications while you're profiling with Scout.
The beating heart of Flash Player
Many Flash applications, especially games, do a great deal of graphical animation. The basic principle is to redraw the screen at a certain frequency—for example 60 times per second—so it looks like a smooth animation. To help you with this style of programming, Flash Player has a core concept of frames. Deep inside the player, there's a beating heart—a timer that fires at a certain frequency called the framerate. The time in between these heartbeats is called a frame. You get to decide the framerate you want your content to run at. It's a property of your SWF, and you can dynamically change it from ActionScript while the SWF is running.
A common way of programming is to register an event handler for Event.ENTER_FRAME, the event that corresponds to the heartbeat and the beginning of a new frame. If you're writing a game, you can use this event handler to do all the periodic work needed to keep the game running. For example, you can process any inputs from the user, update the game state using your physics engine, and finally render the updated scene.
When you're profiling with Scout, the Frame Timeline shows you how long Flash Player spent executing each frame. Consider a game for which you want to achieve a framerate of 60 frames per second (60fps). There are 1000 milliseconds (ms) in a second, so you have a budget of 1000/60 = 16.7ms per frame. If, on average, each frame takes longer than this, Flash Player won't be able to run at the framerate you requested, and your content might look slow and jittery. In Scout's Frame Timeline, the budget is shown as a horizontal red line, and the grey bars represent the total time taken by each frame.
Within a frame, Flash Player has many different activities to perform. One of the first things it does is to dispatch an Event.ENTER_FRAME event and call any registered event handlers. As it executes your ActionScript code, this might cause new deferred or ongoing activities to get added to the "todo list", like redrawing part of the screen or starting a new file download. These have to get executed sometime later on during the frame. Also, mouse, keyboard, and other events might happen during the frame, and these need to get processed and handled. Eventually, Flash Player will finish all its tasks for the frame and have nothing left to do. It then sits and waits for the next heartbeat, so it can start all over again with a new frame!
In Scout, the main thing to watch out for is a colored bar that crosses the red line. This means that Flash Player took longer than the entire frame's budget to do everything it needed to do. In other words, Flash Player had too much work to do in its allotted time! If all the frames consistently go over the budget, then your content will generally slow down (see Figure 1), whereas if you get lots of erratic spikes, your content will be jerky.
Figure 1. Content consistently failing to meet its target framerate
Note that even if you finish the frame in good time, Flash Player will always wait before starting the next frame. This is a good thing—it means that your content isn't hogging all the resources on the device, which reduces power consumption and gives the CPU time to carry out other tasks. It also means that your content has slack built into it, so that it can still run at the target framerate on a slower device. It's completely normal for the grey bars to hover around the red line (see Figure 2).
Figure 2. Content running smoothly at 60fps
There are a few subtle things about frames to be aware of:
- The maximum framerate of Flash Player is capped at 60fps. Setting a higher framerate won't allow your content to go any faster than this. Remember that most monitors don't support more than 60fps, so trying to update the screen faster than this is a big no-no!
- Flash Player tries to play nicely with the operating system. There can be lots of player instances running when you browse the web, and these can all have different framerates. Rather than waking up at random times and slowing down your computer, Flash Player tries to synchronize the wake-up times of the different player instances. Roughly speaking, it wakes up every 60th of a second, and kicks off a new frame in any player instances that are ready. This means that if you set your framerate to something that doesn't divide evenly into 60, like 24fps, then you'll see the grey bars oscillate around the red line–sometimes above, and sometimes below (see Figure 3). This is normal, and it's not a problem as long as you meet your target framerate on average (you can select a range of frames in Scout to see the average framerate).
- If you see in Scout that the grey bars are consistently above the red line, even though the colored bars (the active time) are always below it, then you probably have other applications running on your computer that are using up CPU resources. Try shutting down other applications and browser windows.
Figure 3. Content running smoothly at 24fps
Components of Flash Player
Now that you have a better understanding of the basic structure of Flash Player, it's time to dive a bit deeper into the data that you see in Scout. You'll notice that the Top Activities and Activity Sequence panels give a detailed breakdown of what Flash Player is doing. The descriptions in these panels are designed to be as self-explanatory as possible, but sometimes you need a bit more information to get to the root of the problem. This section groups the different activities of Flash Player into functional areas (see Figure 4), and provides a more detailed explanation of what they mean.
Figure 4. Structure of Flash Player
You can use this section as a reference guide when using Scout, and just read the parts that are relevant to your problem. Alternatively, you can read the entire section to learn a bit more about how the different parts of Flash Player work.
ActionScript 3 and event handling
ActionScript is the language of Flash; it lets you tell Flash Player what to do. When you build a SWF, your ActionScript code gets compiled into a lower-level language called ActionScript bytecode that Flash Player can understand. This bytecode then gets executed by the ActionScript Virtual Machine (AVM), while your SWF is running. The AVM implements certain core features of ActionScript, including garbage collection and exceptions, and also acts as a bridge between your code and Flash Player.
You can interact with Flash Player from ActionScript using APIs. To you these look like normal function calls, but under the hood you're often calling native C code, where all the magic happens! In Scout, these APIs show up as normal function calls in the ActionScript panel, so you don't have to worry about the internal details. If you're spending too long in an API call, you should either call it less often or give it less work to do (by reducing the size or complexity of the arguments).
As well as invoking Flash Player from ActionScript, you need to tell Flash Player when to execute your code. Most of the time, this is done using event handlers. These are functions that you register to get called when a specific event happens. You can create custom events, and call them manually using EventDispatcher.dispatch() , but you'll often want to listen for external events, like mouse movements and key presses. There are a number of activities in Scout that relate to this:
- Handling event "<name>" – Flash Player is always listening for and receiving external events from the operating system. When it receives an event, it first has to do some processing, and then figure out which event handlers it should invoke (for example, on keyboard events, the handler to invoke depends on which object has keyboard focus). Some external events that you'll see in Scout are:
- Keyboard events: keyDown , keyPress , keyUp .
- Mouse events: mouseDown , rightMouseDown , mouseMove , mouseUp , mouseWheel .
- Touch and gesture events: touch , gesture .
- Window events: resize , mouseLeave , foreground , background , fullScreen , fullScreenInteractiveAccepted , visible .
- Event "<name>" – this is the actual ActionScript event handler for the event <name>. You'll only see this if you created and registered an event handler (this applies to any event, not just the ones listed above). Here's a handy tip: Click on an event in the Activity Sequence or Top Activities panel in Scout to filter the ActionScript panel to show only the code that was executing in this specific event handler.
Timers are handled much like external events, except that you set them up yourself:
- Handling event "timer" – dispatching a TimerEvent.TIMER event to any registered handlers.
- Timer started: <interval> – indicates that a timer has been started, with a delay of <interval> ms between timer events.
There are also a number of AVM activities that are related to executing your code and supporting the language features of ActionScript:
- Garbage collection – unlike C and other languages that need explicit memory management, ActionScript takes care of the allocation and freeing of memory for you. Periodically, Flash Player runs a garbage collector to scan for any objects that are no longer being referenced (nothing has a reference to them), and free the memory they're using. If your content spends a significant amount of time doing garbage collection, it's an indication that you're creating too many objects. You might want to try caching or pooling objects to avoid creating new instances all the time.
- Trace: <output> – this gives you the output of any trace() statements in your ActionScript. You can also view this data in the Trace Log panel.
- Exception: <class> – this gives you the stack trace for any exceptions that happen while your ActionScript is executing. This shows up even if the exception was caught and handled, so seeing this in Scout doesn't necessarily mean that there's a problem with your code.
- Handling uncaught error – dispatching an UncaughtErrorEvent.UNCAUGHT_ERROR to any registered handlers.
Finally, there are some activities that you'll see if you invoke ActionScript 3 code from other languages:
- AVM Bridge callback – a call from ActionScript 2 to ActionScript 3 code.
If you use ActionScript workers in your content, they'll appear as separate sessions in Scout. Under the hood, they're really just separate player instances, with an API for sharing data between them. Support for workers in Scout is currently a beta feature. To enable support, you'll need to do the following:
- In Scout, go to Preferences > Beta Features, and select Start Sessions For ActionScript Workers.
- In the sidebar in Scout (if it's not visible, go to Window > Sidebar), make sure that ActionScript Sampler is enabled.
- Make sure your content has opted-in to advanced telemetry (see the getting started guide if you don't know how to do this).
For content that uses ActionScript workers, you might see the following activities in Scout:
- Running Worker code – if you launch a worker, and continually run some ActionScript in it (the worker executes a single long-running function, rather than being event-driven), you'll see this activity in Scout. It means that you're still in the top-level entry point for the worker, so it doesn't correspond to any event.
- Waiting for Condition – blocking on a call to Condition.wait() .
- MessageChannel.receive – blocking on a call to MessageChannel.receive().
- MessageChannel.send – blocking on a call to MessageChannel.send().
- Mutex.lock – blocking on a call to Mutex.lock().
- Mutex.trylock – blocking on a call to Mutex.trylock().
In addition to the built-in measurements that Flash Player makes, you can send custom data to Scout using the Telemetry API. The two main calls are as follows:
Telemetry.sendMetric(name, value) – this reports a name-value pair to Scout, which will show up in the Activity Sequence panel. For example, if you call Telemetry.sendMetric("UserID", 2) , you'll see "UserID: 2" appear in the Activity Sequence panel at the time the code gets executed.
Telemetry.sendSpanMetric(name, startTime, value) – this reports an activity to Scout, with an optional value. You record the start time by looking at Telemetry.spanMarker , and then pass it to Telemetry.sendSpanMetric at the end of the time period you want to measure. It'll show up in Scout in both the Top Activities and Activity Sequence panels.
For more details, and some examples of how to use this, see the documentation for the Telemetry API.
At the core of Flash Player is the frame ticker–the heartbeat that pulses whenever it's time for a new frame to start. At the start of each frame, it executes any timeline tags, invokes any frame scripts on the timeline, and dispatches a few key ActionScript 3 events. The activities of the frame ticker are as follows:
- Running SWF tags for frame – Flash Player executes the SWF tags associated with the frame. This usually corresponds to things you did in Flash Professional; for example, creating the objects you attached to a frame, and moving them around according to your tweens.
- Running frame actions – these are the scripts you attach to a frame on a timeline using the Actions panel in Flash Professional. The script could be ActionScript 2 or ActionScript 3. In the case of ActionScript 3, it might not get executed immediately, but be placed in a queue that Flash Player executes before the frame ends.
- Running AS3 attached to frame – executing any ActionScript 3 code that was queued when Flash Player ran the scripts attached to a frame on the timeline.
- AS2 event "enterFrame" – the MovieClip.onEnterFrame event handler in ActionScript 2.
- Handling event "enterFrame" – when a new frame starts, Flash Player looks for any registered handlers for Event.ENTER_FRAME and invokes them.
- Handling event "frameLabel" – when a new frame is entered, if the frame has a FrameLabel object with a registered handler for Event.FRAME_LABEL , its handler gets invoked.
- Handling event "exitFrame" – just before the current frame ends, Flash Player looks for any registered handlers for Event.EXIT_FRAME and invokes them.
Display list rendering
The display list is the classical approach to rendering in Flash Player. Basically, you get given a blank canvas called the stage, and you draw to it by attaching and positioning graphical entities called display objects. There are different types of display object, including vector art, bitmaps, and text, and they can be nested hierarchically to build up a complicated scene. Whether you interact with display objects from ActionScript, or by positioning them and setting up tweens in Flash Pro, you don't have to worry about how they're actually rendered. Flash Player does the hard work for you, figuring out how to convert the display list into the actual pixels you see on your screen.
If you're using ActionScript to manipulate the display list, you'll notice that there are several APIs you can call to make changes. You can think of these changes as immediate activities. When you call an API, it modifies the internal state of the display list straight away. What it doesn't do is immediately modify what you see on the screen! Instead, Flash Player marks any display objects that you modify as dirty, meaning that they need to be redrawn. Sometime later, after your code has finished executing, Flash Player performs a rendering pass. Effectively, it collects all your changes together, so it only has to update the screen once. You can think of it like stop-motion animation. During a frame, you go around tweaking all the little clay figures, and after you're finished, Flash Player takes the photograph of the scene for that frame.
Figure 5. A rendering pass in Flash Player
Here's what a rendering pass looks like in Scout (see Figure 5):
- Calculating dirty regions – the rendering cycle starts by scanning through the display list, looking for any objects that have been marked as dirty (for example, they were moved around). It then generates up to three rectangles that contain all the dirty objects. These are the areas of the screen that need to be redrawn. You can see these in the DisplayList Rendering panel in Scout, as the red regions.
- Rendering dirty region – for each of the dirty regions, Flash Player has to figure out what the new pixels should be. It does this by constructing the scene in an internal buffer, called the display buffer. There are a few steps involved in this process:
- Building edges from DisplayObject – Flash Player scans through the display list again, looking for display objects that overlap the dirty region. For each one it finds, it breaks it down into a set of edges and fills (these can be solid colors, gradients, or bitmaps defining how the spaces between the edges are colored in). If the display object contains other display objects, this same process gets recursively applied to them. Essentially, Flash Player flattens out your hierarchical scene into regions of different fills.
- Rasterizing edges – Flash Player now has to convert the edges and colors into actual pixels. It divides the dirty region into horizontal lines called scan lines, one for each vertical pixel. The scan lines get shared out among the cores on your machine. Flash Player walks along each scan line, figuring out what color to shade each pixel, based on the fill for the area between the edges that bound it. The time this takes depends on the number of pixels, and the cost of drawing each pixel. Solid colors are the least expensive to draw, whereas rotated and scaled bitmaps with multiple layers of alpha blending can be pretty costly!
- Applying filter: <name> – if you've set up any filters, like a glow or a drop shadow, these now get applied to the rasterized image. Except that if a child of a display object has a filter, it has to be applied before the parent object gets rasterized. Flash Player does this by rasterizing the child display object onto a separate surface (shown in blue in the DisplayList Rendering panel in Scout), and applying the filter to that surface. This results in a new bitmap, which is treated as an atomic fill when building the edges for the parent display object.
- Copying to screen – at the end of the rendering pass, Flash Player copies the data from its display buffer onto the screen. This is also known as presentation. The time this takes depends mostly on the number of pixels that have to be copied, but there might also be a delay in obtaining a lock from the operating system. If you're using hardware acceleration this means that the display buffer is already on the graphics card, and Flash Player just needs to tell the graphics card to display it. This should show up as time spent Waiting for GPU (see Some notes on GPU-related performance issues for more information). If it doesn't, check that you're using the latest version of Flash Player (11.5 or later).
If you're drawing complicated shapes with lots of edges and different filters, then rendering can be expensive. Try to modify the display list as little as possible to reduce the number and size of dirty regions that need to be redrawn on each frame. If you're drawing a complex nested object that you rarely modify (except for moving it around), you can improve rendering performance by caching it. This rasterizes the display object to a cached surface, which only needs to be regenerated if it changes. If you only ever translate the display object, set the cacheAsBitmap property. If you also want to rotate and scale it, use cacheAsBitmapMatrix (only supported by AIR on mobile).
Scout shows you the following activities related to cached surfaces (shown in orange in the DisplayList Rendering panel):
- Rendering from cached surface – if a display object has a valid cache, Flash Player uses this rather than building and rasterizing its edges.
- Updating cached surface – if you modify a cached display object or its children, this invalidates the cache, and it needs to be recreated. If Flash Player is spending too much time updating cached surfaces, it's an indication that you're using caching incorrectly. Caching should only be used on display objects that rarely change, otherwise it's faster not to cache!
As part of each rendering pass, Scout will show you additional information for activities performed on certain types of display object. The following activities relate to rendering text:
- Updating text layout – a text display object has changed (for example, changing the
textproperty of a TextElement or TextField object), and needs to be laid out again. This will also mark the display object as dirty, so that it gets redrawn in the next rendering pass.
- Rendering text – rendering text using the TextField class.
- Rendering FTE text – rendering text using the Flash Text Engine classes, in the flash.text.engine package.
The following activities are related to Bitmap objects and manipulating their associated bitmap data (Bitmap.bitmapData ):
- Creating BitmapData – the constructor for a BitmapData object. This only appears in the DisplayList Rendering panel, in Scout.
- Decompressing images – when you load a compressed image, such as a JPEG or a PNG, it needs to be decompressed before Flash Player can display it. If you find that this is taking a long time, you can tell Flash Player to use asynchronous decoding, which decompresses the image at the time it's loaded, using a background thread so it doesn't block your UI.
- BitmapData.copyPixels – a call to BitmapData.copyPixels() .
- BitmapData.draw – a call to BitmapData.draw() .
There are a few additional operations related to display list rendering that you might encounter in Scout:
- Creating Display Buffer – this creates the display buffer into which Flash Player rasterizes the display list. This should normally happen once, at the time the player instance is created.
- Resizing Display Buffer – this adjusts the size of the display buffer, typically in response to a stage resize.
- Triggering UpdateAfterEvent – a rendering pass is about to start, because you called updateAfterEvent() . As a rule of thumb, if you've set a high framerate (like 30fps or 60fps) then you should never need to call this, since Flash Player already does at least one rendering pass per frame.
- Handling event "render" – if you explicitly call stage.invalidate() , an Event.RENDER event will be dispatched to any registered handlers just before the rendering pass starts.
Stage3D is an ActionScript API that sits on top of OpenGL and DirectX, letting you do cross-platform hardware-accelerated rendering. The way this works is quite different from the traditional display list model, although the Starling framework runs on top of Stage3D and provides a similar API to the display list for 2D content. Stage3D content renders to its own display buffer, which appears on screen behind the display list.
The basic structure of the Stage3D rendering cycle is to first set up the state of the GPU (uploading textures, meshes, and shaders that you want to use), and then issue a number of draw calls that tell the GPU to render batches of triangles to the target buffer. When you've finished constructing the scene, you call Context3D.present() to actually display it on the screen. There are two places where actual work happens:
- Inside the ActionScript APIs – the calls you make using the flash.display3D package. To see how long this takes, turn on the ActionScript Sampler in Scout. If you open the ActionScript category in the Summary panel, you can see how much time you're spending in the Stage3D APIs, and the ActionScript panel lets you explore the particular calls that are slowest.
- On the GPU – ultimately it's the graphics card that does most of the work, such as the actual rendering. Scout doesn't currently provide any information about GPU processing times, but you can see GPU memory usage in the Summary panel. If you think your bottleneck is the GPU, see the section below on GPU-related performance issues.
When Flash Player starts up a new player instance, it first has to download the main SWF, parse it, and load it into memory before it can start to execute it. You'll see the following activities related to this in Scout (note that there's considerable overlap with the networking component of Flash Player):
- Loading SWF: <url> – the URL of the main SWF that Flash Player is about to load. You'll see this when running the standalone version of Flash Player.
- Loading file: <url> – downloading the file at the given URL.
- Receiving Loader data – receiving data over the network for the resource you're loading using Loader.load() . Each time data is received, a ProgressEvent.PROGRESS event will be dispatched to any registered handlers.
- Receiving SWF data – receiving some data that's part of a SWF file.
- Receiving image data – receiving some data that's part of an image, such as a JPEG, PNG, or a GIF.
- Decoding SWF file – parsing the SWF data, and decompressing it if needed.
- Closing Loader – closing the network connection used by the loader. This can be due to the load completing, an error occurring, or a call to Loader.close() .
- Preparing ActionScript bytecode – decoding the ActionScript bytecode so that it's in a form that can be executed.
- Initializing AS globals – initializing variables that are defined outside of any function or class definition.
- Handling event "onLoadInit" – the MovieClipLoader.onLoadInit event handler in ActionScript 2.
There are three main types of network operation supported by Flash Player: local connections, TCP/HTTP connections, and streaming media. Whichever you use, you typically begin by setting up a network connection or initiating a request. Network operations take time, so they don't happen synchronously. Once you've requested something, your ActionScript code can perform other tasks, while Flash Player handles the network operation in the background. You can find out when the operation has finished, or get status updates, by registering event handlers for the relevant events.
To enable two player instances on the same machine to communicate (for example, if you've loaded a helper SWF), you can set up a LocalConnection object to let one invoke functions of the other. Scout shows you the following activities related to local connections:
- LocalConnection callback – invoking functionName(arguments) in the receiving LocalConnection object, as a consequence of a call to send(connectionName, functionName, arguments) on the sending LocalConnection object.
- Handling LocalConnection traffic – performing general maintenance of local connections, including sending and receiving any data for a LocalConnection object.
When you want to download content, like images and other SWFs, you typically use Loader or URLLoader objects, which use HTTP. You can also send and receive data from a server using an HTTP NetConnection. Scout shows you the following activities related to this:
- Sending URL requests –requests made over HTTP, for example with NetConnection.call() , are queued up by Flash Player. Periodically, these queued requests get sent over the network.
- URL request timestamp – the time at which a URL request is sent.
- URL request: <url> – the URL that Flash Player is requesting.
- URL request ID: <id> – a unique identifier for the URL request.
- Responder callback – calling one of the functions you passed to the constructor of a Responder object, corresponding to a NetConnection.call() succeeding or returning an error.
- Processing network buffers – general networking overhead, such as iterating through the buffers to see if any data has arrived.
Flash Player also supports a number of protocols for streaming media from a server, like audio and video data. You can create a NetStream using a NetConnection, where you specify the protocol. The Real Time Messaging Protocol (RTMP) runs on top of TCP, and the Real Time Media Flow Protocol (RTMFP) runs over UDP. You'll see the following activities in Scout, related to streaming:
- Receiving NetStream audio/video – receiving a chunk of audio or video data from the server.
- Decoding media from network – decompressing the audio or video data received over the network, so it can be played by Flash Player.
- Receiving NetStream metadata – receiving metadata about the requested media, such as creation time, duration, theme, and so on. You can register an event handler to be invoked when metadata is received by setting the onMetaData property of the NetStream.client object.
- Receiving NetStream commands – processing command messages from the server. For example, these inform Flash Player about the status of commands it previously requested.
- Closing network connection – this can be due to the stream ending, an error occurring, or a call to NetStream.close() .
- Receiving NetStream shared objects – receiving the data for an ActionScript 3 object that's stored on the server (so it can be shared across multiple clients). This can be a consequence of calling SharedObject.connect().
On the majority of desktop computers, Flash Player is efficient at playing sound. Time spent performing sound operations will show up in the ActionScript panel in Scout as calls to functions in the flash.media package, such as on Sound or SoundChannel objects. You might also see the following activity:
- Dispatching Sound Complete – the Sound.onSoundComplete handler in ActionScript 2, or the handler for Event.SOUND_COMPLETE on a SoundChannel object in ActionScript 3.
Video playback in Flash Player is basically a long-running network operation. When you tell Flash Player the video you want to play, it sets off an ongoing activity in the background. Data periodically arrives over the network, is decompressed, and then gets displayed on the screen. The CPU time needed can vary quite a bit, depending on the platform, codecs, and other video settings.
Scout doesn't currently provide much information about your video performance, but you might see the following activity:
- Initializing StageVideo – setting up StageVideo objects.
There are a few other Flash Player activities that don't really fit into any of the above categories:
- Running AS2 – executing ActionScript 2 code. This may show up even if you didn't write any ActionScript 2, because Flash Player automatically generates some ActionScript 2 code to perform certain initialization and housekeeping functions.
- AIR startup – running ActionScript code at startup for an AIR application.
- Button hit testing – Flash Player has some special code to handle old-style button objects (the kind that you create in Flash Professional). Independently of looking for ActionScript event handlers for mouse events, it searches the display list for any of these buttons whenever the mouse moves. This can be expensive if you have a large number of objects on the display list. Unfortunately, this operation happens even if you don't use old-style button objects, but Adobe is working on a fix for this.
- Runtime overhead – this covers any time that's not accounted for by any other activity. Flash Player only measures activities that typically take a significant amount of time, so all the other little things it does get lumped into this category. The small amount of time that this uses should be negligible, and you don't need to worry about it.
When Flash Player is waiting for something to happen, it shows up as inactive time in Scout. This can either be because it's blocking on something, or simply because it ran out of work to do. If you expand the Inactive category in Scout's Summary panel, you'll see this broken down into some or all of the following:
- Waiting for next frame – there's nothing left to do in the current frame, so the player instance goes to sleep until it's time for the next frame, or some external event happens (like a mouse or network event).
- Waiting for GPU – Flash Player is waiting for the graphics card to perform some operation. See the section on GPU-related performance issues for more details.
- Waiting for condition – a worker thread is blocking on a Condition.wait() , a MessageChannel.send(), or a MessageChannel.receive() call.
Memory reporting in Scout
As well as measuring how long it spends performing various activities, Flash Player keeps track of how much memory it's using. You can see this in the Summary panel in Scout, and just like CPU time, it's broken down into categories. Flash Player only keeps track of memory that it explicitly allocates–there's some memory that the operating system allocates, such as for storing the Flash Player executable, that won't show up in Scout.
When you look at the memory usage of a session in Scout, it's important to realize that the total memory is the memory used by all the running player instances. Memory used by other player instances appears in the category Other, under Other Players. In addition, some of the memory under Uncategorized may be due to other player instances. Some data structures are shared within Flash Player, making it hard to attribute it to a specific player instance. When you're profiling your content in the browser, it's best to run only your SWF if possible.
Flash Player does its best to keep track of the main data structures that use a significant amount of memory, but some areas are better covered than others. At the moment, it doesn't measure the memory used by audio and video buffers, or by JITted ActionScript code. This will show up under Uncategorized, along with any other internal data structures that aren't tracked.
Some notes on GPU-related performance issues
The GPU is the specialized processor on your graphics card that lets you do hardware-accelerated rendering. It's really good at doing massively parallel computations, like positioning and coloring huge arrays of triangles. That's in contrast to the CPU, which can do much more complicated tasks, but is only really good at doing one thing at a time. Stage3D makes use of the GPU by providing an ActionScript API that lets you talk to it directly. To make life easier, you'll often use a higher-level framework, such as Starling for 2D content, and Away3D for 3D content. Keep in mind, though, that these frameworks are using the GPU behind the scenes.
The thing to remember when using Stage3D is that the GPU runs in parallel with the CPU. This means that the speed of your content is limited by the slowest component. Even if your ActionScript is fast (so that the CPU isn't overloaded), if you give the GPU too much work to do then you won't achieve the framerate you want. Here are two of the most common performance problems when using the GPU:
- You might be asking the GPU to do too much. The most common causes are issuing too many draw calls, changing the GPU state too often, or using meshes and textures that are too large. There are lots of ways to optimize your content. For example, using compressed textures, using texture atlases with Starling, and of course simplifying the objects you're trying to render. At the moment, Scout can't show you what the GPU is doing, but you can use the Stage3D Rendering panel in Scout to see what Stage3D commands you're executing, and look for ways to optimize them.
- You might be trying to update the screen faster than the GPU can manage. Graphics cards work using a technique called double-buffering. One buffer contains the data that's currently being shown on the screen, while the other buffer (the backbuffer) is used to construct the next image to display. When you call Context3D.present() , you're telling the GPU to display what you've been drawing, meaning that the GPU should swap these two buffers around. But the GPU only swaps them every 60th of a second. This is known as the VSync, and it's related to how fast a monitor can update its image. If the GPU isn't ready to swap, it'll block, and this shows up as Waiting for GPU in Scout. This normally isn't a problem, but if the CPU can't keep up with the VSync rate, it might repeatedly miss the deadline and then have to wait for the next VSync for the GPU to update. If this happens, you can often improve performance by setting a lower framerate to avoid the extra waiting time.
Here's a great tip: If your content shows excessive Waiting for GPU time in Scout, try temporarily disabling hardware acceleration in Flash Player (right-click and select Settings). This will cause Flash Player to fall back to software rendering, and the waiting time will vanish, so you can confirm that your problem is GPU-related.
Where to go from here
Now that you know more about how Flash Player works, you'll be better able to use Adobe Scout to optimize your content. Remember that you can use this article as a reference if you forget what something means while using Scout. Happy profiling!
This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License