分析 DirectX 应用

这说明如何使用作为Windows性能Toolkit一部分随附的 XPerfGPUView 工具来度量 DirectX 应用的一些最重要的性能时间度量。 这不是用于了解工具的完整指南,而是用于分析 DirectX 应用性能的特定适用性。 虽然此处讨论的大多数技术都与所有 DirectX 应用相关,但它与使用交换链的应用最相关,而与使用 SIS/VSIS 和 XAML 动画的 XAML 构建的 DirectX 应用程序最为相关。 我们将引导你完成关键性能时间度量、如何获取和安装工具,然后分析性能度量跟踪以了解应用瓶颈。

关于工具

XPerf

XPerf 是一组基于WINDOWS (ETW 事件跟踪构建的性能分析工具) ,旨在测量和分析详细的系统和应用性能和资源使用情况。 从Windows 8开始,此命令行工具具有图形用户界面,称为Windows性能记录器 (WPR) 和Windows 性能分析器 (WPA) 。 有关这些工具的详细信息,请参阅网页中Windows性能Toolkit ( WPT) :Windows性能Toolkit

ETW 收集请求的内核事件,并将其保存到名为事件跟踪日志 (ETL) 文件中。 这些内核事件提供有关运行应用时应用和系统特征的大量信息。 通过启用跟踪捕获、执行需要分析的所需应用方案、停止将数据存储在 ETL 文件中的捕获来收集数据,从而收集数据。 然后,可以使用命令行工具 xperf.exe 或视觉跟踪分析工具 xperfview.exe分析相同或不同计算机上的文件。

GPUView

GPUView 是一种开发工具,用于确定图形处理单元的性能 (GPU) 和 CPU。 它查看有关直接内存访问的性能, (DMA) 缓冲区处理以及视频硬件上所有其他视频处理。

对于严重依赖 GPU 的 DirectX 应用, GPUView 是一种功能强大的工具,用于了解在 CPU 与 GPU 上完成的工作之间的关系。 有关 GPUViewseeUsing GPUView 的详细信息。

XPerf 类似,ETW 跟踪首先通过启动跟踪服务、执行需要分析的应用的方案、停止服务并将信息保存在 ETL 文件中。 GPUView 以图形格式呈现 ETL 文件中的数据。

安装 GPUView 工具后,建议在“GPUView 帮助”菜单下阅读“GPUView 的主显示”主题。 它包含有关如何解释 GPUView UI 的有用信息。

安装工具

XPerfGPUView 均包含在Windows性能Toolkit (WPT) 中。

XPerf 作为 Windows 软件开发工具包的一部分提供, (SDK) 用于Windows。 下载Windows SDK

WINDOWS评估和部署工具包 (Windows ADK) 中提供了 GPUView下载Windows ADK

安装后,必须将包含 XPerfGPUView 的目录添加到系统“Path”变量。

单击"开始"菜单按钮并键入“系统变量”。 系统属性窗口随即打开。 单击“编辑系统环境变量”。 从“系统属性”对话框中选择“环境变量”。 “Path”变量位于“系统变量”下。 将包含 xperf.exeGPUView.exe 的目录追加到路径。 这些可执行文件位于“Windows工具包”内的“Windows性能Toolkit”目录中。 默认位置为:C:\Program Files (x86) \Windows Kits\10\Windows Performance Toolkit

性能时间度量

大多数应用都希望运行顺利,并响应用户输入。 但是,根据所需方案,性能的一个方面可能比另一个方面更重要。 例如,对于在触摸Tablet PC上运行的新闻阅读器应用,最重要的方面是一次查看一篇文章,并平移/缩放/滚动浏览相同或不同的文章。 在此方案中,无需呈现每个帧的所有内容。 但是,在触摸手势上顺利滚动浏览文章的能力非常重要。

在另一个实例中,如果删除帧,游戏或视频呈现应用会使用大量动画故障。 在这种情况下,在没有用户输入干预的情况下在屏幕上显示内容的功能非常重要。

