文档

Unity Engine

Unity Engine

性能分析器标记参考

Reference for built-in Profiler markers.
阅读时间25 分钟最后更新于 1 个月前

Unity 的代码配备了性能分析器标记,可用于深入了解应用程序中占用时间的内容。下表列出了一些内置标记。

主线程基础标记

主线程基础标记可清晰区分在应用程序上花费的时间与在 Unity 编辑器和性能分析器活动中花费的时间。您还可以将这些标记与
ProfilerRecorder
API 结合使用以获取主线程上一帧的时间信息,或者使用
FrameTimingManager
API 来获取运行时的高级帧统计信息。
此外,还可以使用 CPU Main Thread Frame Time、CPU Render Thread Frame Time 和 CPU Total Frame Time 等渲染性能分析器计数器来获取应用程序的 CPU 使用情况的高级时间信息。有关更多信息,请参阅渲染性能分析器计数器参考。

标记

描述

PlayerLoop包含源自应用程序主循环的所有样本。在播放器以活跃播放模式在编辑器中运行时,如果目标是编辑器而非播放模式,则 PlayerLoop 样本会嵌套在 EditorLoop 下。
EditorLoop
(仅限编辑器的标记)
包含源自编辑器主循环的所有样本。仅当在编辑器中对播放器进行性能分析时才会出现此样本。在使用性能分析器针对的目标是播放模式时,EditorLoop 样本会指示渲染和运行包含播放器的编辑器所花费的时间。

有关更多信息,请参阅播放模式和编辑模式样本。
Profiler.CollectEditorStats
(仅限编辑器的标记)
包含与收集不同活跃性能分析器模块的统计信息有关的所有样本。

在
Profiler.CollectGlobalStats
标记下嵌套的样本,展示了播放器在收集特定模块的统计数据时产生的开销。所有其他子样本仅反映它们在编辑器中的影响。

要消除特定模块的开销,请关闭模块的图表或调用
Profiler.SetAreaEnabled
。

**注意:**使用内置计数器的自定义性能分析器模块会启用内置计数器的区域,即使其所属的模块已禁用也是如此。要防止性能分析器收集这些统计信息并产生收集开销,请确保同时禁用内置性能分析器模块和自定义性能分析器模块。

脚本更新标记

除非使用作业系统,否则大多数脚本代码都嵌套在以下标记下面。有关作业系统样本的信息,请参阅本页面的多线程标记部分。
有关 Unity 更新循环的更多详细信息,请参阅事件函数执行顺序相关文档。您可以使用
PlayerLoop.SetPlayerLoop
将自己的回调插入到 Player Loop 中。如果直接将回调插入到主循环中,则脚本更新样本将自行显示。如果将回调作为子系统插入,则样本将显示在相应的主 PlayerLoopSystem 标记下。

标记

描述

BehaviourUpdate包含
MonoBehaviour.Update
方法的所有样本。
CoroutinesDelayedCalls包含首次生成后的所有协程样本。
FixedBehaviourUpdate包含
Monobehaviour.FixedUpdate
方法的所有样本。
PreLateUpdate.ScriptRunBehaviourLateUpdate包含
Monobehaviour.LateUpdate
方法的所有样本。
Update.ScriptRunBehaviourUpdate包含
MonoBehaviour.Update
和协程的所有样本。

渲染和 VSync 标记

这些标记包含 CPU 在其中花时间来处理 GPU 的数据,或者可能在其中等待 GPU 完成的样本。如果 GPU 性能分析器模块不可用或者增加过多开销,则性能分析器模块详细信息面板中的工具栏不会显示此信息。这些标记下的样本可用于很好地了解应用程序的性能瓶颈是在 CPU 还是 GPU。

标记

描述

WaitForTargetFPS指示应用程序在等待
Application.targetFrameRate
指定的目标 FPS 时所花费的时间。

如果该样本是 Gfx.WaitForPresentOnGfxThread 的子样本,则代表应用程序等待 GPU 所花费的时间。例如,如果在 QualitySettings.vSyncCount 中进行了配置,或者如果在目标平台上实施了 vSync,这可能是 GPU 等待下一个 VSync 所花费的时间。不过,即使 GPU 尚未完成一帧的计算,也会发出具有此标记的样本。

要确定导致具有此标记的样本为何耗时过长,可切换到 CPU 性能分析器模块块中的时间轴视图。在此视图中,可以检查渲染线程的运行情况,以及在当前帧与相邻帧中此样本结束时间的间隔。

如果该间隔持续时间大于应用程序的帧时间(基于目标帧率或 vSync),则表示帧的渲染或计算时间太长。如果是这种情况,需要调查渲染线程,了解与执行其他为 GPU 准备和发送指令的任务相比,渲染线程在 Gfx.PresentFrame 操作上花了多少时间。如果渲染线程在 Gfx.PresentFrame 中花费了大量时间,则渲染工作受限于 GPU。如果渲染线程的时间用于准备命令,则应用程序受限于 CPU。

若应用程序受限于 GPU,想知道优化方向,可使用 Unity 性能分析器或平台性能分析器对 GPU 工作进行性能分析。有关更多信息,请参阅有关如何优化图形性能的用户手册文档。

**注意:**编辑器不会在 GPU 上进行 VSync,而是使用 WaitForTargetFPS 来模拟 VSync 的延迟。某些平台(特别是 Android 和 iOS)会强制执行 VSync 或默认帧率上限为 30 或 60。
Gfx.PresentFrame表示应用程序在等待 GPU 渲染和呈现帧方面花费的时间,其中包括等待 VSync 的时间。

主线程上带有 WaitForTargetFPS 标记的样本会显示等待 VSync 所花费的时间。
Gfx.ProcessCommands包含对渲染线程上渲染命令的所有处理。应用程序可能会花费此处理时间的一部分来等待 VSync 或主线程的新命令;可通过子样本 Gfx.WaitForPresentOnGfxThread 来了解此内容。
Gfx.WaitForCommands指示渲染线程已准备好接受新命令。如果看到此标记,则可能指示主线程上存在瓶颈。
<GraphicsAPIName>.WaitForLastPresent
例如:
GfxDeviceD3D11.WaitForLastPresent
GfxDeviceD3D12.WaitForLastPresent
GfxDeviceMetal.WaitForLastPresent
当主线程等待 GPU 将帧号翻转到屏幕 (
Time.frameCount - QualitySettings.maxQueuedFrames + 1
) 时,会出现带有此标记的样本。这意味着如果 QualitySettings.maxQueuedFrames 大于 1,则此时间用于等待 GPU 翻转应用程序在前一个主线程帧中请求渲染的帧。

有关此样本的更多详细信息以及 Unity 帧管线的概述,请参阅关于修复时间增量的 Unity 博客文章。
Gfx.WaitForPresentOnGfxThread指示主线程已准备好开始渲染下一帧,但是渲染线程未结束对于 GPU 呈现该帧的等待。这可能表明应用程序是受限于 GPU。要查看渲染线程同时在哪些方面花费时间,请查看 CPU 性能分析器模块的时间轴视图。

如果渲染线程在 Camera.Render 中花费时间,则表明应用程序受限于 CPU,可能在向 GPU 发送绘制调用或纹理数据方面耗时过长。

如果渲染线程在 Gfx.PresentFrame 中花费时间,则表示应用程序受限于 GPU,也有可能是在 GPU 上等待 VSync。Gfx.WaitForPresentOnGfxThread 的 WaitForTargetFPS 子样本表示当前阶段应用程序等待 VSync 所花费的时间占比。当前阶段是从 Unity 指示图形 API 交换缓冲区到此操作完成之间的一段时间。
Gfx.WaitForRenderThread指示主线程正在等待渲染线程处理位于命令流中的所有命令。带有此标记的样本仅出现在多线程渲染中。

后端脚本标记

这些样本突出显示 Mono 或 IL2CPP 脚本后端活动,对于垃圾收集和分配问题的故障排除非常有用。

标记

描述

GC.Alloc表示托管堆(包含受自动垃圾回收影响的托管分配)中的分配。要减少应用程序在自动垃圾收集方面所花费的时间,应该尽量减少这些类型的样本。
GC.Collect表示与垃圾收集相关的样本。每当 Unity 需要执行垃圾收集时,它都会停止运行程序代码,并且仅在垃圾回收器完成所有工作后才恢复正常执行。**注意:**如果启用了增量垃圾收集,垃圾回收器可能无法在一帧内完成工作。

这种中断可能会导致应用程序的执行出现延迟,延迟时间短则不到一毫秒,长则可达数百毫秒。这取决于垃圾回收器需要处理的内存量以及应用程序运行的平台。如需了解更多信息,请参阅有关了解自动内存管理的文档。
Mono.JIT
仅适用于 Mono
包含与脚本方法的即时编译相关的样本。当函数首次执行时,Mono 会对其进行编译,Mono.JIT 代表的就是这种编译所产生的开销。
UnsafeUtility.Malloc包含调用 UnsafeUtility.Malloc 以分配非托管内存的样本。虽然垃圾回收器不跟踪此内存,但分配内存可能会产生显著性能影响(随此样本出现)。要调查此调用的源,可以在性能分析器 (Profiler) 窗口中为此标记启用调用栈 (Call Stack) 记录。

多线程标记

这些标记包含的样本不测量消耗的 CPU 周期,而是突出显示与线程同步和作业系统相关的信息。查看这些样本时,使用 CPU 性能分析器模块的时间轴 (Timeline) 视图可以检查其他线程上同时发生的操作。

