Intro To Profiling Applications

From FDT Documentation

Revision as of 20:45, 22 September 2010 by Aklement (Talk | contribs)
Jump to: navigation, search

Profiling is an important part of software development. If you're creating a simple image carousel, a profiler is something that you may not need. If you're building an AIR application that will work on a computer kiosk, running for hours on end, a profiler is going to be almost necessary and likely a life saver.

Contents

Getting Started

Import this project into FDT ( learn about importing and exporting via Creating Project Templates) or copy and paste the code below to follow along:

Main.as:

package demo {
	import graphics.shapes.Circle;
 
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
 
	public class Main extends Sprite {
		private var circles : Array = [];
 
		public function Main() {
			this.stage.addEventListener(MouseEvent.MOUSE_DOWN, start_circles);
			this.stage.addEventListener(MouseEvent.MOUSE_UP, stop_circles);
		} 
 
		private function start_circles(event : MouseEvent) : void {
			this.addEventListener(Event.ENTER_FRAME, draw_circles);
		}
 
		private function stop_circles(event : MouseEvent) : void {
			this.removeEventListener(Event.ENTER_FRAME, draw_circles);
 
			while(circles[0]) {
				this.removeChild(circles.pop());
			}
		}
 
		private function draw_circles(event : Event) : void {
			// with no referece this won't be garbage collected
			addChild(create_circle());
			// hold a referce in array so it can be removed from stage 
                       //and garbage collected
			circles.unshift(create_circle());
			addChild(circles[0]);
		}
 
		private function create_circle() : Circle {
			var circle : Circle = new Circle();
			circle.x = this.stage.stageWidth * Math.random();
			circle.y = this.stage.stageHeight * Math.random();
			return  circle;
		}
	}
}


Cirlce.as:

package graphics.shapes {
	import flash.display.Shape;
 
	public class Circle extends Shape {
		public function Circle() {
			this.graphics.beginFill(0xffffff * Math.random());
			this.graphics.drawCircle(0, 0, 20 * Math.random());
		}
	}
}

How The Example Project Works

With our project setup and our Main.as 08 001.gif class and Circle.as class 08 002.gif setup. We'll quickly cover the code. Cirlce is just a class that draws a circle of random size and color. It's also located in the graphics.shapes namespace (package). Main is a class that creates circles and adds them to the stage. The only bit of code to note is this:

private function draw_circles(event : Event) : void {
	// with no referece this won't be garbage collected
	addChild(create_circle());
	// hold a referce in array so it can be removed from stage and garbage collected
	circles.unshift(create_circle());
	addChild(circles[0]);
}


Here we're creating two circles - one is placed directly on the stage and the other is having a reference (pointer) stored into an Array so we can retrieve it later:

private function stop_circles(event : MouseEvent) : void {
	this.removeEventListener(Event.ENTER_FRAME, draw_circles);
 
	while(circles[0]) {
		this.removeChild(circles.pop());
	}
}


On MOUSE_UP, we're stopping the creation of new circles and each Circle in the circles array is being taken out of the array and then removed from the stage. This will remove any references to the circle we've created so it can be easily deleted from memory (garbage collected).

Running The SWF

Before profiling, lets just run the .SWF to see what's going on. This demo already has a launch configuration included [003], and to access this we'll jump to the Run Configurations window, select it [005] and hit Run [006]. When the window pops up [007], press down on the stage (MouseEvent.MOUSE_DOWN) to begin drawing circles [008] and then release the mouse (MouseEvent.MOUSE_UP) to have half of them disappear [009].

Those circles that disappeared will be eligible for garbage collection and the ones on the stage will not.

Launching The Profiler

Now, let's get to the profiler. Again, we have multiple ways of launching the profiler, but to make sure we're using the same launch profile, let go to the profile menu and choose our 'ProfileTest' launch [010]. FDT will compile and and launch the .SWF then switch to the Profile perspective [011]. For now let's move off the External SWF Viewer and focus on the Profiler Perspective [012].

