The flash.sampler.* API and the Sample object

I recently became aware of the flash.sampler.* package, which gives you access to the same profiling data via AS3 that FlashBuilder uses for it’s profiler. It’s a very useful API for performance and memory profiling, offering enhanced introspection tools, more granular timing, method invocation counts, and method invocation sampling. It has been available in the Debug player since player 9.0r115, but I somehow remained aware of it’s existence until a few days ago.

Given that, I thought I’d write up a quick post about the API to help people get started with using it. The API is generally well documented in the Flex 4 language reference, so I’ll just focus on a few key methods and gotchas.

General information
Most of the API exists as methods within the flash.sampler package. Simply import flash.sampler.* (or the individual methods), and call the methods directly. The sampler API is only available in a debug player.

It’s also worth knowing that along with the API, the Flash player allows you to specify your own preload SWF, which will be loaded prior to other content in debug players. You can specify this in the “mm.cfg” file – the details are documented in the Flex API docs for the sampler package. This mechanism is what FlashBuilder uses to funnel sample data to the profiler. This let’s you build your own tool chain that can be invoked on any site. There’s lots of room here for building tools that run in the browser, or that connect to a companion AIR app for inspecting or profiling content.

(as an aside – jpauclair has the best write ups of mm.cfg I’ve seen – definitely worth reading if you’re interested in profiling Flash content)

Introspection
The sampler API includes a few handy introspection methods:

getSize() // returns the size in memory of the specified object in bytes
getMemberNames() // returns an iterator object containing all of the private and public members (properties / methods) on the specified object
isGetterSetter() // checks whether a proper is defined with a getter/setter

Sampling
Sampling allows you to log all of the methods that were invoked over a period of time, and determine the amount of time each method took to execute. Here are the key methods:

startSampling(); // starts collecting sample data
stopSampling(); // ends a sampling session, and clears all sample data
pauseSampling(); // stops collecting sample data, without clearing existing data
getSamples(); // returns an iterator object (see below) containing all of the samples collected since the last clear
getSampleCount(); // returns the number of samples that will be returned by getSamples()
clearSamples(); // clears current samples data - you will generally want to call this after each getSamples() call to remove the samples you have already read.

For the most part this API is pretty straightforward. Where it gets weird is when you look at the object returned by getSamples(). Initially, I simply traced the object, and got an error saying “Property toString not found on (null) and there is no default value”.

This made me think that I was doing something wrong, and that getSamples was returning null. Then I realized that null always traces as “null”. It occurred to me that the error was actually showing that the type of the offending object was outputting null. Running describeType on the object returns its type as “*::*”. Very interesting! Apparently it is using some low-level iterator object that doesn’t even have an AS3 type (I’m trying to get more info on this).

If you ignore the weird return type, and simply iterate the object with a for..each loop (which appears to provide a determinate order for this object type, also interesting), you will get a list of Sample objects, which includes a time stamp in microseconds, and an array of StackFrame objects which contain the function’s full path/name and the SWF line number associated with it.

var o:* = getSamples();
for each (var s:Sample in o) {
trace(s.time,s.stack);
}
clearSamples();

Samples may also be instances of the NewObjectSample or DeleteObjectSample subclasses, which indicate the costs of instantiating or destroying an object respectively. The former has a type property that indicates the created object’s type. The latter has a size property that indicates the object’s size in memory at the time it was deleted. Both have an id property (presently undocumented on NewObjectSample) which lets you pair the create and destroy actions together.

With this information and some analysis, you can track time spent in any method (singularly or as an aggregate) and object creation.

I’ll be playing around with this API more over the next couple of weeks. I will likely talk about it a bit at FitC in Toronto and Flash and the City in NYC. I’m hoping to incorporate some of it’s capabilities into an updated version of PerformanceTest, and might build out some other tools around it. I’ll blog more as I learn more.

Grant Skinner

The "g" in gskinner. Also the "skinner".

@gskinner

10 Comments

  1. Thanks for the info! Looks like I have some updating to do to my logger util! yay!

  2. It’s the API Adobe introduced when FlexBuilder 2 got the Profiler based on sampling data. The API delivers huge amounts of data and it just doesn’t perform to analyze the data in Flash only tools. So it fits perfectly in Java based environments like the Profiler in FlexBuilder or FDT.

  3. Meinhard – it does create a huge amount of data, and analyzing large sample sets will take a lot of horsepower. For more isolated cases though, it should be possible to utilize the API to get valuable information.

    I don’t have a really strong sense of how I’ll utilize it yet, but the more tools you know how to use, the more things you can build.

  4. So strange to me that I never knew about this either. It seems like the community would have been talking a lot more about it.

    Anyway, very good to know, thanks!!

  5. The sampler API is a great set of class giving us ways to make better/faster code…

    But some of the flags in the mm.cfg file give us some additional power: AS3Verbose for exemple.

    Here is how to analyse/optimize your code using thoses (hidden) additional profiling options

    http://jpauclair.net/2010/03/15/flash-asm/

  6. orion elenzil May 3, 2011 at 2:47pm

    great article, thanks.
    i notice that i have to get and analyze the samples before calling stopSampling().

    anyone know what the units of the timestamp are ?
    averaging across 7 seconds, i measure a change of 150,000 per second.

    i’m a bit surprised by what gets identified as a NewObjectSample and DeleteObjectSample. are those reliable ?

  7. Running in a browser, if I load my swf via swfobject, getSampleCount always returns 0, whereas if I point the browser directly at the .swf file, getSampleCount returns properly… Why would this be?

  8. Scratch that – I was accessing my .swf from a non-trusted location when it wasn’t working. The livedocs say the agent SWF (or presumably anybody who wants to access the sampler) must reside in a localTrusted path.

Leave a Reply

Your email address will not be published. Required fields are marked *