为了了解应用的哪个部分有问题,第一步是确定最重要的方案。 一旦了解应用的核心方面及其将如何进行练习,使用工具查找问题就变得更容易了。

一些最常见的性能时间指标如下所示:

启动时间

从进程启动到第一次显示点击屏幕所测量的时间。 当系统温暖时,此度量更有用,这意味着在应用启动几次后进行度量。

每个帧的 CPU 时间

CPU 主动处理一帧的应用工作负荷的时间。 如果应用运行顺利,则一个帧所需的所有处理都在一个 v 同步间隔内发生。 由于监视器刷新速率为 60Hz,因此每个帧的刷新速率为 16 毫秒。 如果 CPU 时间/帧大于 16 毫秒,可能需要 CPU 优化才能生成故障免费应用体验。

每个帧的 GPU 时间

GPU 主动处理一帧的应用工作负荷的时间。 当处理一帧数据所花费的时间超过 16 毫秒时,应用会绑定 GPU。

能够了解应用是 CPU 还是 GPU 绑定,会缩小代码中存在问题的部分。

采用性能时间度量跟踪

执行以下步骤以执行跟踪:

  1. 以管理员身份打开命令窗口。
  2. 如果应用已在运行,请关闭该应用。
  3. 将目录更改为 Windows Performance Toolkit 文件夹中的 gpuview 目录。
  4. 键入“log.cmd”以启动事件跟踪。 此选项记录最有趣的事件。 其他可用选项记录事件的不同范围。 例如,“v”或详细日志模式捕获 GPUView 感知的所有事件。
  5. 启动示例,并以涵盖需要分析的性能路径的方式练习示例。
  6. 返回命令窗口,然后再次键入“log.cmd”以停止日志记录。
  7. 这会在 gpuview 文件夹中输出名为“merged.etl”的文件。 可以将此文件保存到另一个位置,并且可以在同一台或不同的计算机上对其进行分析。 若要查看堆栈捕获详细信息,请保存与应用关联的符号文件 (.pdb) 。

度量

注意

几何实现示例的度量是在具有集成 DirectX11 图形卡的 Quad Core 计算机上进行的。 度量值因计算机配置而异。

 

本部分演示如何测量每个帧度量的启动时间、CPU 和 GPU 时间。 可以捕获计算机上相同示例的性能跟踪,并查看各种度量的差异。

若要在 GPUView 中分析跟踪,请使用 GPUView.exe打开“merged.elt”文件。

启动时间

启动时间由应用开始所用的总时间度量,直到内容首次出现在屏幕上。

最好按照上一部分中列出的步骤执行启动时间度量,这些变体如下:

  • 如果在首次启动应用时进行启动度量,则称为冷启动。 这可能因在短时间内启动应用几次后采取的度量值而异。 这称为热启动。 根据应用在启动时创建的资源数量,这两个启动时间之间存在很大差异。 根据应用目标,可能需要衡量一个或另一个目标。
  • 记录性能信息时,一旦屏幕上显示第一帧,立即终止应用。

