闪光/动作脚本CPU分析器分析器、脚本、闪光、动作

2023-09-08 11:02:20 作者:野性难驯

你有没有发现这样的工具,并成功地用它?

Have you found such a tool and used it successfully?

推荐答案

我也一直在寻找一个分析器用于AS,但我想要一个免费/开源的解决方案,具有的FlashDevelop和Flex SDK的作品。我没有发现。所以我写了一个简单的Python脚本和一个更简单的AS类。该脚本主要采取任何文件和分析增加了code(即调用来衡量该函数的总运行时间为1毫秒的精度 - 在 flash.utils.getTimer()的分辨率调用)每个函数的定义。该脚本有时会犯错,但这些通常很容易用手工修复。然后,你需要手动添加下一行:地方倾倒在某一点上分析统计。这种方法是准确的显然远,但它仍然给你的瓶颈良好的感觉在你的code。我用了一个100K的文件,成功。

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.

下面是AS类:

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;
    	}
    }
}

在这里是做的伎俩的python脚本:

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.