使用 OpenGL 的 C++ 性能怪异

Posted

技术标签:

【中文标题】使用 OpenGL 的 C++ 性能怪异【英文标题】:C++ performance weirdness w/ OpenGL 【发布时间】:2011-06-05 14:01:46 【问题描述】:

我正在用 C++ 重写一些渲染 C 代码。旧的 C 代码基本上计算它需要的所有内容并在每一帧渲染它。新的 C++ 代码改为预先计算所需的内容并将其存储为链表。

现在,实际的渲染操作是翻译、颜色更改和调用 GL 列表。

虽然执行链表中的操作应该非常简单,但结果方法调用似乎比旧版本花费的时间更长(每次都会计算所有内容 - 我当然确保新版本不是重新计算)。

奇怪的事情?它执行的 OpenGL 操作比旧版本少。但它变得更奇怪了。当我为每种类型的操作添加计数器,并在方法结束时添加一个很好的旧 printf 时,它变得更快 - gprof 和手动测量都证实了这一点。

我还费心查看了 G++ 在这两种情况下生成的汇编代码(有和没有踪迹),并且没有重大变化(这是我最初的怀疑)——唯一的区别是多了几个堆栈词分配给计数器,增加所述计数器,并准备 printf 然后跳转到它。

同样,这适用于 -O2 和 -O3。我在 Ubuntu Maverick 上使用 gcc 4.4.5 和 gprof 2.20.51。

我想我的问题是:发生了什么事?我究竟做错了什么?是不是有什么东西让我的测量结果和 gprof 都丢了?

【问题讨论】:

那么分析告诉了没有计数器的版本?顺便说一句,我推荐 valgrind+callgrind 作为分析器,而 kcachegrind 作为可视化工具。 在没有计数器的版本中,渲染函数的平均时间为0.02ms(总计)。在带计数器的版本中,它不注册(总共 0.00 毫秒)。谢谢,我会试试 valgrind(但上次我尝试用它来检查同一个程序的内存泄漏时,它会导致使用专有的 nVidia 驱动程序崩溃)。 我还会尝试获取详细的配置文件,包括源代码的各个行。 如果分析这么简单,每个人都会随机放置计数器:P 每个 OpenGL 调用的计时仅衡量将操作添加到执行批处理所需的时间。但在您的情况下真正重要的是总渲染时间,即从帧的第一个 OpenGL 调用到完成 glFinish 调用的时间。我很确定,如果您比较程序的两个版本,那么在一个版本中调用 OpenGL 所需的额外时间将补偿更长的时间,直到 glFinish() 在另一个版本中返回。 【参考方案1】:

通过在 printf 中花费时间,您可能会避免在下一次 OpenGL 调用中出现停顿。

【讨论】:

我的下一个 OpenGL 调用是另一个完全不相关的函数,因此它不会影响该特定函数。我可以尝试在对两个测试函数的调用之间放置一个 printf,它可能会指出这个问题。 看起来你是对的。我反转了我的 2 个函数之间的调用,分析结果也反转了。【参考方案2】:

如果没有更多信息,很难知道这里发生了什么,但这里有一些提示:

您确定 OpenGL 调用是相同的吗?您可以使用一些工具来比较发出的调用。确保不存在由可能不同的完成顺序引入的状态变化。 您是否尝试过在运行时使用分析器?如果您有很多对象,那么在遍历列表时追逐指针这一简单事实可能会导致缓存未命中。 您是否发现了特定的瓶颈,无论是在 CPU 端还是 GPU 端?

这是我自己对可能出现问题的猜测。您发送到 GPU 的调用需要一些时间才能完成:前面的代码通过混合 CPU 操作和 GPU 调用,使 CPU 和 GPU 并行工作;相反,新代码首先让 CPU 在 GPU 空闲时计算很多东西,然后在 CPU 无事可做时将所有工作提供给 GPU。

【讨论】:

以上是关于使用 OpenGL 的 C++ 性能怪异的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL相机旋转怪异

OpenGL 性能问题

OpenGL glReadPixels 性能

为啥没有实现 OpenGL 灰度纹理性能增益?

OpenGL帧缓冲性能问题

OpenGL中 Canvas 性能分析