Visual Studio 2013 Update 4 CTP1-GPU 使用率工具
[原文发表地址] GPU Usage tool in Visual Studio 2013 Update 4 CTP1
[原文发表时间] 2014/9/4
在发布了对Visual Studio 2013 Update 3 RC中图形诊断的一系列改进后,我们团队正致力于带给您更多的DirectX 应用的性能分析工具。在昨天发布的Visual Studio 2013 Update 4 CTP1(这里下载)中,您将在性能和诊断中心看到一个崭新的GPU使用率工具,您可以用它来收集和分析DirectX应用的GPU使用率的数据。CTP1支持本地运行Windows 桌面应用程序和Windows 应用商店应用。在后续的发布中,我们将会把对Window Phone 应用和远程分析的支持加入其中。您可以在这里找到相关文档,通过Channel9视频观看实时演示,或者通过此篇博客的余下内容获得更多有关此功能的信息。
如果所有的游戏以60FPS运行且没有任何性能问题可调查,那这个世界就太棒了!但是事实上,在开发和发布过后的时间里,一些应用程序往往不能达到它们的目标帧率-不论是PC上的60FPS还是小型数据终端的30FPS,或者那些应用程序的帧率在会话中期大幅度降低。
从:当多核可被使用时却仅利用了单核CPU,到:GPU渲染一个过于复杂的点阵,造成DirectX应用性能问题的原因变化多端。通常从剥离主要问题到底是超过了还是未达到CPU或GPU使用率开始,会对找到原因有很大帮助。这个GPU 使用率工具可以帮助您判断CPU或GPU是否是此应用的性能瓶颈。您也可以调查每一个GPU事件的时间,前提是在当前安装的是支持的显卡和最新的驱动。请查看此文档中支持的显卡列表,并登陆您的显卡供应商网站(Intel, NVidia, AMD)下载最新的驱动为此项功能提供GPU事件数据。
让我们开始第一次尝试吧!
GPU 使用情况工具可以通过性能和诊断中心来加载,菜单:调试 ->性能和诊断或Alt+F2.
从这里您可以选择仅勾选GPU使用率或勾选包含其在内的其他工具,例如CPU使用率。
点击开始,将开始在用DirectX工程模板新建的默认DirectX工程上单独运行GPU使用率。 在显示的用户账号控制对话框点击Yes,给收集数据赋予权限。
GPU使用率工具开始收集数据,并在打开的诊断会话文件中显示三部分图片,这些图片反应的实时数据不但包括在图形诊断工具中同样可见的帧时间和FPS, 还包括一个崭新的GPU使用率图片用以展示GPU繁忙程度。
现在让我们点击底部的结束收集链接或顶部的结束按钮生成报告。生成的报告显示了实时会话的上述三部分图片。如果您想要深入分析时间轴的一段特定区域,例如若一段帧率或GPU使用率突然下降,您可以在时间轴选择一段区域并点击底部的这里链接查看GPU使用率数据的细节。在这个实例中,这个应用在整个会话过程中运行流畅,因此我们可以选取任意一段来调查GPU细节信息。
GPU细节信息窗口将会单独于此会话窗口打开。上半部分是时间轴视图,展示了每一个CPU内核和GPU引擎随时间的使用情况,下半部分是一个事件列表,展示了发生在GPU上的图形事件列表。需要注意的是这个事件列表的数据需要图形驱动的支持,因此如果您的显卡不支持或者您未安装最新的驱动,事件列表是不可见的,在这种情形下所有的时间将显示为:unattributed。您可以查看此文档中支持的显卡列表,并登陆您的显卡供应商网站(Intel, NVidia, AMD)下载最新的驱动为此项功能提供GPU事件数据。
所有使用GPU的进程都将被捕获,且每一个进程将在时间轴视图中有一个不同的颜色。在这个实例中,黄色代表了性能分析的目标进程,也就是App5.exe。
当您点击或是在事件列表中进行导航,您将看到在CPU和GPU泳道上显示的弹出小控件,展示所选事件在GPU上的执行时间,以及与它相对应的CPU工作发生在CPU上的时间。泳道中的淡灰色垂直线标记了每个监视器的垂直同步信号Vsyncs。Vsyncs线可以用来作为理解是否某个Present调用丢失了Vsyncs的参考。在每两个Vsyncs之间必须有一个Present调用,确保这个应用稳定达到60FPS。
这个GPU详细视图提供了以下有用的信息:
- CPU和GPU在一个更细粒度层次上的繁忙程度
- DirectX事件在CPU上被调用的时间和在GPU上被执行的时间
- 每一个事件在GPU和CPU上消耗的时间
- 是否因为Present调用丢失Vsyncs而导致目标帧率下降
此功能的好处对于这个实例而言并不明显,因为这个应用过于简单,且GPU和CPU都不繁忙。在下一个阶段,我们将要在一个更现实的应用中尝试看看这些数据是如何被使用的.
让我们开始分析一个更现实的应用
在这个实例中,我们将会用到一个的内部测试的应用程序,它叫CityDemo,是一个渲染模拟城市的3D场景。这一次我们将要试着在同一个会话里面运行GPU使用率和CPU使用率两个工具。如果说要判断一个应用是CPU受限还是GPU受限仅用一个GPU使用率工具是必需的话,那么加入CPU使用率信息将会帮助我们更快地分析这种情况下是否CPU是问题的根源。
让我们再次加载性能和诊断中心,但这次我们选择GPU使用率和CPU使用率两个工具。FPS图告诉我们这个应用以40FPS运行。在FPS图中的红线代表默认的阀值:60FPS。如果您的目标是更低的帧率,可以使用下拉菜单降低到30FPS。而且您将注意到会显示一个CPU使用率图因为我们选择了CPU使用率工具。这个提供了一个GPU和CPU状态紧密结合的视图。在这种情况下,CPU利用率差不多20%,GPU使用率大约60%。那么CPU和GPU都没有满负荷,但是为什么这个应用程序没有达到60FPS?
为了解开这个疑惑,让我们深入GPU详细信息去看看,关于为什么这个应用运行缓慢是否能得到任何线索。因为这个图片是不变的,所以我们可以选择一段区域并打开GPU详细信息视图。从详细信息视图中的时间轴我们可以得到:
1. 大约GPU上的Present调用每4次就会丢失1次Vsync,造成了40FPS。我们当前并没有在图上标记所有的Present调用,但是在这种情况下Present在GPU泳道上每一块儿的尾部。试着用时间轴上部的过滤器仅仅显示Present事件,这样就更容易找到Present了。
2.可以注意到一些事件被分组了,例如“Draw city”和“Draw rain”。这些组是由使用ID3DuserDefinedAnnotation接口插入到app的标记所产生的。添加分组标记到您的渲染代码中,可以很好地帮您判断您的哪部分渲染代码开销较大,特别是针对一些复杂的应用。下面是如何在app中插入标记的一个实例:
ComPtr<ID3DUserDefinedAnnotation> pPerf;
pPerf->BeginEvent(L"Draw city");
m_city->Render(m_d3dContext.Get(), this);
pPerf->EndEvent();
3.从这个事件列表我们可以看出来“Draw city”花费了14ms才渲染到GPU。对比下面两幅图中,“Draw city”和“Draw rain”在CPU3泳道上开始的时间,它们是很接近的。这表明CPU快速地处理完“Draw city”就立即开始处理“Draw rain”。但是从 “Draw rain”开始到CPU3泳道上这个块儿的末端,它花费了将近12ms的时间准备雨滴的数据。
4.现在我们可以看出来是CPU限制的问题,因为GPU一直在等待CPU处理雨滴的数据,而它的开销很大。我们看CPU内核泳道,这个app一次仅使用了单核,而其他的三个CPU内核处于空闲状态。现在我们知道是CPU限制的问题,所以让我们回到主视图页面并选择CPU使用率分页(幸亏我们开始的时候开启了CPU使用率的收集!)在这里我们可以深入研究这个调用树,看看是哪个方法造成了最大的CPU开销。在这个例子中,是由SkinnableModel::CommitUpdates生成的 stl调用消耗了所选CPU时间的66.31%。我们可以右键单击这个方法上并点击View Source,在编辑器中打开这个方法。
在CommitUpdates方法中,我们可以看到stl在以下代码中被调用:
for(auto iter = m_pendingInstances.begin(); iter != m_pendingInstances.end(); iter++)
{
instanceList[instanceIndex++] = *iter;
}
现在我们了解了这个app的瓶颈在哪里。这个循环迭代了5000次来为每个雨滴准备数据。我们可以利用这个机器上所有的CPU内核并行地去处理这个任务,来让它变得更迅速。一种实现方法是将循环处理变为并行处理(在这里for_each可以完成同样的任务J)。
parallel_for(0, size, [&, size](int instanceIndex)
{
instanceList[instanceIndex++] = *iter++;
});
现在我们重新运行这个app。喔哦!FPS攀升到60FPS了,而且从后面的这张图可以看到GPU没有丢失任意Vsync,并且四个CPU内核全部都被利用了。
总结
在这篇博客中,我们展示了如何使用GPU使用率工具。这个工具对您有用吗?您觉得它怎么样?如果您还没有使用过它,请下载Visual Studio 2013 Update4 CTP1,尝试使用并告诉我们您的任何建议!J