# 性能分析低级原生插件

> Extend the profiler and collect performance data from native plug-ins.

可以使用低级原生插件性能分析器 API 扩展[性能分析器](/engine/6000.0/manual/analysis/profiler/introduction.md)并收集原生插件代码的性能数据，或是准备性能分析数据以发送到第三方性能分析工具，例如 Razor (PS4)、PIX（Xbox、Windows）、Chrome Tracing、ETW、ITT、Vtune 或 Telemetry。

低级原生插件性能分析器 API 提供以下接口来用于 Unity 性能分析器与外部工具之间的通信：

* **IUnityProfiler**：使用此接口可从 C/C++ 原生插件代码向 Unity 性能分析器添加检测事件。
* **IUnityProfilerCallbacks**：使用此接口可拦截 Unity 性能分析器事件并将它们存储或重定向到其他工具。

## IUnityProfiler API 参考##iunityprofiler-api-reference

使用 `IUnityProfiler` 插件 API 可将检测添加到原生插件的 C/C++ 代码。

该插件 API 由 `IUnityProfiler` 接口表示，该接口在 `IUnityProfiler.h` 头文件中进行声明。Unity 将标头存储在 Unity 安装的 `<UnityInstallPath>\Editor\Data\PluginAPI` 文件夹中。（在 macOS 上，右键单击 Unity 应用程序，然后选择**显示软件包内容 (Show Package Contents)**。标头位于 `Contents\PluginAPI`）。

| **方法**                  | **描述**                                |
| ----------------------- | ------------------------------------- |
| `CreateMarker`          | 创建性能分析器标记，它表示命名检测范围，随后可以用于生成检测样本。     |
| `SetMarkerMetadataName` | 指定可以与检测样本一起传递以用于性能分析器标记的自定义参数名称。      |
| `BeginSample`           | 开始按性能分析器标记命名的代码的检测部分。                 |
| `EndSample`             | 结束检测部分。                               |
| `EmitEvent`             | 使用元数据发出通用事件。                          |
| `IsEnabled`             | 如果性能分析器在捕获数据，则返回 1。                   |
| `IsAvailable`           | 对于可使用性能分析器的编辑器或开发播放器返回 1，对于发布播放器返回 0。 |
| `RegisterThread`        | 以指定名称注册当前线程。                          |
| `UnregisterThread`      | 从性能分析器取消注册当前线程。\\                     |

### IUnityProfiler 示例##iunityprofiler-example

以下示例生成性能分析器事件，这些事件随后会显示在 Profiler 窗口中。

```lang-csharp
#include <IUnityInterface.h>
#include <IUnityProfiler.h>

static IUnityProfiler* s_UnityProfiler = NULL;
static const UnityProfilerMarkerDesc* s_MyPluginMarker = NULL;
static bool s_IsDevelopmentBuild = false;

static void MyPluginWorkMethod()
{
    if (s_IsDevelopmentBuild)
        s_UnityProfiler->BeginSample(s_MyPluginMarker);

    // Code I want to see in Unity Profiler as "MyPluginMethod".
    // ...

    if (s_IsDevelopmentBuild)
        s_UnityProfiler->EndSample(s_MyPluginMarker);
}

extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginLoad(IUnityInterfaces* unityInterfaces)
{
    s_UnityProfiler = unityInterfaces->Get<IUnityProfiler>();
    if (s_UnityProfiler == NULL)
        return;
    s_IsDevelopmentBuild = s_UnityProfiler->IsAvailable() != 0;
    s_UnityProfiler->CreateMarker(&s_MyPluginMarker, "MyPluginMethod", kUnityProfilerCategoryOther, kUnityProfilerMarkerFlagDefault, 0);
}

extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginUnload()
{
    s_UnityProfiler  = NULL;
}
```

## IUnityProfilerCallbacks API 回调##iunityprofilercallbacks-api-callbacks

