使用性能探查器中的 CPU 分析来分析性能(C#、Visual Basic、C++、F#)

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

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

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

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

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

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

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

以下说明介绍如何使用不带调试器的“CPU 使用情况”工具以及 Visual Studio“性能探查器” 。 示例使用本地计算机上的发布版本。 发布版本提供了实际应用性能的最佳视图。 有关演示如何使用 CPU 使用情况工具提高性能的教程,请参阅案例研究 - 初学者代码优化指南

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

收集 CPU 使用率数据

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

    屏幕截图显示选择“发布”和“本地计算机”。

    屏幕截图显示选择“发布”和“本地计算机”。

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

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

    屏幕截图显示选择“CPU 使用情况”。

    屏幕截图显示选择“CPU 使用情况”。

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

    注意

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

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

    屏幕截图显示停止 CPU 使用情况数据收集。

    屏幕截图显示停止 CPU 使用情况数据收集。

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

    屏幕截图显示 CPU 使用情况报告。

    屏幕截图显示 CPU 使用情况报告。

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

CPU 使用率数据列

名称 描述
CPU 总量 [单位,以百分数计算] 总数据量 % 等式

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

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

分析 CPU 见解

如果顶级见解部分显示任何见解,请使用提供的链接获取有关所标识问题的详细信息。 此外,如果使用 Copilot,询问 Copilot 按钮将打开 Copilot 聊天窗口,Copilot 将根据代码和任何已识别的问题提供建议。

有关详细信息,请参阅 CPU 见解

分析 CPU 使用率

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

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

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

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

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

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

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

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

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

CPU 使用率调用关系树

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

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

调用关系树结构

屏幕截图显示调用树结构。

屏幕截图显示调用树结构。

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

外部代码

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

要查看外部代码的调用路径,请在主报告摘要页面(右窗格)上的“设置”下拉列表中取消选择“仅显示我的代码”,然后选择“应用”。设置下拉菜单在主报告摘要页面上可用,在详细视图上不可用。)

显示“设置”和显示“仅显示我的代码”的屏幕截图。

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

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

屏幕截图显示“显示外部代码”。

禁用“仅显示我的代码”时,“CPU 使用率”页面的“调用树”视图将展开外部代码调用。

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

屏幕截图显示调用树中嵌套的外部代码。

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

屏幕截图显示调用树中嵌套的外部代码。

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

屏幕截图显示搜索嵌套的外部代码。

屏幕截图显示搜索嵌套的外部代码。

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

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

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

屏幕截图显示异步节点。

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

屏幕截图显示展开的异步节点。

屏幕截图显示展开的异步节点。

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

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

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

收集调用计数 (.NET)

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

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

    显示 CPU 使用率的“设置”图标的屏幕截图。

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

    显示 CPU 使用率的“设置”的屏幕截图。

  3. 收集 CPU 使用率数据。

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

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

    显示调用计数数据的屏幕截图。