在不进行调试的情况下分析性能探查器中的 CPU 使用情况(C#、Visual Basic、C++、F#)

开始调查应用中的性能问题的好方法之一是了解其 CPU 使用情况。 “CPU 使用情况”性能工具显示 C++、C#/Visual Basic 中执行代码所花费的 CPU 时间和百分比。

CPU 使用情况工具可帮助你:

  • 诊断团队代码库中的慢速或进程挂起。 该工具可帮助你诊断团队生产代码出现的问题。 该工具提供数据的自动见解和各种视图,以便分析和诊断性能问题。

  • 识别 DevOps 方案中的性能问题,例如当客户报告在旺季期间某些请求或订单未通过零售网站时。 通常,问题在生产中,并且目前很难进行调试,但此工具可以帮助你捕获问题的足够信息和证据。 收集跟踪文件后,分析可以快速帮助你了解潜在原因,并在代码上下文中提供建议,以便你可以执行后续步骤来解决此问题。

  • 如果 API 请求中不存在延迟问题,则可以使用 CPU 使用率工具检查是否存在高 CPU 使用率和其他相关问题。 CPU 使用率工具可帮助你确定瓶颈,让你可以缩小优化的范围。

CPU 使用情况工具对本地跟踪会话和生产都很有用。 还可以采用以下方法启动 CPU 使用情况工具:使用键盘快捷方式 Alt+F2,然后选择“CPU 使用情况”,或使用 dotnet-tracedotnet-monitor 等工具打开已收集的跟踪。 (对于 .NET 生产代码,这是最有可能选择的跟踪收集方式。)

“CPU 使用情况”工具可以在打开的 Visual Studio 项目、在已安装的 Microsoft Store 应用上运行,也可以附加到正在运行的应用或进程。 无论是否进行调试,都可以运行“CPU 使用情况”工具。 有关详细信息,请参阅运行带或不带调试器的分析工具

以下说明介绍如何使用不带调试器的“CPU 使用情况”工具以及 Visual Studio“性能探查器” 。 示例使用本地计算机上的发布版本。 发布版本提供了实际应用性能的最佳视图。 要使用调试版本(附加调试器)分析 CPU 使用情况,请参阅性能分析初学者指南

通常,本地计算机最好复制已安装的应用执行。 要从远程设备收集数据,请直接在该设备上运行应用,而不通过使用远程桌面连接运行。

注意

需要 Windows 7 或更高版本才能使用性能探查器

收集 CPU 使用量数据

  1. 在 Visual Studio 项目中,将解决方案配置设置为“发布”,然后选择“本地 Windows 调试器”(或“本地计算机”)作为部署目标

    Screenshot that shows Select Release and Local Machine.

    Screenshot that shows Select Release and Local Machine.

  2. 选择“调试”>“性能探查器”

  3. 在“可用工具”下,选择“CPU 使用情况”,然后选择“启动”

    Screenshot that shows Select CPU Usage.

    Screenshot that shows Select CPU Usage.

    如果在启动探查器之前启用了“在暂停后开始收集”选项,则在诊断会话视图中选择“记录”按钮之前,不会收集数据。

    注意

    若要详细了解如何提高此工具的效率,请参阅优化探查器设置

  4. 应用启动后,诊断会话即会开始,并显示 CPU 使用情况数据。 完成收集数据后,选择“停止收集”

    Screenshot that shows Stop CPU Usage data collection.

    Screenshot that shows Stop CPU Usage data collection.

    CPU 使用量工具可分析数据并显示报告。 如果在收集或显示数据时遇到问题,请参阅排查分析错误并修复问题

    Screenshot that shows CPU Usage report.

    Screenshot that shows CPU Usage report.

    使用“筛选器”下拉列表以选择或取消选择要显示的线程,并使用“搜索”框搜索特定线程或节点

CPU 使用情况数据列

名称 描述
CPU 总量 [单位,以百分数计算] Total % data equation

调用函数所使用的毫秒数和 CPU 百分比,以及函数在所选时间范围内调用的函数。 这与“CPU 利用率”时间线图不同,后者是将时间范围内的 CPU 总活动量与可用 CPU 总量进行比较。
自 CPU [单位,以百分数计算] Self % equation

在所选时间范围内调用函数所使用的毫秒数和 CPU 百分比,不包括函数调用的函数。
模块 在某些视图中会显示“模块”列,该列显示包含函数的模块的名称。

分析 CPU 见解

若要分析热门见解、排名靠前的函数和热路径,请参阅 CPU 见解

分析 CPU 使用量报告

若要分析报表,请单击“打开详细信息”,或单击其中一个排名靠前的函数打开“函数”视图。

报表提供诊断数据的不同视图:

  • 调用方/被调用方
  • 调用树
  • 模块
  • 函数
  • 火焰图

若要分析报表,请单击“创建详细的报表”。

报表提供诊断数据的不同视图:

  • 调用方/被调用方
  • 调用树

在除调用方/被调用方之外的所有视图中,诊断报告按“CPU 总量”从最高到最低进行排序。 通过选择列标题更改排序顺序或排序列。 可以双击感兴趣的函数,将看到该函数的源,并且该函数中所用时间的分布情况会突出显示。 该表显示包含数据(例如函数中所用的时间)的列,包括所调用的函数(总 CPU),以及显示函数中所用时间的另一列,不包括调用的函数(自 CPU)。

此数据可以帮助评估函数本身是否属于性能瓶颈。 确定方法显示的数据量,看看第三方代码或运行时库是否是终结点速度慢或资源消耗量大的原因。

有关使用火焰图的详细信息,请参阅使用火焰图识别热路径

CPU 使用率调用关系树

要查看调用关系树,请选择报表中的父节点。 默认情况下,“CPU 使用情况”页面将打开“调用方/被调用方”视图。 在“当前视图”下拉列表中,选择“调用树” 。

可以单击“展开热路径”和“显示热路径”按钮,以查看调用树视图中使用最高 CPU 百分比的函数调用。

调用关系树结构

Screenshot that shows Call tree structure.

Screenshot that shows Call tree structure.

映像 描述
Step 1 CPU 使用情况调用树中的顶级节点是一个伪节点。
Step 2 在大多数应用中,当“显示外部代码”选项处于禁用状态时,第二级别节点就是“[外部代码]”节点。 该节点包含启动和停止应用、绘制 UI、控制线程计划以及向应用提供其他低级别服务的系统和框架代码。
Step 3 二级节点的子级为用户代码方法和异步例程,它们由二级系统和框架代码进行调用或创建。
Step 4 方法的子节点仅有父方法调用的数据。 禁用“显示外部代码” 后,应用方法只能包含 [外部代码] 节点。

外部代码

由代码执行的系统和框架函数称为“外部代码”。 外部代码函数启动和停止应用、绘制 UI、控制线程以及向应用提供其他低级别服务。 在大多数情况下,你不会对外部代码感兴趣,因此 CPU 使用情况调用树可将用户方法的外部函数收集到一个“[外部代码]”节点中。

若要查看外部代码的调用路径,请将当前视图切换到“调用树”视图,或右键单击并选择“调用树中的视图”。

Screenshot that shows Show in Call Tree.

要查看外部代码的调用路径,请在主诊断报表页面(右窗格)上的“筛选器”下拉列表中选择“显示外部代码”,然后选择“应用”。 “CPU 使用情况”页面的“调用树”视图随即展开外部代码调用 。 (“筛选器”下拉菜单在主诊断页面上可用,在详细视图上不可用。

Screenshot that shows Show External Code.

许多外部代码调用链都是深度嵌套的,因此链的宽度可能超过“函数名”列的显示宽度。 然后,函数名称如下图所示。

Screenshot that shows nested external code in the call tree.

许多外部代码调用链都是深度嵌套的,因此链的宽度可能超过“函数名”列的显示宽度。 函数名则显示为“...”

Screenshot that shows nested external code in the call tree.

要查找所需的函数名称,请使用搜索框。 将鼠标悬停在所选行上或使用水平滚动条来查看数据。

Screenshot that shows Search for nested external code.

Screenshot that shows Search for nested external code.

CPU 使用情况调用树中的异步函数

当编译器遇到异步方法时,它会创建一个隐藏的类来控制方法的执行。 从概念上讲,此类是状态机。 该类具有编译器生成的异步调用原始方法以及运行其所需的回调、计划程序和迭代器的函数。 当父方法调用原始方法时,编译器将从父方法的执行上下文中删除该方法,并在控制应用执行的系统和框架代码的上下文中运行隐藏的类方法。 异步方法通常(但不总是)在一个或多个不同线程上执行。 此代码在“CPU 使用情况”调用树中显示为“[外部代码]”节点的子节点,位于树的顶部节点下面 。

在以下示例中,“[外部代码]”下方的前两个节点是编译器生成的状态机类的方法。 第三个节点是对原始方法的调用。

Screenshot that shows Asynchronous node.

展开生成的方法,以显示正在进行的操作:

Screenshot that shows expanded asynchronous node.

Screenshot that shows expanded asynchronous node.

  • MainPage::GetMaxNumberAsyncButton_Click 只管理任务值列表、计算结果最大值以及显示输出。

  • MainPage+<GetMaxNumberAsyncButton_Click>d__3::MoveNext 显示用于计划和启动 48 个任务所需的活动,这些任务将包装对 GetNumberAsync的调用。

  • MainPage::<GetNumberAsync>b__b 显示调用 GetNumber 的任务的活动。

收集调用计数 (.NET)

如果要在“函数”视图中查看调用计数,可以在启动探查器之前启用设置。 .NET 项目类型支持此设置,并且需要在探查器下启动进程。 不支持附加方案。

  1. 在性能探查器中,选择 CPU 使用率的“设置”图标。

    Screenshot that shows the settings icon for CPU Usage.

  2. 启用“收集调用计数(仅 .NET)”选项。

    Screenshot that shows settings for CPU Usage.

  3. 收集 CPU 使用率数据。

  4. 打开“函数”视图,并确保“调用计数”列设置为可见。

    如果看不到该列,请右键单击列标题以选择可见列。

    Screenshot that shows call count data.