# 向代码中添加性能分析器标记

> Add profiler markers to mark up areas of your code.

向代码添加[性能分析器标记](/engine/6000.0/manual/analysis/profiler/adding-information-code/intro.md)，以便在 [Profiler 窗口](/engine/6000.0/manual/analysis/profiler/window.md)中的 [CPU 使用情况模块](/engine/6000.0/manual/analysis/profiler/collect-data/visualizing-data/cpu/introduction.md)的**时间轴视图**和**层级视图**中查看 `ProfilerMarker.Begin`、`ProfilerMarker.End` 或 `ProfilerMarker.Auto` 生成的样本：


**时间轴视图中具有元数据的性能分析器示例。:**
![](/api/media?file=/engine/6000.0/media/images/profiler-marker-metadata-timeline.png)


**层级视图中包含元数据的性能分析器样本。:**
![](/api/media?file=/engine/6000.0/media/images/profiler-marker-metadata-hierarchy.png)

## 资质要求

一些示例会用到 [Profiling Core 包](https://docs.unity3d.com/Packages/com.unity.profiling.core@latest)，在开始之前必须安装该包。因为 Unity Profiling Core 是核心包，所以在 Package Manager UI 中无法找到。要安装包，请执行以下操作之一：

* [添加名称](/engine/6000.0/manual/packages-list/packages/upm-ui/actions/quick.md)，即 `com.unity.profiling.core`。
* [通过此链接](/engine/6000.0/manual/com-unity-profiling.md)安装。

## 标记代码

要使用 [`ProfilerMarker` API](/engine/6000.0/script-reference/unity-profiling/profiler-marker.md)，请将要分析的代码放在对 `ProfilerMarker.Begin` 和 `ProfilerMarker.End` 的调用之间。例如：

```lang-csharp
using UnityEngine;
using Unity.Profiling;

public class ProfilerMarkerExample
{
    static readonly ProfilerMarker k_MyCodeMarker = new ProfilerMarker("My Code");

    void Update() {
        k_MyCodeMarker.Begin();
        Debug.Log("This code is being profiled");
        k_MyCodeMarker.End();
    }
}
```

\*\*注意：\*\*避免在性能分析器标记的名称中使用 `/` 字符，因为这会使 Profiler 窗口无法在 CPU 性能分析器模块的图表视图中突出显示该标记。

确保在调用 `End` 之前，`Begin` 和 `End` 调用之间的代码不会退出作用域。如果在调用 `End` 之前代码退出作用域，则系统会将错误消息记录到控制台。为了避免在每次返回之前都必须调用 `End`，可以使用 `Auto`，这样样本在离开作用域时会自动结束。有关更多信息，请参阅本文档中关于[自动关闭性能分析器标记代码块](#automatically-close)的部分。

Unity 会记录性能分析代码块的执行时间并将其报告给性能分析器，并将其显示在 [CPU 性能分析器模块中](/engine/6000.0/manual/analysis/profiler/collect-data/visualizing-data/cpu/introduction.md)，而无需使用[深度性能分析](/engine/6000.0/manual/analysis/profiler/collect-data/deep-profiling.md)。它将在 CPU 性能分析器模块的**层级视图**中显示为新条目，如下所示：


**Profiler 窗口中的性能分析器样本。:**
![](/api/media?file=/engine/6000.0/media/images/profiler-marker-full-sample.png)

### 自动关闭性能分析器标记代码块

使用 `ProfilerMarker.Auto` 可确保在代码块末尾自动调用 `ProfilerMarker.End`。以下是等效调用：

```lang-csharp
using Unity.Profiling;

public class MySystemClass
{
    static readonly ProfilerMarker k_UpdatePerfMarker = new ProfilerMarker("MySystem.Update");

    public void Update()
    {
        k_UpdatePerfMarker.Begin();
        // ...
        k_UpdatePerfMarker.End();

        using (k_UpdatePerfMarker.Auto())
        {
            // ...
        }
    }
}
```

与 `Begin()` 和 `End()` 调用不同，Unity 无法在非开发（发布）构建中编译排除 `ProfilerMarker.Auto` 调用。但是，它将返回 null，这样只会增加很少的开销。

还可以将 `ProfilerMarker.Auto` 与 `using var` 结合使用，一旦当前作用域结束，`End` 调用将自动发生。此方法可最大限度减少向代码添加 `ProfilerMarker` 实例时需要更改的代码量：

```lang-csharp
using Unity.Profiling;

public class MySystemClass
{
    static readonly ProfilerMarker k_UpdatePerfMarker = new ProfilerMarker("MySystem.Update");

    public void Update()
    {
        using var _ = k_UpdatePerfMarker.Auto();
        // ...
    }
}
```

\*\*注意：\*\*在使用 `ProfilerMarker` 进行标记的区域内不支持任何异步 `await` 和 `yield` 调用，即使使用 `Auto`，也会在控制台中记录错误消息。

## 向样本添加整数或浮点参数

有时，您可能希望向代码样本添加上下文，以确定代码长时间运行的特定条件。

例如，如果系统执行对象模拟，可使用性能分析器样本来传递对象的数量。如果性能分析器返回异常数值，且样本持续时间较长，这可能意味需要使用另一个线程进行模拟，将 CPU 工作拆分为多个帧（时间切片），或者调整应用程序的设计以避免掉帧。

`ProfilerMarker` 最多支持三个数字参数：[`ProfilerMarker<TP1>`](https://docs.unity3d.com/Packages/com.unity.profiling.core@1.0/api/Unity.Profiling.ProfilerMarker-1.html)、[`ProfilerMarker<TP1, TP2>`](https://docs.unity3d.com/Packages/com.unity.profiling.core@1.0/api/Unity.Profiling.ProfilerMarker-2.html) 和 [`ProfilerMarker<TP1, TP2, TP3>`](https://docs.unity3d.com/Packages/com.unity.profiling.core@1.0/api/Unity.Profiling.ProfilerMarker-3.html)：

```lang-csharp
using Unity.Profiling;

public class MySystemClass
{
  static readonly ProfilerMarker<int> k_PreparePerfMarker = new ProfilerMarker<int>("MySystem.Prepare", "Objects Count");
  static readonly ProfilerMarker<float> k_SimulatePerfMarker = new ProfilerMarker<float>(ProfilerCategory.Scripts, "MySystem.Simulate", "Objects Density");

  public void Update(int objectsCount)
  {
    k_PreparePerfMarker.Begin(objectsCount);
    // ...
    k_PreparePerfMarker.End();

    using (k_SimulatePerfMarker.Auto(objectsCount * 1.0f))
    {
      // ...
    }
  }
}
```

## 向样本添加字符串参数

`ProfilerMarker` API 支持将字符串参数添加到性能分析器标记中。如果要在应用程序加载关卡或数据文件时显示关卡或文件的名称，字符串参数会很有用。使用 [`ProfilerMarkerExtension`](https://docs.unity3d.com/Packages/com.unity.profiling.core@1.0/api/Unity.Profiling.ProfilerMarkerExtension.html) 方法将字符串参数与性能分析器样本一起传递：

```lang-csharp
using Unity.Profiling;

public class MySystemClass
{
  static readonly ProfilerMarker k_PreparePerfMarker = new ProfilerMarker("MySystem.Prepare");

  public void Prepare(string path)
  {
    k_PreparePerfMarker.Begin(path);
    // ...
    k_PreparePerfMarker.End();
  }
}
```

## 其他资源

* [将性能分析信息添加到代码中简介](/engine/6000.0/manual/analysis/profiler/adding-information-code/intro.md)
* [将性能分析器计数器添加到代码中](/engine/6000.0/manual/analysis/profiler/adding-information-code/add-counters-code.md)
* [CPU 使用情况性能分析器模块简介](/engine/6000.0/manual/analysis/profiler/collect-data/visualizing-data/cpu/introduction.md)
* [`ProfilerMarker` API](/engine/6000.0/script-reference/unity-profiling/profiler-marker.md)
* [Profiling Core 包](https://docs.unity3d.com/Packages/com.unity.profiling.core@latest)