原生性能分析器插件 API 在 Unity 子系统与第三方性能分析 API 之间提供了接口，以便可以使用外部性能分析工具对 Unity 应用程序进行性能分析。`IUnityProfilerCallbacks` 标头公开了 API，Unity 将其存储在 Unity 安装的 `<UnityInstallPath>\Editor\Data\PluginAPI` 文件夹中。（在 macOS 上，右键单击 Unity 应用程序，然后选择**显示软件包内容 (Show Package Contents)**。标头位于 `Contents\PluginAPI`）。

以下 Unity 性能分析器功能有助于捕获检测数据，以便可以分析应用程序的性能：

| **性能分析器功能** | **描述**                                                                                                                                                                                                          |
| ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **类别**      | Unity 将性能分析数据分组到不同类别，例如渲染 (Rendering)、脚本 (Scripting) 和动画 (Animation)，并为每个类别指定颜色。进行颜色编码的类别有助于在 Profiler 窗口中直观区分数据类型。性能分析器原生插件 API 可以获取这些颜色，以便可以在外部性能分析工具中使用它们。                                                   |
| **用途标志**    | 用途标志起到过滤器的作用，可减少 Unity 发送到外部性能分析工具的数据量。在 Unity 将性能分析数据发送到外部工具之前，可以使用使用标志从这些数据中删除不必要的信息。性能分析器将以下用途标志应用于事件标记以便过滤数据：**可用性标志**描述一个标记在 Unity 编辑器或开发或发布播放器中是否可用。与您在编辑器中执行的任务类型相关的**详细级别**，以及任务所需的信息级别（例如，内部、调试或用户级别）。 |
| **帧事件**     | 可以使用性能分析器原生插件 API 在外部性能分析工具中执行帧时间分析。                                                                                                                                                                            |
| **线程性能分析**  | Unity 在线程（例如，主线程、渲染线程和作业系统工作线程）上执行大量工作。可以使用性能分析器原生插件 API 在任何线程上启用性能分析。                                                                                                                                          |

要在外部分析器中使用 Unity 性能分析器生成的检测数据，可以在集成第三方性能分析器的 C/C++ 插件代码中使用最少量的回调：

| **回调**                           | **功能**                                                                                                                                                                                                    |
| -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `RegisterCreateCategoryCallback` | 注册 `IUnityProfilerCreateCategoryCallback` 回调，以便每当 Unity 创建类别时都获取性能分析器类别名称和颜色。                                                                                                                             |
| `RegisterCreateMarkerCallback`   | 注册一个 `IUnityProfilerCreateMarkerCallback` 回调，每当 Unity 创建标记时都会调用该回调。使用它可获取标记的名称、性能分析器类别和用途标志。回调函数的 const `UnityProfilerMarkerDesc* markerDesc` 参数表示指向标记描述的持久性指针，可以用于在 `RegisterMarkerEventCallback` 中过滤标记。 |
| `RegisterMarkerEventCallback`    | 注册 IUnityProfilerMarkerEventCallback 回调，Unity 在发生单次事件、限定范围的事件、内存分配事件或垃圾收集事件时会调用该回调。随后可以使用此回调在外部性能分析工具中调用相关函数。\*\*注意：\*\*Unity 使用 `GC.Alloc` 标记表示内存分配事件，使用 `GC.Collect` 标记表示垃圾收集事件。                        |
| `RegisterFrameCallback`          | 将样本封装到逻辑帧中，以便不使用帧的外部性能分析工具可以使用这些样本。还注册一个回调，Unity 性能分析器在 Unity 启动下一个逻辑 CPU 帧时会运行该回调。                                                                                                                       |
| `RegisterCreateThreadCallback`   | 注册一个回调，以便每当 Unity 注册用于性能分析的线程时都可获取内部线程名称。                                                                                                                                                                 |

### IUnityProfilerCallbacks 示例##iunityprofilercallbacks-example

此示例演示如何将 Unity 性能分析器事件传递给另一个具有压入/弹出语义的性能分析器。它提供两种函数：

* `void MyProfilerPushMarker(const char* name)`：推送指定的标记。
* `void MyProfilerPopMarker()`：弹出检测标记。

以下示例提供将开始和结束检测事件从 Unity 性能分析器传递到外部性能分析器所需的最小实现：

```lang-csharp
#include <IUnityInterface.h>
#include <IUnityProfilerCallbacks.h>

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();
            break;
        }
    }
}

static void UNITY_INTERFACE_API MyProfilerCreateMarkerCallback(const UnityProfilerMarkerDesc* markerDesc, void* userData)
{
    s_UnityProfilerCallbacks->RegisterMarkerEventCallback(markerDesc, MyProfilerEventCallback, NULL);
}

extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginLoad(IUnityInterfaces* unityInterfaces)
{
    s_UnityProfilerCallbacks = unityInterfaces->Get<IUnityProfilerCallbacks>();
    s_UnityProfilerCallbacks->RegisterCreateMarkerCallback(&MyProfilerCreateMarkerCallback, NULL);
}

extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginUnload()
{
    s_UnityProfilerCallbacks->UnregisterCreateMarkerCallback(&MyProfilerCreateMarkerCallback, NULL);
    s_UnityProfilerCallbacks->UnregisterMarkerEventCallback(NULL, &MyProfilerEventCallback, NULL);
}
```

\*\*注意：\*\*要从所有标记中取消注册给定的回调，请将第一个参数设置为 `null` 后运行 `UnregisterEventCallback`。

### UnitySystracePlugin 示例##unitysystraceplugin-example

您可以每帧动态注册和取消注册标记回调。以下示例根据第三方性能分析状态通过启用和禁用回调来最大限度降低性能分析开销。

```lang-csharp
| static void UNITY_INTERFACE_API SystraceFrameCallback(void* userData)
{
    bool isCapturing = ATrace_isEnabled();
    if (isCapturing != s_isCapturing)
    {
        s_isCapturing = isCapturing;
        if (isCapturing)
        {
            s_UnityProfilerCallbacks->
              RegisterCreateMarkerCallback(SystraceCreateEventCallback, NULL);
        }
        else
        {
            s_UnityProfilerCallbacks->
              UnregisterCreateMarkerCallback(SystraceCreateEventCallback, NULL);
            s_UnityProfilerCallbacks->
              UnregisterMarkerEventCallback(NULL, SystraceEventCallback, NULL);
        }
    }
}
```

\*\*注意：\*\*要从所有标记中取消注册给定的回调，请将第一个参数设置为 `null` 后运行 `UnregisterEventCallback`。

## 特殊标记##special-markers

Unity 具有以下包含有用元数据的特殊标记：

* `Profiler.DefaultMarker`
* `GC.Alloc`

### Profiler.DefaultMarker##profiler.defaultmarker

`Profiler.DefaultMarker` 是 Unity 为 [Profiler.BeginSample](/engine/6000.0/script-reference/unity-engine-profiling/profiler/begin-sample.md) 和 [Profiler.EndSample](/engine/6000.0/script-reference/unity-engine-profiling/profiler/end-sample.md) 事件保留的标记。

在上一个示例中，`kUnityProfilerMarkerEventTypeBegin eventType` 对应于 `Profiler.BeginSample` 事件，并具有以下数据：

* Int32：`UnityEngine.Object` 实例 ID。如果未指定对象，则此项为 0。
* UInt16 数组：传递给 `Profiler.BeginSample` 的 UTF16 字符串。此大小以字节为单位。
* UInt32：类别索引。

### GC.Alloc##gc.alloc

`GC.Alloc` 与垃圾收集分配相对应的标记。该标记提供以下数据：

* Int64：分配大小。

## 其他资源##additional-resources

* [性能分析器简介](/engine/6000.0/manual/analysis/profiler/introduction.md)
* [将性能分析信息添加到代码中](/engine/6000.0/manual/analysis/profiler/adding-information-code.md)
* [原生插件简介](/engine/6000.0/manual/scripting/compilation-and-code-reload/plug-ins/native.md)
