标签:des style http io os 使用 ar java for
Adobe Scout 用于优化 Flash 内容,是一款极为强大的工具,因为它能让您看到 Flash Player 幕后正在发生的事情。但是若明白 Flash Player 为什么做这些事情,您看到这些事情才会最有用。只有这样,您才能有效地找到修复 Scout 所告知的问题的方法!
本文的目的是让您大致了解 Flash Player 的工作原理,并将之与您在 Scout 中看到的信息相关联。本文也是 Scout 中所用术语的参考指南,因此您可以从中查找 Flash Player 执行的各种活动的含义。如果您使用过 Scout,并且认为“我花了太多的时间做某件事,却不知道某件事的含义”,那么本文就是为您准备的!
注意,本文不是 Scout 用户界面指南。不知道如何使用 Scout,或者不知道各个面板的作用,那么请首先阅读入门指南。
Flash Player 像个人助理一样,帮助您安排复杂的事情,并充当您与外界的接口。但是 Flash Player 自己不会做任何事情,除非您告诉它做什么!有两种方式做这件事:
Flash Player 执行您的脚本或者时间轴中的标记时,这些脚本或标记会告诉它去执行各种活动。这些活动可以大致分为 4 类:
在阅读本文时,一定要记住以下内容。Flash Player 不只是执行 ActionScript 代码,它还执行很多其他活动!如果您将 Flash Player 看作个人助理,那么执行 ActionScript 代码就像助理在会议中的工作。即使是一个非常简短的会议,Flash Player 仍然必须提前准备您需要的所有资料。呈现您的精美动画需要花费时间,大部分真正的工作发生在 ActionScript 代码之外!
您可能会感到好奇,Flash Player 怎么管理这些不同活动的执行呢?
您在 Web 浏览器中运行 Flash 内容时,Flash Player 通常运行在一个单独的操作系统进程中。对于运行在该浏览器中的所有 SWF(包括任何相关的工人线程),只存在一个进程,所以 Flash Player 管理这些 SWF 的执行,就像它们都是独立运行的一样。每个正在运行的 SWF 称作一个播放器实例,对应于 Scout 中的一个会话。工人线程也是播放器实例。对于 AIR 内容,只存在一个主播放器实例,加上它所使用的任何工人线程。
运行的时候,Flash Player 会在不同的活动之间切换。它可能执行一会儿脚本,然后播放一会儿视频,然后再呈现一些图片,等等。具体的顺序取决于正在发生什么样的事件、正在执行哪些持续活动,以及 SWF 的脚本和时间轴请求了哪些活动。在所有这一切的发生过程中,Flash Player 会记录它所做的事情,并测量消耗的资源,包括 CPU 时间、CPU 内存和 GPU 内存。这些测量值被发送到 Scout,以便您可以看到正在发生的情况。为了最小化这些测量的开销,Flash Player 只测量和报告那些花费时间或内存较多的活动。
基本上,Flash Player 在任何时间都处于两种模式之一:
在 Scout 中,总时间(活跃和不活跃时间之和)用 Frame Timeline 中的灰色竖条表示。为了更加形象地表示 Flash Player 花费在执行各种不同类型活动上的时间比例,Scout 将活跃时间分为 4 大类别:
一定要知道,Scout 展示的是已逝时间,而不是 CPU 时间。可以把 Flash Player 想象成一个人拿着秒表坐在那里为每个活动计时。如果操作系统在活动中间打断 Flash Player,让另一个应用程序运行一会儿,那么 Flash Player 将测量到一个较长的已逝时间。为了得到最精确的数据,在使用 Scout 进行剖析时应该关闭其他应用程序。
很多 Flash 应用程序,尤其是游戏,具有大量的图形动画。基本原理是以某个频率(比如说 60 次/秒)重绘屏幕,使之看起来像一个流畅的动画。为帮助您进行这种编程,Flash Player 具有一个核心概念——帧。进入播放器的深层,是它的心脏——一个以某种频率(称作帧速率)触发的定时器。这些心跳之间的时间称作帧。您需要确定以什么样的帧速率运行自己的内容。帧速率是 SWF 的一个属性,您可以在 SWF 运行期间从 ActionScript 动态地更改它。
一种常见的编程方式是,为 Event.ENTER_FRAME
(该事件对应于心跳和新帧的开始)注册一个事件处理程序。如果编写游戏,您可以使用这个事件处理程序来做保持游戏运行所需的所有周期性工作。例如,可以处理任何用户输入,使用物理引擎更新游戏状态,最后呈现更新后的场景。
使用 Scout 进行剖析时,Frame Timeline 显示 Flash Player 执行每一帧花费的时间。下面来考虑一款游戏,您想对它获得 60 帧/秒 (60fps) 的帧速率。一秒钟等于 1000 毫秒 (ms),所以每一帧的预算时间是 1000/60 = 16.7ms。通常,如果每一帧花费的时间都比这个时间长,那么 Flash Player 将不能以您所需的帧速率运行,您的内容就可能看起来缓慢而抖动。在 Scout 的 Frame Timeline 中,预算时间显示为一条水平红线,灰色竖条表示每个帧花费的总时间。
在一个帧中,Flash Player 要执行很多不同的活动。其中首先要做的一件事情就是分派一个 Event.ENTER_FRAME
事件并调用任何已注册的事件处理程序。在它执行 ActionScript 代码时,这可能会导致新的延迟活动或持续活动添加到“要执行的活动列表”,比如说重绘部分屏幕或者开始新的文件下载。这些活动必须在这个帧中稍后的某个时间得到执行。此外,帧中还可能出现鼠标、键盘及其他事件,这些事件也需要被处理和完成。最终,Flash Player 将完成它对于这个帧的所有任务,不留下任何未完成事情。然后它坐下来等待下一次心跳,以便再次开始一个新的帧!
在 Scout 中,需要关注的主要是越过红线的彩色竖条。这表示 Flash Player 完成它需要完成的所有事情花费的时间长于整个帧的预算时间。换句话说,Flash Player 在分配给它的时间内有太多的事情要做!如果所有的帧都超出预算时间,那么您的内容通常就会变慢(见图 1),而如果有很多参差不齐的尖峰,内容就会不流畅。
注意,即使您早早地完成帧,Flash Player 在开始下一帧之前也总是会等待。这是一件好事情——表示您的内容不会一直霸占着设备上的所有资源,这可以降低电力消耗,腾出 CPU 时间来执行其他任务。这也表示您的内容中内置有时差,以便可以按目标帧速率运行在较慢的设备上。灰色竖条徘佪在红线周围的情况极为正常(见图 2)。
关于帧,需要了解一些琐碎的事情:
既然已经较好地了解了 Flash Player 的基本结构,现在就该进一步来了解 Scout 中看到的数据。您会注意到,Top Activities 和 Activity Sequence 面板给出了 Flash Player 正在做的事情的详细分类。这些面板中的描述尽可能地一目了然,但是有时候您也需要更多的信息来了解问题的根源。本节将 Flash Player 的各种活动划分为几个功能区域(见图 4),并对它们的含义提供了更详细的解释。
您可以将本节作为使用 Scout 时的参考指南,只阅读跟具体问题有关的部分。或者,您也可以阅读整个这一节,更多地了解 Flash Player 的各个部分是如何工作的。
ActionScript 是 Flash 语言;它让您告诉 Flash Player 去做什么。您建立一个 SWF 时,ActionScript 代码会被编译成一种 Flash Player 可以理解的较低级的语言,即 ActionScript 字节码。当 SWF 运行时,该字节码会由 ActionScript 虚拟机 (AVM) 执行。AVM 实现 ActionScript 的某些核心功能,包括垃圾收集和异常,还充当您的代码与 Flash Player 之间的桥梁。
您可以使用 API 从 ActionScript 与 Flash Player 交互。对于您来说,这些 API 就像普通的函数调用,但是在底层,您经常是在调用原生 C 代码——这里就是奇迹发生的地方!在 Scout 中, 这些 API 在 ActionScript 面板中显示为普通的函数调用,您无需担心内部细节。如果在一个 API 调用中花费了太长的时间,您就应该少调用它或者给它分配较少的工作去做(通过缩小参数的大小或复杂度)。
从 ActionScript 调用 Flash Player 时,您需要告诉 Flash Player 何时执行您的代码。大多数时候,这使用事件处理程序来完成。这些事件处理程序是您注册的一些函数,旨在特定事件发生时进行调用。您可以创建定制事件,并使用 EventDispatcher.dispatch()
手动调用它们,但是您会经常需要侦听外部事件,比如说鼠标移动和键盘按键。Scout 中有很多与此相关的活动:
keyDown
, keyPress
, keyUp
.mouseDown
, rightMouseDown
, mouseMove
, mouseUp
, mouseWheel
.touch
, gesture
.resize
, mouseLeave
, foreground
, background
, fullScreen
, fullScreenInteractiveAccepted
, visible
.定时器的处理方式非常类似于外部事件,只不过它们是由您自己设置的:
TimerEvent.TIMER
事件。其中也会有很多与执行您的代码及支持 ActionScript 语言特性相关的 AVM 活动:
trace()
语句的输出。也可以在 Trace Log 面板中查看该数据。UncaughtErrorEvent.UNCAUGHT_ERROR
。最后,如果您从其他语言调用了 ActionScript 3 代码,还会看到一些活动:
如果您在内容中使用了 ActionScript 工人,那么它们将作为单独的会话出现在 Scout 中。在底层,它们实际上就是单独的播放器实例,带有一个用于在它们之间共享数据的 API。在 Scout 中,对工人的支持目前还是一个 beta 特性。为启用支持,您需要做以下事情:
对于使用 ActionScript 工人的内容,您可能会在 Scout 中看到以下活动:
Condition.wait()
的调用上阻塞。MessageChannel.receive()
的调用上阻塞。MessageChannel.send()
的调用上阻塞。Mutex.lock()
的调用上阻塞。Mutex.trylock()
的调用上阻塞。除了 Flash Player 所做的内置测量,您还可以使用 Telemetry API 向 Scout 发送定制数据。两个主要的调用如下:
Telemetry.sendMetric(name, value)
– 这向 Scout 报告一个名-值对,将显示在 Activity Sequence 面板中。例如,如果调用 Telemetry.sendMetric("UserID", 2)
,您将在代码执行时看到 "UserID:2" 出现在 Activity Sequence 面板中。Telemetry.sendSpanMetric(name, startTime, value)
– 这向 Scout 报告一个活动,带有一个可选值。您通过查看 Telemetry.spanMarker
记录开始时间,然后在您想要测量的周期末尾将之传递到 Telemetry.sendSpanMetric
。它将同时显示在 Scout 的 Top Activities 和 Activity Sequence 面板中。有关更多信息,以及如何使用该 API 的例子,请参见 关于 Telemetry API 的文档。
Flash Player 的核心是帧滴答器–每当一个新帧开始时发生的心跳。在每个帧的开始,它都会执行任何时间轴标记,调用时间轴上的任何帧脚本,并分派一些关键的 ActionScript 3 事件。帧滴答器的活动如下:
MovieClip.onEnterFrame
事件处理程序。Event.ENTER_FRAME
的任何已注册处理程序。Event.FRAME_LABEL
带有已注册处理程序,那么该处理程序就会被调用。Event.EXIT_FRAME
的任何已注册处理程序。显示列表是 Flash Player 中经典的呈现方法。简单来说,给您一个称作画布的空白屏幕,您通过附加和布置称作显示对象的图形实体,在画布上绘画。有几种不同类型的显示对象,包括矢量插画、位图和文本,它们可以逐层嵌套来构成复杂的场景。无论是从 ActionScript 与显示对象交互,还是通过在 Flash Pro 中布置它们和设置补间,您都无需担心它们是如何真正呈现的。Flash Player 为您完成这项艰难的工作,计算出如何将显示列表转换成您在屏幕上看到的实际像素。
如果是使用 ActionScript 来操纵显示列表,您会注意到有好几种 API 您可以调用来进行更改。您可以将这些更改看作为即时活动。您调用 API 时,它会立即修改显示列表的内部状态。它不做的是立即修改您在屏幕上看到的内容!相反,Flash Player 将您修改的任何显示对象标记为脏的,这表示它们需要重绘。稍后某个时候,在您的代码执行完成之后,Flash Player 将执行一个呈现通道。它将所有的更改收集到一起,因此只需更新一次屏幕,大大提高了效率。您可以将这想象成单格拍制动画。在一个帧当中,您到处捏制好所有的小泥人,完成之后,Flash Player 再来拍摄这一帧的场景图。
这就是呈现通道在 Scout 中的样子(见图 5):
如果绘制带有很多边缘和不同过滤器的复杂形状,那么呈现将会很昂贵。请将显示列表修改为尽可能地小,以减小每个帧中需要重绘的脏区域的数量和大小。如果是绘制一个很少修改(只四处移动)的复杂的嵌套对象,那么您可以通过高速缓存它来改善呈现性能。这会将显示对象栅格化到一个高速缓存表面,该表面发生更改的话只需重新生成即可。如果只平移显示对象,那么请设置 cacheAsBitmap
属性。如果还想要对它进行旋转和缩放,那么请使用 cacheAsBitmapMatrix
(只在手机上受 AIR 支持)。
Scout 显示以下与高速缓存表面(在 DisplayList Rendering 面板中显示为橙色)相关的活动:
作为每个呈现通道的一部分,Scout 将显示关于在某些特定类型的显示对象上执行的活动的附加信息。以下活动与呈现文本相关:
以下活动与 Bitmap 对象及操纵它们的相关位图数据 (Bitmap.bitmapData
) 相关:
BitmapData.copyPixels()
的调用。BitmapData.draw()
的调用。您可能会在 Scout 中遇到几个与显示列表呈现相关的额外操作:
updateAfterEvent()
。一般来说,如果设置了较高的帧速率(比如 30fps 或 60fps),那么您应该永远不需要调用该函数,因为 Flash Player 已经每个帧至少执行了一个呈现通道。stage.invalidate()
,那么在呈现通道临开始之前,一个 Event.RENDER
事件将被分派给任何已注册处理程序。Stage3D 是一个基于 OpenGL 和 DirectX 的 ActionScript API,可以实现跨平台的硬件加速呈现。它的工作方式完全不同于传统的显示列表模型,尽管Starling 框架运行在 Stage3D 之上,并向 2D 内容显示列表提供一个类似的 API。Stage3D 内容呈现到它自己的显示缓冲区,在显示列表之后出现在屏幕上。
Stage3D 呈现循环的基本结构是,首先设置 GPU 的状态(上传您想要使用的纹理、网格和着色器),然后发出很多绘制调用,用于告诉 GPU 向目标缓冲区呈现大批的三角形。场景构造完之后,调用 Context3D.present()
以将它真正显示到屏幕上。实际工作发生的地方有两个:
开始一个新的播放器实例时,Flash Player 首先必须下载、解析主 SWF,并将之加载到内存中,然后才能开始执行它。您将在 Scout 中看到与之相关的以下活动(注意,与 Flash Player 的网络组件有一定程度的重叠):
Loader.load()
加载的资源的数据。每次接收到数据时,一个 ProgressEvent.PROGRESS
事件都会被分派给任何已注册处理程序。Loader.close()
。MovieClipLoader.onLoadInit
事件处理程序。Flash Player 支持的网络操作有三种主要类型:本地连接、TCP/HTTP 连接和流媒体。无论使用哪种类型,开始一般是设置网络连接或发出请求。网络操作比较费时,所以不是同步发生的。一旦您发出了请求,ActionScript 代码就可以在 Flash Player 在后台处理网络操作的同时执行其他任务。通过为相关事件注册事件处理程序,可以了解此操作何时完成或者状态发生更新。
要让同一台机器上的两个播放器实例进行通信(例如,假设加载了一个帮助器 SWF),可以设置一个 LocalConnection 对象,来让一个实例调用另一个实例的函数。Scout 显示以下与本地连接相关的活动:
send(connectionName, functionName, arguments)
,所以在接收 LocalConnection 对象时要调用 functionName(arguments)
。想要下载内容时,比如图像和其他 SWF,您通常使用 Loader 或 URLLoader 对象,它们使用 HTTP。您也可以使用 HTTP NetConnection 从服务器发送或接收数据。Scout 显示以下与下载相关的活动:
NetConnection.call()
之类函数通过 HTTP 发出的请求由 Flash Player 进行排队。这些排好队的请求定期地通过网络发送出去。NetConnection.call()
成功或返回错误,所以调用一个您传递给 Responder 对象构造函数的函数。Flash Player 也为来自服务器的流媒体(比如音频和视频数据)支持很多协议。可以使用 NetConnection 创建 NetStream,并指定协议。实时消息传递协议 (RTMP) 运行在 TCP 之上,实时媒体流协议 (RTMFP) 运行在 UDP 之上。在 Scout 中可以看到以下与流式传输相关的活动:
NetStream.client
对象的 onMetaData
属性,可以注册一个在接收到元数据时调用的事件处理程序。NetStream.close()
。SharedObject.connect()
。在多数台式机上,Flash Player 播放声音的效率很高。当对诸如 Sound 或 SoundChannel 之类的对象调用 flash.media 包中的函数时,执行声音操作花费的时间将显示在 Scout 的 ActionScript 面板中。您也可能看到下面这个活动:
Sound.onSoundComplete
处理程序,或者是用 ActionScript 3 编写的针对 SoundChannel 对象的 Event.SOUND_COMPLETE
处理程序。Flash Player 中的视频播放基本上是一个长期运行的网络操作。当您将想要播放的视频告诉 Flash Player 时,Flash Player 就会在后台发起一个持续活动。通过网络定期到达的数据被解压,然后显示在屏幕上。取决于平台、编解码器以及其他视频设置,需要的 CPU 时间差异很大。
Scout 目前不提供关于视频性能的很多信息,但是您可能会看到下面这个活动:
还有一些无法归为以上类别的其他 Flash Player 活动:
Flash Player 在等待发生某事情时,Scout 中显示为不活跃时间。这可能是因为在某件事情上阻塞了,或者只是已经完成了所有的工作。展开 Scout 的 Summary 面板中的 Inactive 类别,会看到这个时间分为以下部分或所有种类:
Condition.wait()
、MessageChannel.send()
或 MessageChannel.receive()
调用上。
就跟测量执行各种活动花费了多长时间一样,Flash Player 也跟踪它在使用多少内存。在 Scout 的 Summary 面板中可以看到该报告,就像 CPU 时间一样,内存使用情况也分为几类。Flash Player 只跟踪它显式分配的内存——有一些内存是操作系统分配的,比如说用于存储 Flash Player 可执行文件的内存,这不会显示在 Scout 中。
在 Scout 中查看一个会话的内存使用情况时,一定要明白总内存是所有正在运行的播放器实例使用的内存。其他播放器实例使用的内存出现在 Other 类别中,位于 Other Players 下面。此外,Uncategorized 类别下的一些内存可能是其他播放器实例使用的。一些数据结构在 Flash Player 中是共享的,因而难以归属于特定的播放器实例。在浏览器中剖析内容时,可能的话最好只运行 SWF。
Flash Player 尽力跟踪使用大量内存的主要数据结构,但是某些区域比另外一些区域涵盖得更好一些。目前,它测量音频和视频缓冲区或者 JITted ActionScript 代码使用的内存。这将和任何其他未跟踪的内部数据结构一起显示在 Uncategorized 类别下。
GPU 是显卡上的专用处理器,用于硬件加速呈现。它擅长于大规模并行计算,比如说定位和着色巨大的三角形阵列。这是与 CPU 进行的比较,CPU 可以完成更复杂的任务,但是只擅长于一次做一件事情。Stage3D 通过提供一个 ActionScript API 来利用 GPU,该 API 的作用是让您可以直接与之沟通。为了工作更为轻松,通常会用到一个较高级别的框架,比如针对 2D 内容的 Starling 和针对 3D 内容的 Away3D。但是请记住,这些框架是在幕后使用 GPU。
使用 Stage3D 时要记住的一件事情是,GPU 与 CPU 并行运行。这意味着,内容的速度局限于那个最慢的组件。即使您的 ActionScript 代码很快(所以 CPU 没有超载),如果分派 GPU 太多的工作,那么也不会得到您想要的帧速率。下面是使用 GPU 时的两个最常见性能问题:
Context3D.present()
时是在告诉 GPU 显示您所绘制的内容,意味着 GPU 应该轮换这两个分区。但是 GPU 每 1/60 秒才对它们轮换一次。这就是所谓的 VSync,它跟显示器更新图像的速度相关。如果 GPU 不能轮换,它将阻塞,这在 Scout 中显示为 Waiting for GPU。这通常不是问题,但是如果 CPU 跟不上 VSync 速率,它可能再三地错过最后期限,然后必须等待下一个 VSync,GPU 才能更新。如果发生此情况,通常可以通过设置较低的帧速率来避免额外的等待时间,从而改善性能。下面是一个重要的提示:如果您的内容在 Scout 中显示过多的 Waiting for GPU 时间,请尝试在 Flash Player 中临时禁用硬件加速(右击并选择 Settings)。这将导致 Flash Player 退回到软件呈现,等待时间将会消失,所以您可以确认问题是 GPU 相关的。
既然更多地了解了 Flash Player 的工作方式,那么接下来最好能够使用 Adobe Scout 来优化内容。记住,如果在使用 Scout 时忘记了一些指标的含义,您可以使用本文作为参考。祝您学习快乐!
标签:des style http io os 使用 ar java for
原文地址:http://www.cnblogs.com/jiahuafu/p/4013231.html