使用 GPUView 计算启动时间

  1. GPUView 中,向下滚动到相关进程,在本例中GeometryRealization.exe。

    Screenshot that shows an example of processes in GPUView.

  2. 上下文 CPU 队列表示已排队到硬件的图形工作负荷,但不一定由硬件处理。 当跟踪文件打开时,它会显示在跟踪拍摄时间之间记录的所有事件。 若要计算启动时间,请选择感兴趣的区域,放大第一个上下文 CPU 队列的初始部分, (这是使用 Ctrl +Z 显示活动) 的区域。 有关 GPUView 控件的详细信息,请参阅 GPUView 帮助文件部分“ GPUView 控件摘要”。 下图仅显示放大到上下文 CPU 队列的第一部分的GeometryRealization.exe进程。 上下文 CPU 队列的颜色由队列正下方的矩形表示,队列中的相同颜色数据包显示在硬件上排队的 GPU 工作。 上下文队列中的阴影模式数据包显示当前数据包,这意味着应用希望硬件在屏幕上显示内容。

    Screenshot that shows examples of the 'Context C P U Queue'.

  3. 启动时间是应用首次启动 (在此例中 UI 线程入口点模块SHCORE.dll) 的时间,直到上下文首次出现时 (标记一个舱口数据包) 。 此处的图突出了感兴趣的领域。

    注意

    实际的当前信息在翻转队列中表示,因此,在当前数据包实际在翻转队列中完成之前,需要花费的时间。

     

    下图中不显示完整的状态栏,也显示了突出显示部分之间的已用时间。 这是应用的启动时间。 在这种情况下,对于上面提到的计算机,它大约为 240 毫秒。

    Screenshot that shows areas of interest regarding startup-time in the 'Context C P U Queue'.

每个帧的 CPU 和 GPU 时间

测量 CPU 时间时需要考虑一些事项。 在跟踪中查找要分析的方案的区域。 例如,在几何图形实现示例中,已分析的方案之一是呈现 2048 和 8192 基元之间的转换,所有未实现 (如前所述,几何图形不会分割每个帧) 。 跟踪清楚地显示了基元转换前后 CPU 和 GPU 活动的差异。

正在分析两种方案,以计算每个帧的 CPU 和 GPU 时间。 如下所示。

  • 从呈现 2048 个未实现的基元过渡到 8192 个未实现的基元。
  • 从呈现 8192 实现的基元转换为 8192 个未实现的基元。

在这两种情况下,都观察到帧速率大幅下降。 测量 CPU 和 GPU 时间,两者之间的关系以及跟踪中的其他几个模式可以提供有关应用中有问题的区域的有用信息。

计算 2048 基元未实现时的 CPU 和 GPU 时间

  1. 使用 GPUView.exe打开跟踪文件。

  2. 向下滚动到GeometryRealization.exe进程。

  3. 选择用于计算 CPU 时间的区域,并使用 CTRL + Z 将其放大。

    Screenshot that shows an area selected for calculating C P U time in the 'Context CPU Queue'.

  4. 通过在 F8 之间切换来显示 v 同步信息。 保持放大,直到很容易看到一个 vsync 值的数据。 蓝线是 v 同步时间的位置。 通常,每 16 毫秒 (60 fps) 发生一次,但如果 DWM 遇到性能问题,则运行速度较慢,因此每 32 毫秒 (30 fps) 就会发生一次。 要了解时间,请从一个蓝色条形图中选择下一个蓝色条,然后查看 GPUView 窗口右下角报告的 ms 数。

    Screenshot that shows an example of v-sync times.

  5. 若要测量每个帧的 CPU 时间,请测量呈现所涉及的所有线程所花费的时间长度。 从性能的角度来看,缩小预期最相关的线程可能是值得的。 例如,在几何图形实现示例中,内容正在动画处理,需要在屏幕中呈现每个帧,使 UI 线程成为重要内容。 确定要查看的线程后,测量此线程上的条形长度。 平均其中一些生成每个帧的 CPU 时间。 下图显示了 UI 线程上花费的时间。 它还表明,这次适合两个连续 v 同步,这意味着它达到 60FPS。

    Screenshot that shows the time taken up on the U I thread.

    还可以通过查看翻转队列来验证相应的时间范围,其中显示 DWM 能够显示每个帧。

    Screenshot that shows an example of the 'Flip Queue'.

  6. GPU 时间的度量方式与 CPU 时间相同。 放大相关区域,以测量 CPU 时间。 测量 GPU 硬件队列中条形的长度,其颜色与上下文 CPU 队列的颜色相同。 只要条形图适合连续 v 同步,应用在 60FPS 上运行顺利。

    Screenshot that shows an example of the 'GPU Hardware Queue' displaying information that an app is running at 60 F P S.