标记

描述

Idle包含指示工作线程处于非活动状态的时间长度的样本。工作线程在作业系统不使用它的任何时间都处于非活动状态,会进入等待模式以等待信号标。

JobSystem 唤醒 Idle 样本时(例如,为了调度新作业),这些样本之间通常会出现较小的间隙时间。较长的间隙可能表示尚未检测的原生作业正在线程上运行。
JobHandle.Complete包含指示作业同步点何时发生的样本。同步点可能会对应用程序产生性能影响,并可能会干扰多线程作业代码的执行。要更容易找到同步点发生的确切位置,请为此样本启用调用栈 (Call Stack) 记录。在 CPU 性能分析器模块的时间轴 (Timeline) 视图中,可以启用流程事件 (Flow Events) 以查看此时完成的作业。
Semaphore.WaitForSignal包含描述线程上的同步点的样本。要找出所等待的线程,请在时间轴 (Timeline) 视图中查看在此线程之前不久结束的所有样本。
WaitForJobGroupID此标记意味着在 JobHandle 上触发了同步栅栏。这可能导致任务窃取的情况,即某个工作线程完成自身任务后,会去查看并执行其他工作线程的作业任务。在该标记下显示的作业示例,就是这些被执行的“窃取”任务。被“窃取”的作业任务并非一定是原本在等待的任务。

物理标记

下表概括了一些高级的物理性能分析器标记。
FixedUpdate
会调用所有这些测量数据。

标记

描述

Physics.FetchResults包含从物理引擎收集物理模拟结果的样本,例如接触流、触发器重叠和关节断裂事件。
Physics.Interpolation包含测量
Physics.Interpolation
方法的执行时间的样本。此方法管理应用程序中所有物理对象的位置和旋转的插值。
Physics.Processing包含花费时间等待主线程直到物理模拟在所有线程上完成的样本。如果应用程序在
Physics.Processing
方面花费大量时间,但是在场景中只有几个与物理相关的游戏对象,这可能表明工作线程由于作业窃取机制,接手了其他系统任务,并且将其报告为物理任务。这是因为在等待期间,主线程会从高优先级队列中拾取作业。
Physics.ProcessingCloth包含测量
Physics.ProcessingCloth
方法的执行时间的样本。此方法处理所有布料物理作业。展开此样本可显示物理系统内部完成的工作的低级细节。
Physics.ProcessReports包含与通过回调(如
OnTriggerEnter
)将物理数据转发到脚本所花费的时间相对应的样本。**注意:**这些样本不计算所需的数据,因为它们已经在
FetchResults
期间做好准备。

包括四个不同的阶段:
Physics.Contacts包含测量
Physics.Contacts
的执行时间的样本。这会处理
OnCollisionEnter
、
OnCollisionExit
和
OnCollisionStay
事件。
Physics.JointBreaks包含测量
Physics.JointBreaks
的执行时间的样本。这会处理与受损关节相关的更新和消息。
Physics.TriggerEnterExits包含测量
Physics.TriggerEnterExits
的执行时间的样本。这会处理
OnTriggerEnter
和
OnTriggerExit
事件。
Physics.TriggerStays包含测量
Physics.TriggerStays
的执行时间的样本。这会处理
OnTriggerStay
事件。
Physics.Simulate包含测量为
Physics.Simulate
方法处理先决条件所花费的时间量的样本。此方法指示物理系统运行其模拟,这会更新当前物理的状态。
Physics.UpdateBodies包含更新所有物理体的位置和旋转的样本。对于每个具有刚体组件的游戏对象,带有此标记的样本会从物理系统读取姿势并将其写入变换组件。
Physics.UpdateCloth包含测量
Physics.UpdateCloth
方法的执行时间的样本。此方法处理与布料及其蒙皮网格相关的更新。
有关脚本生命周期及脚本生命周期内的一般样本的更多信息,请参阅事件函数的执行顺序的相关文档。

动画标记

下表包含动画系统中的标记。有关动画系统性能的一般信息,请参阅 Mecanim 性能与优化页面。

PreLateUpdate.DirectorUpdateAnimationBegin 阶段

在此阶段,将处理每个激活并启用的 Animator。无论剔除模式和可见性如何,都会处理活动的 Animator。
以
Director.
开头的标记还可以涵盖播放对象 (Playables) 和时间轴 (Timeline)

标记

描述

Director.PrepareFrame设置、调度和等待
Director.PrepareFrameJob
作业。这些作业评估所有激活的 Animator 组件的状态机。
Director.PrepareFrameJob (job)计算单个活动 Animator 的状态机。处理 Animator 所需的时间,会随着其状态机的复杂程度增加而变长,也就是与状态数量、过渡数量以及层数量相关。

