闪存/Actionscript CPU分析工具

16

你是否找到过这样的工具,并成功使用过它?

9个回答

16
我也在寻找AS的分析器,但我希望找到一个免费/开源的解决方案,可以与FlashDevelop和Flex SDK一起使用。但我没有找到合适的。所以我写了一个简单的Python脚本和一个更简单的AS类。该脚本可以将任何AS文件添加分析代码(即调用flash.utils.getTimer()的总运行时间,并将其精度设置为1毫秒)到每个函数定义中。该脚本有时会出错,但这些通常很容易手动修复。然后您需要手动添加一行:在某个时刻将分析统计数据转储到某个位置。这种方法显然远非准确,但它仍然可以让您感受到代码中的瓶颈。我已经成功地将其用于100k的文件。
以下是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脚本:

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()

欢迎自由使用、分发和修改。


我在 Python 脚本的第 31 行遇到了一个错误:UnboundLocalError: local variable 'klass' referenced before assignment。 - Marc Novakowski
我在函数开头添加了一行代码来初始化klass变量。 - David Hanak
@DavidHanak请包含如何使用你的工具的说明,以便新手能够使用它们。谢谢。 - Martin Asenov

6
Adobe最近发布了一款名为Adobe Scout的新型Flash分析工具: http://gaming.adobe.com/technologies/scout/ 与旧版Flash Builder profiler相比,它有了巨大的改进——除了可以展示ActionScript执行时间外,还能展示内部播放器功能(如渲染和网络)的详细信息。
它有一个免费试用期,只需注册一个免费的Creative Cloud账户。之后,将继续提供免费基础版本,并且完整版本可作为付费Creative Cloud帐户的一部分获得。

2

需要注意的是,Flash Player 在每个平台和浏览器上的实现都不同,因此速度差异显著。因此,如果您正在开发资源密集型应用程序,应该使用针对每个操作系统特定的分析工具,比如在 OS X 上使用 Instruments ,并且当然要在每个浏览器中测试性能。


2

我曾经使用过Flex Builder 3自带的分析器,取得了一定的成功。我发现它在查找内存泄漏和GC问题方面特别有用。

但是,在方法执行时间方面,由于应用程序的异步性质以及给[onEnterFrame]和其他内部方法的时间量较少,它对我来说不太有用,尽管我仍然能够根据输出进行一些优化。


2

我之前基于flasm编写了一个Flash分析器(http://snow.prohosting.com/bensch/flasp.html),您需要使用flasm插入分析汇编代码,然后运行程序。

另一种(可能)更好的方法是使用David Chang的分析代码,它根本不需要flasm。www.nochump.com/asprof/

祝好


2

这是我个人最喜欢的一个。请注意它是基于Java和开源的。 http://github.com/bengarney/PBLabsProfiler

它使用了Flash/Flex编译器的未公开功能,与Flash Builder内置的分析器相同。是的!我已经成功地用它来优化我的一些Flash代码。


1
是的,PushButton Labs Profiler非常出色地完成了工作! - Pavel Alexeev

1

Flex Builder 3 包含一个性能和内存分析器。我没有使用过它,但它看起来非常漂亮。我不确定它是否可以用于非 Flex 内容,但它肯定只适用于 AS3。

除此之外,多年来我发现了一些可行的方法来进行某种程度的分析。最简单的方法显然是构建一个 FPS 计量器并观察其行为。对于更多关于代码密集型应用程序的信息,我做的一件事是编写一个简单的框架,在方法的开头和结尾调用 getTimer() 并跟踪累积时间,但我从未使用过任何预制工具。在实践中,对于代码密集型工作的瓶颈通常很明显,在这些情况下,我直接将计时器放在我正在优化的内容周围。

当渲染瓶颈出现时,首先尝试的是以目标FPS简单发布,并使用FPS计量器跟踪实际播放时间是否低于目标硬件(的要求)。您可以通过调用refreshAfterUpdate的1ms超时来获取有关渲染的更详细信息,并监视刷新之间的实际时间。不幸的是,您无法获得比“每次刷新”更精细的信息 - 您无法直接查看光栅化、合成等花费的时间。(尽管您通常可以推断出这些事情。例如,您可以在矢量重型对象上启用位图缓存以避免光栅化,并观察结果。)


那个链接指向Flex Builder 3的功能介绍——那不是当前版本吗? - hasseg
哇,你说得对 - 你可以看出我不是FB用户。 我会编辑以提高清晰度,但也许更熟悉FB分析器的人可以添加有关内幕的信息。 感谢您的提示! - fenomas

1

我发现矿工非常有用,而且对于非商业项目是免费的。它具有广泛的功能,但被标记为“性能分析器”的选项卡最有帮助。我发现这是在代码中找到瓶颈的好方法,或者至少知道主要原因(渲染、文本、网络等)。

我花了一点时间才找到安装说明,但它很简单。将.swc文件包含在您的项目中,然后在文档类构造函数中添加一行代码即可。

this.addChild(new TheMiner(true));

更多信息:http://www.sociodox.com/theminer/support.html

0

有一个FlashPreloaderProfiler: http://jpauclair.net/flashpreloadprofiler

它是用ActionScript编写的,不需要在后台运行Java应用程序,并且具有一些更多的功能,如内存分析器。

但我更喜欢PBLabsProfiler :)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接