Unity Profiler 原生插件可以通过脚本从 Unity 中提取数据,以便在诸如 Razor (PS4)、PIX(Xbox、Windows)、Chrome Tracing、ETW、ITT、Vtune 和 Telemetry 之类的外部工具中进行分析。Unity Profiler 记录事件,Profiler 原生插件 API 将这些事件公开给第三方性能分析 API,后者再将它们传递给相关的分析工具。
以下 Unity Profiler 功能有助于捕获用于性能分析的检测数据:
__类别__:Unity 将性能分析数据分组到不同类别,例如渲染 (Rendering)、脚本 (Scripting) 和动画 (Animation),并为每个类别指定颜色。这有助于在 Profiler 窗口中直观区分数据类型。Profiler 原生插件 API 可以获取这些颜色,以便可以在外部性能分析器中使用它们。
__用途标志__:Unity Profiler 将以下用途标志应用于事件标记以帮助过滤数据:
描述一个标记在 Unity Editor 或开发或发布播放器中是否可用的可用性标志。
与您在 Editor 中执行的任务类型相关的详细级别,以及任务所需的信息级别(例如,内部、调试或用户级别)。
用途标志可用于在将数据传递给外部工具之前对数据进行过滤以减少生成的数据量,并在外部工具中过滤数据以减少信息中的干扰。
__帧事件__:Profiler 原生插件 API 可以在外部性能分析器中执行帧时间分析。
__线程性能分析__:Unity 在线程(例如,主线程、渲染线程和作业系统工作线程)上执行大量工作。您可以使用 Profiler 原生插件 API 在任何线程上启用性能分析。
原生 Profiler 插件 API 提供了 Unity 子系统与第三方性能分析 API 之间的接口。此 API 由 IUnityProfilerCallbacks 头公开,并由 Unity 存储在 Unity 安装目录的 <UnityInstallPath>\Editor\Data\PluginAPI 文件夹中。
要使用 Unity Profiler 在外部性能分析器中生成的检测数据,请使用以下最少量的回调:
RegisterCreateCategoryCallback
:每当 Unity 创建一个类别时,Profiler 都会获取类别名称和颜色,并注册此回调。
RegisterCreateMarkerCallback
:每当 Unity 创建一个标记时,Profiler 都会获取标记名称、类别和用途标志,并注册此回调。UnityProfilerMarkerDesc 表示一个持久性指针,可用于过滤 RegisterMarkerEventCallback 中的标记。
RegisterMarkerEventCallback
:使用 Unity Profiler 等效工具跟踪外部性能分析器 push/pop 标记,并为给定的标记注册事件回调。Unity Profiler 在发生限定范围的检测事件或单次事件时运行指定的回调。您还可以将内存分配和垃圾收集事件作为标记进行跟踪。Unity 将这些事件分别表示为 GC.Alloc
和 GC.Collect
。
RegisterFrameCallback
:将样本封装到逻辑帧中以便在没有帧概念的外部性能分析器中使用,并注册当 Unity 启动下一个逻辑 CPU 帧时由 Unity Profiler 运行的回调。
RegisterCreateThreadCallback
:每当 Unity 注册一个用于性能分析的线程时,Profiler 都会获取内部线程名称,并为该线程注册此回调。
以下示例显示如何将开始和结束事件发送到外部性能分析器:
| #include <IUnityInterface.h>
# include <IUnityProfilerCallbacks.h><br/>
static IUnityProfilerCallbacks* s_UnityProfilerCallbacks = NULL;
static void UNITY_INTERFACE_API MyProfilerEventCallback(
const UnityProfilerMarkerDesc* markerDesc,
UnityProfilerMarkerEventType eventType,
unsigned short eventDataCount,
const UnityProfilerMarkerData* eventData, void* userData)
{
switch (eventType)
{
case kUnityProfilerMarkerEventTypeBegin:
{
MyProfilerPushMarker(markerDesc->name);
break;
}
case kUnityProfilerMarkerEventTypeEnd:
{
MyProfilerPopMarker(markerDesc->name);
break;
}
}
}
static void UNITY_INTERFACE_API MyProfilerCreateEventCallback(
const UnityProfilerMarkerDesc* markerDesc, void* userData)
{
s_UnityProfilerCallbacks->
RegisterEventCallback(markerDesc, MyProfilerEventCallback, NULL);
}
extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginLoad(IUnityInterfaces* unityInterfaces)
{
s_UnityProfilerCallbacks = unityInterfaces->Get<IUnityProfilerCallbacks>();
s_UnityProfilerCallbacks->
RegisterCreateEventCallback(&MyProfilerCreateEventCallback, NULL);
}
extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginUnload()
{
s_UnityProfilerCallbacks->
UnregisterCreateEventCallback(&MyProfilerCreateEventCallback, NULL);
s_UnityProfilerCallbacks->
UnregisterEventCallback(NULL, &MyProfilerEventCallback, NULL);
}
__注意__:要从所有标记中取消注册给定的回调,请将第一个参数设置为 NULL 后运行 UnregisterEventCallback。
您可以每帧动态注册和取消注册标记回调。以下示例说明了如何根据第三方性能分析状态通过启用和禁用回调来最大限度降低性能分析开销。
| static void UNITY_INTERFACE_API SystraceFrameCallback(void* userData)
{
bool isCapturing = ATrace_isEnabled();
if (isCapturing != s_isCapturing)
{
s_isCapturing = isCapturing;
if (isCapturing)
{
s_UnityProfilerCallbacks-><br/> RegisterCreateMarkerCallback(SystraceCreateEventCallback, NULL);
}
else
{
s_UnityProfilerCallbacks->
UnregisterCreateMarkerCallback(SystraceCreateEventCallback, NULL);
s_UnityProfilerCallbacks->
UnregisterMarkerEventCallback(NULL, SystraceEventCallback, NULL);
}
}
}
__注意__:为了最大限度减少回调开销,可以仅在捕获期间注册回调。
Systrace API 提供了 ATrace_isEnabled API,用于确定是否已启用捕获。您可以逐帧进行此检查以动态启用或禁用回调。有关更高级用途的示例,请参阅 UnitySystracePlugin 代码仓库。
Unity 具有以下包含有用元数据的标记:
Unity 为 Profiler.BeginSample 和 Profiler.EndSample 事件保留的标记。kUnityProfilerMarkerEventTypeBegin eventType
对应于 Profiler.BeginSample
事件并具有以下数据:
Int32:UnityEngine.Object
实例 ID,如果未指定对象,则为 0。
UInt16 数组:传递给 Profiler.BeginSample
的 UTF16 字符串。此大小以字节为单位。
UInt32:类别索引。
与垃圾收集分配相对应的标记。该标记提供以下数据: