Have you found such a tool and used it successfully?
Flex Builder 3 includes a performance and memory profiler. I haven't used it, but it looks pretty snazzy. I'm not sure if it can be used for non-Flex content, but it will definitely only work for AS3.
Apart from that, over the years I've found a couple of workable methods for a certain level of profiling. At the simplest you can obviously just build an FPS meter and watch how it behaves. For more info about code-heavy applications one thing I've done is to whip up a simple framework for making getTimer()
calls at the beginning and end of methods and tracking the cumulative time, but I've never used any pre-made tools for that. In practice it's usually pretty obvious where the bottlenecks are for code-heavy work, and in those cases I just put timer directly around what I'm trying to optimize.
When the bottlenecks are in rendering, the first thing to try is to simply publish at your target FPS, and use an FPS meter to track when actual playback falls below that (on target hardware). You can get more detailed information about rendering by, for example, invoking a 1ms timeout that calls refreshAfterUpdate
, and monitoring the actual time between refreshes. Unfortunately you can't get any more granular than "per refresh" though - you can't directly see how much time is spent rasterizing, compositing, etc. (Though you can often infer these things. For example, you can enable bitmap caching on vector-heavy objects to take rasterization off the table, and observe the results.)
It's important to note that the Flash Player implementation is different on each platform and to an extent each browser, so expect notable speed differences. So if you're developing a resource intensive application you should be using profiling tools specific to each OS you're targeting, like for example Instruments on OS X and of course test the performance in each browser.
I've used the profiler that comes with Flex Builder 3 with moderate success. I find out especially useful in finding memory leaks and or GC issues.
It was much less useful for me in the area of time-in-method performance due to the asynchronous nature of the application in question and the amount of time given to [onEnterFrame] and other internal methods, though I was still able to make some optimisations based on the output.
I was also looking for a profiler for AS, but I wanted an freeware/open source solution that works with FlashDevelop and Flex SDK. I found none. So I wrote a simple python script and an even simpler AS class. The script essentially takes any AS file and adds profiling code (i.e. calls to measure the total runtime of that function with an accuracy of 1 ms - the resolution of the flash.utils.getTimer()
call) to each function definition. The script sometimes makes mistakes, but these are usually easy to fix by hand. Then you need to add one more line manually: dump the profiling statistics somewhere at some point. This method is obviously far from accurate, but it nonetheless gives you good feel of bottlenecks in your code. I used it for a 100k file with success.
Here is the AS class:
package {
public class Profiler {
private static var instance:Profiler;
public static function get profiler():Profiler {
if (!Profiler.instance) Profiler.instance = new Profiler;
return Profiler.instance;
}
private var data:Object = {};
public function profile(fn:String, dur:int):void {
if (!data.hasOwnProperty(fn)) data[fn] = new Number(0);
data[fn] += dur / 1000.0;
}
public function clear():void {
data = { };
}
public function get stats():String {
var st:String = "";
for (var fn:String in data) {
st += fn + ":\t" + data[fn] + "\n";
}
return st;
}
}
}
And here is the python script that does the trick:
import sre, sys
rePOI = sre.compile(r'''\bclass\b|\bfunction\b|\breturn\b|["'/{}]''')
reFun = sre.compile(r'\bfunction\b\s*((?:[gs]et\s+)?\w*)\s*\(')
reCls = sre.compile(r'class\s+(\w+)[\s{]')
reStr = sre.compile(r'''(["'/]).*?(?<!\\)\1''')
def addProfilingCalls(body):
stack = []
pos = 0
depth = 0
retvar = 0
klass = ""
match = rePOI.search(body, pos)
while match:
poi = match.group(0)
pos = match.start(0)
endpos = match.end(0)
if poi in '''"'/''':
strm = reStr.match(body, pos)
if strm and (poi != '/' or sre.search('[=(,]\s*$', body[:pos])):
endpos = strm.end(0)
elif poi == 'class':
klass = reCls.match(body, pos).group(1)
sys.stderr.write('class ' + klass + '\n')
elif poi == 'function':
fname = reFun.match(body, pos)
if fname.group(1):
fname = klass + '.' + fname.group(1)
else:
lastf = stack[-1]
lastf['anon'] += 1
fname = lastf['name'] + '.anon' + str(lastf['anon'])
sys.stderr.write('function ' + fname + '\n')
stack.append({'name':fname, 'depth':depth, 'anon':0})
brace = body.find('{', pos) + 1
line = "\nvar __start__:int = flash.utils.getTimer();"
body = body[:brace] + line + body[brace:]
depth += 1
endpos = brace + len(line)
elif poi == '{':
depth += 1
elif poi == 'return':
lastf = stack[-1]
semicolon = body.find(';', pos) + 1
if sre.match('return\s*;', body[pos:]):
line = "{ Profiler.profiler.profile('" + lastf['name'] + \
"', flash.utils.getTimer() - __start__); return; }"
else:
retvar += 1
line = "{ var __ret" + str(retvar) + "__:* =" + body[pos+6:semicolon] + \
"\nProfiler.profiler.profile('" + lastf['name'] + \
"', flash.utils.getTimer() - __start__); return __ret" + str(retvar) + "__; }"
body = body[:pos] + line + body[semicolon:]
endpos = pos + len(line)
elif poi == '}':
depth -= 1
if len(stack) > 0 and stack[-1]['depth'] == depth:
lastf = stack.pop()
line = "Profiler.profiler.profile('" + lastf['name'] + \
"', flash.utils.getTimer() - __start__);\n"
body = body[:pos] + line + body[pos:]
endpos += len(line)
pos = endpos
match = rePOI.search(body, pos)
return body
def main():
if len(sys.argv) >= 2: inf = open(sys.argv[1], 'rU')
else: inf = sys.stdin
if len(sys.argv) >= 3: outf = open(sys.argv[2], 'wU')
else: outf = sys.stdout
outf.write(addProfilingCalls(inf.read()))
inf.close()
outf.close()
if __name__ == "__main__":
main()
Feel free to use, distribute and modify both.
I wrote a flash profiler based on flasm a while ago (http://snow.prohosting.com/bensch/flasp.html) You need to use flasm to insert the profiling asm and then run the program.
Another (maybe) better way is to use David Chang's profiling code which doesn't require flasm at all. www.nochump.com/asprof/
cheers
This one is my personal favorite. Note that it's built on java and open source. http://github.com/bengarney/PBLabsProfiler
It uses undocumented features of flash/flex compiler. The same ones Flash Builder built-in profiler uses. And yes! I have successfully used it to optimize some of my flash code.