In this example, the views have been moved around to make best use of the space available. You can set it up however you like.

The Profiler Perspective

Memory Graph

The top part is the Memory Graph [013]. This is a visual representation of the .SWF's memory footprint displayed over time. This is where you'll be looking to compare Peak Memory (a total of all Objects created) and Current Memory (Objects that are currently active in memory).

Live Objects

The next view is the LiveObjects view [014]. This provides a breakdown of the objects created and how much memory that type of object takes up. In this example we can see that the String type takes up .31 percent of memory in our app.

Profile Monitor

The Profile Monitor is where we control the profile process [015]. Use this when you want to force garbage collection [016], terminate [017] or suspend (pause) the profiler [018]. When using these controls, make sure you have the currently running process selected, otherwise you won't be able to control the active profiling session [019].

Console

The Console view here is the same as it exists elsewhere in FDT [020]. It simply provides an output of FDT's actions.

Profiler In Action

Bring focus back to the running .SWF and press and hold the mouse button. As you do this, circles will begin appearing on the stage. You'll see the Memory Graph begin to climb and the LiveObjects view being updating [021]. When the mouse is released, half of the circles will disappear. These objects that disappeared are now eligible for garbage collection. For the standard player release, Flash's garbage collection is designed to be automated and not to be user initiated. Since we are using the debug player, FDT has access to an API that allows developers to initiate garbage collection as they wish. To initiate garbage collection, press the Run Garbage Collection button [022].

Instantly, you'll see a dip in the Current Memory within the Memory Graph view and the Instances column within the LiveObjects view will drop [023]. This drop represents the deletion of those circles we removed from the stage.

Filters

To get a better idea of what is going on, let's pause the execution of the .SWF and profiler by pressing the Suspend button [024]. With everything paused, lets take a closer look at the filters that are available. Here we have two important filters: Filter internal packages [025] and Filter native objects [026]. To a get a better idea of what garbage collection did for us, click on the Filter native objects filter. Here we can see the objects we created, Main and Circle [027]. Notice that there are 305 circles active compared to 611 that have been generated in total. Our ENTER_FRAME event handler was creating two objects total - one we explicitly generate a reference for and one that we anonymously add. Our MOUSE_UP handler is then removing the circles we created a reference for and leaving the others behind. That is why when the garbage collector executed it removed exactly half of the circles, 305, of the total 610.

Memory Snapshots

Sometimes it doesn't make sense to pause your .SWF to inspect it. That is what Memory Snapshots are for. If your .SWF is not already executing, resume it now. After minimizing the Console view, prepare to take a snapshot by selecting the running process and press the Create Memory Snapshot button [029].

note: this example was restarted to clean up the UI a bit so it's not going to match exactly previous screens;however, the steps to this point are the same.

FDT will then create a memory snapshot of the running .SWF. Let's wait a little bit and then hit the garbage collection button and wait for the memory to be cleared [031]. After the memory has been cleared take another snapshot [032].

With both snapshots created [033], we can now take a closer look at what was going on at that moment and even compare the two. Initiate the Memory Snapshot View by double clicking on one of the snapshots [034]. To clear things up a bit, let's use the Filter native objects filter on the snapshot [035]. This snapshot now provides a detailed report of the status of the application at a specific time. We can dive even deeper and investigate the instances associated with that type by expanding the Class type [036]. Clicking an a particular instance [07] will then activate the Back References [038] associated with it. The Allocation Trace is also available to us and provides further information about the running .SWF [039].

Another useful features regarding Snapshots is the ability to compare Snapshots. Do this by selecting the two available Snapshots and pressing the Compare Snapshot button [040]. A new Compared Snapshot will be created [041]. Double click on this and the Compare Snapshot view will open [042]. Here Missing Objects and Additional Objects can be investigated. In our case, the Missing Objects are those that were deleted when we initiated garbage collection and the Additional Objects are the various events being dispatched by the mouse events and ENTER_FRAME event.

Get FDT5