如何在Metal上测量GPU时间?

8

我想通过编程的方式查看我的应用程序在macOS和iOS上消耗了多少GPU时间。在OpenGL和D3D中,我可以使用GPU计时器查询对象。我搜索过了,但找不到类似于Metal的东西。我如何在Metal上测量GPU时间,而不使用Instruments等工具?我正在使用Objective-C。

3个回答

5
这种方法存在几个问题:
1) 大多数情况下,您真正想知道的是命令缓冲区内GPU端的延迟时间,而不是与CPU的往返时间。最好的测量方法是运行20个着色器实例和10个着色器实例之间的时间差异。然而,这种方法可能会添加噪音,因为误差是两个测量相关误差之和。
2) 等待完成时,GPU在停止执行时会降低时钟速度。当它再次启动时,时钟处于低功耗状态,可能需要相当长的时间才能恢复,这会使您的结果产生偏差。这可能是一个严重的问题,可能会导致您在基准测试中的性能低估了两倍或更多。
3) 如果您在计划开始时启动时钟并在完成后停止,但GPU正在运行其他工作,那么您的经过时间包括花费在其他工作负载上的时间。如果GPU没有忙碌,则会出现(2)中描述的时钟降频问题。
这个问题比我处理过的大多数基准测试案例更难以正确处理,而我已经进行了很多性能测量。
最好的方法是使用设备上的性能监视器计数器来测量这些内容,因为这是直接衡量正在发生的事情,使用机器自己的时间概念。我更喜欢报告周期而不是墙上钟表时间的方法,因为这往往会消除时钟漂移,但并不是所有人都同意这一点。(硬件的各个部分没有运行在相同的频率上等等)。我建议您查看开发人员工具以了解基于PMC的测量方法,如果找不到它们,请提出要求。

4
您可以给命令缓冲区添加计划和已完成处理程序块,可以在每个块中获取时间戳并进行比较。由于块是在 CPU 上执行的,所以会有一些延迟,但这应该能让您接近目标。
随着 Metal 2.1 的推出,现在提供了“事件”,更像是其他 API 中的 “栅栏”。 (名称 MTLFence 已用于同步共享堆栈。) 特别地,在使用 MTLSharedEvent 时,您可以编码命令以修改事件值,并将其放置在命令缓冲区的特定点。然后,您可以等待事件达到目标值或请求异步执行块,当事件达到目标值时即可完成执行。
虽然还存在延迟等问题(如 Ian Ollmann 所描述),但它比命令缓冲区的调度和完成更细粒度。特别地,正如 Klaas 在评论中所提到的,被调度的命令缓冲区不能说明它已经开始执行。您可以将命令放置在一系列命令的开头和结尾处以设置事件的值 (使用不同的值),并且只有在实际执行时才会通知。
最后,在 iOS 10.3+ 中但不在 macOS 中,MTLCommandBuffer 具有两个属性,GPUStartTime 和 GPUEndTime,您可以确定命令缓冲区在 GPU 上执行所需的时间。这不应以与其他技术相同的方式受到延迟的影响。

在@ian的回答中,关于(3)怎么样?在我将渲染到离屏缓冲区,然后将其混合到可绘制对象的情况下,两个已安排的处理程序都会先被调用,然后是两个已完成的处理程序。无法确定哪一个花费了多少时间。 - Klaas
@Klaas 是的,Ian是正确的。我也用一些其他技术更新了我的答案。 - Ken Thomases

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接