计算 8192 基元呈现未实现时的 CPU 和 GPU 时间

  1. 如果再次执行相同的步骤,跟踪显示一个帧的所有 CPU 工作都不适合一个 v 同步和下一个帧。 这意味着应用已绑定 CPU。 UI 线程正在饱和 CPU。

    Screenshot that shows an example of the UI thread saturating the C P U.

    查看翻转队列时,还清楚 DWM 无法显示每个帧。

    Screenshot that shows an example of the D W M unable to present every frame.

  2. 若要分析花费的时间,请在 XPerf 中打开跟踪。 若要分析 XPerf 中的启动时间,请先在 GPUView 中查找时间间隔。 将鼠标悬停在间隔的左侧和右侧,并记下 GPUView 窗口底部显示的绝对时间。 然后在 XPerf 中打开相同的 .etl 文件,向下滚动到“CPU 采样依据 CPU”图,右键单击并选择“选择间隔...”这允许键入通过查看 GPU 跟踪发现的兴趣间隔。

    Screenshot that shows 'C P U sampling by C P U' in 'Windows Performance Analysis'.

  3. 转到“跟踪”菜单,并确保选中“加载符号”。 此外,请转到“跟踪 -> 配置符号路径”,然后在应用符号路径中键入。 符号文件包含有关单独数据库中编译的可执行文件 (.pdb) 的调试信息。 此文件通常称为 PDB。 有关符号文件的详细信息,可在此处找到: 符号文件。 此文件可以位于应用目录的“调试”文件夹中。

  4. 若要获取应用中花费时间的细分,请右键单击上一步中选择的时间间隔,然后单击“摘要表”。 若要大致了解每个 dll 中花费的时间,请取消选中“列”菜单中的“Stack”。 请注意,此处的“Count”列显示给定 dll/函数中的样本数。 由于每个 ms 大约采用一个样本,因此此数字可以用作每个 dll/函数中花费多少时间的最佳猜测。 选中“列”菜单中的“堆栈”将为调用图中每个函数花费的非独占时间。 这将有助于进一步分解问题点。

  5. 2048 未实现基元的堆栈跟踪信息显示,在几何实现过程中花费了 30% 的 CPU 时间。 其中大约36%的时间用于几何分割和抚摸。

  6. 8192 未实现基元的堆栈跟踪信息显示,大约 60% 的 CPU 时间 (4 个核心) 用于几何图形实现。

    Screenshot that shows stack trace information for C P U time.

计算正在实现 8192 基元时的 CPU 时间

从配置文件中可以清楚地看出应用已绑定 CPU。 为了减少 CPU 花费的时间,可以创建几何图形一次并缓存。 缓存的内容可以呈现每个帧,而不会产生每个帧的几何分割成本。 在 GPUView 中查看应用的实现部分的跟踪时,很明显,DWM 能够呈现每个帧,CPU 时间急剧减少。

Screenshot that shows an example of a trace in GPUView showing D W M is able to present every frame.

图的第一部分显示已实现 8192 个基元。 每个帧的相应 CPU 时间能够适应两个连续 v 同步。 在图形的后面部分,这不是真的。

XPerf 中,CPU 处于空闲状态最长,几何实现应用上花费的 CPU 时间只有大约 25%。

gpuview screenshot.

总结

GPUViewXPerf 以及用于分析 DirectX 应用性能的强大工具。 本文是使用这些工具和了解基本性能度量和应用特征的入门指南。 除了了解工具的使用外,首先必须了解正在分析的应用。 "开始"菜单查找有关应用尝试实现的问题的解答? 系统中哪些线程最重要的? 你愿意做出什么权衡? 分析性能跟踪时,首先查看明显的有问题的位置。 应用 CPU 或 GPU 是否绑定? 应用是否能够显示每个帧? 工具与对应用的理解一起,可以提供非常有用的信息来理解、查找和最终解决性能问题。