DirectX 应用程序每 3 秒"hiccups"一次

DirectX application "hiccups" every 3 seconds

本文关键字:hiccups 一次 应用程序 DirectX      更新时间:2023-10-16

一个多星期以来,我一直在调查DirectX 11 C++应用程序中的一个问题,因此我正在向StackOverflow上的优秀人员寻求任何可能帮助我追踪这一问题的见解。

我的应用程序将以每秒60-90帧的速度运行,但每隔几秒钟我就会得到一个大约需要三分之一秒才能完成的帧。经过大量的调查、调试和使用各种代码分析器,我将其缩小到对DirectX API的调用。然而,从一个缓慢的帧到下一个,导致速度减慢的并不总是同一个API调用。在我最近的一次跑步中,暂停的呼叫(总是大约五分之一秒)是

  • ID3D11DeviceContext:UpdateSubresource
  • ID3D11DeviceContext:绘制索引
  • IDXGISwapChain:存在

不仅不是同一个函数停滞,而且这些函数中的每一个(主要是前两个)的缓慢调用可能来自我代码中的各个地方。

根据我在代码中放置的多个评测工具和我自己的高分辨率计时器来帮助测量事物,我发现这种"打嗝"会以不到3秒(~2.95)的一致间隔发生

此应用程序从外部硬件收集数据,并使用DirectX实时可视化这些数据。当应用程序运行时,硬件可能处于空闲状态或以各种速度运行。硬件运行得越快,收集的数据就越多,而且必须可视化。我指出这一点是因为当考虑到这个bug的一些特征时,它可能会很有用:

  • 硬件空闲时不会出现长帧。这对我来说很有意义,因为软件只需要重新绘制它已经拥有的数据,而不必将新数据传输到GPU
  • 然而,无论硬件运行速度如何,长帧都以这些一致的3秒间隔出现。因此,即使我的应用程序每秒收集的数据量是原来的两倍,长帧的频率也不会改变
  • 这些长帧的持续时间非常一致。总是在0.25到0.3秒之间(我相信是对DirectX API的缓慢调用是一致的,所以整个帧持续时间的任何变化都是该调用外部的)
  • 在上周的现场测试中(当我第一次发现这个问题时),我注意到在应用程序的几次运行中,经过长时间(可能20分钟或更长时间)的连续测试,除了观看程序之外,没有与程序进行太多交互,打嗝就会消失。如果我们与应用程序的某些功能交互或重新启动程序,问题就会再次出现。这对我来说没有意义,但就像GPU"发现"并解决了问题一样,但当我们改变了它以前的工作模式时,它又恢复了。不幸的是,我们硬件的性质让我很难在实验室环境中复制它

此错误始终发生在两台硬件非常相似的不同机器上(双GTX580卡)。但是,在应用程序的最新版本中,没有出现此问题。不幸的是,自那以后,代码经历了许多更改,因此很难确定是什么具体的更改导致了问题。

我考虑了图形驱动程序,所以更新到了最新版本,但这并没有什么不同。我还考虑了对这两台计算机进行其他更改的可能性,或者可能对两台计算机上运行的软件进行更新,可能会导致GPU出现问题。但我想不出除了在应用程序运行时在两台机器上都运行的Microsoft Security Essentials之外还有什么,而且我已经尝试禁用它的实时保护功能,但无济于事。

虽然我很希望这是一个可以关闭的外部程序,但最终我担心我一定是用DirectX API做了一些错误/不正确的事情,导致GPU不得不每隔几秒钟进行一次调整。也许我在GPU上更新数据的方式上做错了什么(因为滞后只发生在我收集数据以显示时)。然后GPU每隔几秒钟就会暂停一次,而在暂停期间调用的任何API函数都无法像正常情况下那样快速返回?

如有任何建议,我们将不胜感激!

谢谢,Tim

更新(2013.01.21):

我终于让步了,重新搜索了我的应用程序以前的修订版,直到我找到了一个没有出现这个错误的地方。然后我进行了一次又一次的修订,直到我准确地发现了错误开始发生的时间,并设法找出了问题的根源。在我向顶点类型添加了一个"无符号整数"字段后,问题开始出现,我为其分配了一个大的顶点缓冲区。由于顶点缓冲区的大小,这一变化增加了184.65 MB(1107.87 MB到1292.52)。因为我的顶点结构中确实需要这个额外的字段,所以我找到了其他方法来减少整个顶点缓冲区大小,并将其降至704.26 MB。

我的最佳猜测是,该字段的添加及其所需的额外内存导致我超过了GPU上的某个阈值/限制。我不确定这是超出了总内存分配,还是超出了单个顶点缓冲区的限制。无论哪种方式,似乎这种过度导致GPU必须每隔几秒钟做一些额外的工作(可能与CPU通信),所以我对API的调用不得不等待。如果有人有任何信息可以澄清大型顶点缓冲区的含义,我很乐意听到!

感谢所有给我时间和建议的人。

1)尝试转动VSYNC

2) 您是否正在分配/释放大块内存?尝试在程序开始时分配内存,不要解除分配,只需覆盖它(这可能就是您使用updatesubsource所做的)

3) 将与硬件设备的交互放在一个单独的线程上。在设备完全完成向应用程序传递数据后,将其加载到GPU中。不要让设备控制主线程。我怀疑设备偶尔会阻塞主线程,我完全是在猜测,但如果你是直接将数据从设备复制到GPU,设备会偶尔阻塞,这会导致速度减慢。