如何在Metal上测量GPU时间?

Sur*_*ine 5 profiling metal

我想以编程方式查看我的应用程序的一部分在macOS和iOS上消耗多少GPU时间。在OpenGL和D3D上,我可以使用GPU计时器查询对象。我进行了搜索,找不到与Metal类似的东西。如何在不使用仪器等的情况下在Metal上测量GPU时间。我在使用Objective-C。

Ian*_*ann 5

这种方法有几个问题:

1) 您真的想知道大多数时候命令缓冲区内的 GPU 端延迟是多少,而不是往返 CPU。这更好地衡量为运行 20 个着色器实例和 10 个着色器实例之间的时间差。但是,该方法会增加噪声,因为误差是与两次测量相关的误差之和。

2) 等待完成会导致 GPU 在停止执行时时钟下降。当它再次启动时,时钟处于低功耗状态,可能需要很长时间才能再次启动,从而影响您的结果。这可能是一个严重的问题,可能会低估您在基准测试中的表现与实际表现的两倍或更多。

3) 如果您按计划启动时钟并在完成时停止,但 GPU 正忙于运行其他工作,那么您的已用时间包括其他工作负载所花费的时间。如果 GPU 不忙,则会遇到 (2) 中描述的时钟下降问题。

这个问题比我使用过的大多数基准测试案例要难得多,而且我已经做了很多性能测量。

衡量这些事情的最好方法是使用设备性能监视器计数器,因为它使用机器自己的时间概念直接衡量正在发生的事情。我喜欢那些报告周期超过挂钟时间的人,因为这往往会消除时钟摆动,但对此并没有普遍共识。(并非硬件的所有部分都以相同的频率运行,等等)我会向开发人员工具寻求基于 PMC 的测量方法,如果您找不到它们,请询问它们。


Ken*_*ses 4

您可以将计划的和已完成的处理程序块添加到命令缓冲区。您可以获取每个时间戳并进行比较。由于这些块是在 CPU 上执行的,因此存在一些延迟,但它应该可以让您接近。

在 Metal 2.1 中,Metal 现在提供了“事件”,这更像是其他 API 中的栅栏。(该名称MTLFence已用于同步共享堆内容。)特别是,使用MTLSharedEvent,您可以对命令进行编码以修改命令缓冲区中特定点处的事件值。然后,您可以通过两种方式让事件具有该值,或者要求在事件达到目标值时异步执行块。

这仍然存在延迟等问题(正如 Ian Ollmann 所描述的),但比命令缓冲区调度和完成更细粒度。特别是,正如 Klaas 在评论中提到的,正在调度的命令缓冲区并不表明它已经开始执行。您可以在命令序列的开头和末尾(使用不同的值)放置命令来设置事件的值,并且这些命令只会在实际执行时发出通知。

最后,在 iOS 10.3+(但不是 macOS)上,MTLCommandBuffer有两个属性GPUStartTimeGPUEndTime,您可以使用它们确定命令缓冲区在 GPU 上执行所需的时间。这不应该像其他技术那样受到延迟的影响。