对具有实现
OnStateMachineEnter
或
OnStateMachineExit
监听器的
StateMachineBehaviours
的状态机的评估将受限于主线程。
Animators.PrepareFirstPass为后续处理步骤做好准备。
Animators.ProcessGraphJob构建、调度并等待
Animator.ProcessGraph
作业的结果。
Animators.ProcessGraph (job)评估所有连接的动画剪辑 (AnimationClips) 中的所有属性。

通过将所有剪辑的根运动属性混合在一起来计算根运动位移。

收集当前
deltaTime
的新动画事件。

在评估动画剪辑 (AnimationClips) 的属性时,曲线段会缓存在帧之间的本地,以避免不必要地多次读取动画剪辑 (AnimationClips) 的内存。
Animators.FireAnimationEventsAndBehaviours在
StateMachineBehaviours
和 MonoBehaviour 上触发所有动画事件消息,但在
Director.PrepareFrameJob
中已触发的
OnStateMachineEnter
或
OnStateMachineExit
监听器除外。
Animators.ApplyOnAnimatorMove应用根运动并在 MonoBehaviours 上触发
OnAnimatorMove
消息。

PreLateUpdate.DirectorUpdateAnimationEnd

在此阶段,仅处理具有剔除模式
Always Update
的 Animator 和具有剔除模式
UpdateTransform
或
Cull Completely
的可见 Animator。通过根运动移出帧且具有
Cull Completely
的 Animator 不会参与此阶段。由 StateMachineBehaviours 和 AnimationEvents 触发的用户代码所禁用的 Animator 也是如此

标记

功能

Animators.PrepareSecondPass设置后续处理步骤。这包括根据剔除模式和可见性状态对 Animator 进行筛选。
Animators.SortWriteJob变换系统一次只允许单个线程修改变换层级结构 (Transform Hierarchy)。为了适应此约束,
Animators.SortWriteJob
按 Transform.root 对
Animators.WriteTransforms
作业进行分组。

为了获得最佳性能,请避免在同一变换层级结构中使用多个 Animator,这样可以提高任务调度和并行处理的精细度。
Animators.ProcessAnimationsJob构建、调度并等待
Animators.ProcessAnimations
作业的结果。
Animator.ProcessAnimations (job)对单个 Animator 中当前处于激活状态的动画剪辑 (AnimationClips) 的所有属性进行混合,但不包括根运动的属性。将它们应用于内部的角色模型 (avatar) 表征。

此标记的持续时长会随动画及混合的复杂程度而变化。
OnAnimatorIK设置动画 IK。为每个启用 IK pass 的 Animator Controller 层进行一次此调用。
Animators.WriteJob构建、调度并等待
Animator.WriteTransform
作业的结果。这些作业会将动画角色模型 (avatar) 的变换姿势写入相关游戏对象的变换层级结构。
Animators.WriteTransforms (job)将所有动画变换从工作线程写入场景。
Animator.WriteProperties将任何不是变换姿势的动画属性写入目标对象。

性能警告

CPU 性能分析器可检测到一些常见性能问题,并发出相关警告。这些警告会显示在模块详细信息面板中的 CPU 性能分析器模块的层级结构视图中的警告 (Warning) 列内。
性能分析器可以检测到在性能至关重要的背景中应避免的某些特定调用。这种情况下会显示警告以及操作对性能产生影响的原因,如下所示:

警告

描述

Animation.DestroyAnimationClip
Animation.AddClip
Animation.RemoveClip
Animation.Clone
Animation.Deactivate
指示已触发 RebuildInternalState。RebuildInternalState 是一种操作,它遍历动画组件中每个剪辑的曲线列表,然后将每条曲线重新绑定到游戏对象上某个组件中的值。

这是一项极为耗费资源的操作,因此应尽可能避免在运行时调用这些方法。
AssetBundle.asset/allAssets指示在 AssetBundle 加载未完成时(AssetBundleRequest.isDone 为 false),Unity 调用了 AssetBundleRequest.assets/allAssets API。这会导致主线程卡顿并等待加载操作完成。
AsyncUploadManager.AsyncBufferResized
AsyncUploadManager.AsyncBufferDelete
指示用于向 GPU 上传数据的内部缓冲区因容量不足而被调整大小。这种大小调整比较缓慢,会导致 CPU 活动出现峰值。

如果能够腾出内存来预先分配更大的空间,就可以避免此警告。

您可以使用质量设置 (Quality Settings) 中的异步上传缓冲区大小 (Async Upload Buffer Size) 设置来设置默认大小。

AsyncUploadManager.AsyncBufferResize 标记指示新分配的大小,您可以将其用作默认缓冲区大小的参考。
Rigidbody.SetKinematic为刚体重新创建非凸面体 MeshCollider。

其他资源