当渲染帧时,我的C#应用程序出现了意外的峰值。我一直在使用分析器进行检查,发现以下情况:
- 当垂直同步打开时,程序似乎在交换缓冲区时将控制权交给操作系统(或执行某些操作)...并以某种方式保持其渲染非常一致。这很好,因为它可以平稳地渲染帧,而没有这种奇怪的微跳。下面的图像显示被认为是完全流畅的情况。这是我们所说的“通过平稳渲染而没有任何卡顿,它完美地工作”的情况。
当垂直同步开启时,这种大间隔永远不会发生,原因我不理解。对于不熟悉垂直同步和游戏的人来说,你不能在第一人称射击游戏中使用垂直同步,因为它会破坏输入处理方式,所以我不能使用垂直同步,必须调查非垂直同步版本。我需要找出为什么非垂直同步版本会有这些主要停顿。
我的问题是,如何从上面看到的图像中知道是什么导致了这个延迟?
性能分析器显示,在此处有大量等待时间,等待时间高达80%,CPU使用率为20%(与准备渲染数据时的100% CPU使用率相比)。
分析器还显示,在该循环中根本没有运行任何渲染代码...这很奇怪,因为渲染器几乎完全占据了性能,因此在没有任何帧速率限制的情况下,它应该用实心蓝色矩形淹没整个图表。
问题是,分析器显示的代码只是调用我上面选择的区域中的轮询输入和dll。 请注意,
DispatchRenderFrame
另一个调用正在进行 OpenGL 调用,但当我完全删除它时,程序没有任何影响,因此您可以忽略它。这可能意味着下面看到的用户输入对微卡顿问题也没有影响......但我不能删除它,因为它是我用于窗口管理(OpenTK)的库的一部分。我不确定
CLR Worker
线程是什么或者它在做什么。它也发生在垂直同步(期望平滑的 profiling one),所以即使我不知道它是否是罪犯,我的猜测是它可能不是,但我不确定,因为它在 'desired vsync example' 中的相同位置也出现了。是否有某些中断发生,操作系统接管了但没有恢复我的线程,因为它将其分类为 CPU 占用率过高?只是一种想法......但再次在示例中显示蓝色条,因此我假设
Main
线程实际上没有在我突出显示的代码段中休眠,而是实际运行?正如您所看到的,我不确定我突出显示的时间片正在告诉我什么,这就是我需要帮助的地方。我不知道为什么等待百分比在代码的这一点上如此之高,或者从这里去哪里进一步诊断问题。
编辑: 我使用
Stopwatch
类进行了粗略的分析,以查看哪些位置会导致波峰,并且波峰仅来自计算部分。没有任何 OpenGL 调用会导致任何延迟。它纯粹发生在一个函数的函数内部,这些函数进行数学计算和访问数据,或将数据写入预先分配的结构体数组中。
额外备注:
这也让我好奇是否有一种方法可以强制使C#虚拟机尽可能地使用CPU?
没有垃圾被产生。这不是一个GC问题。我不能在应用程序运行期间运行GC,所以我不会产生垃圾。渲染函数中的所有结构体都在堆栈上,唯一需要管理对象的堆分配数组是具有足够大的大小来存储所有渲染数据的池化数组。它只在开始和结束时出现在分析器中,但不会在渲染阶段运行。
ref
/in
时,它们不会被移动到堆上,而是使用线程的栈进行复制。 - dymanoid