在C++中进行良好性能优化的想法

Sma*_*acL 5 c++ optimization

好吧,过去三天我一直坐在探查器结果面前,通过自动化套件运行各种各样的测试用例.我们的想法是看看是否有任何良好的优化通常可以提高性能.我有资格不错在这方面如下:

  • 在最终用户级别具有非常重要和可观察的性能改进潜力,例如在表现不佳的领域中提高> 100%.

  • 是否有可能减少核心空间使用,例如在数据繁重区域减少> 50%.

  • 易于实现,对代码的混淆最少,副作用最小.即实施优化的好处大大超过了成本.

该应用程序是一个3D映射和建模包,在界面中有大量图形,后端有几何处理.我已经为确保大多数处理的最佳算法选择做了很多工作,而且在这个阶段我正在寻找任何通用的简单方法来处理大型和复杂的数据集时获得额外的优势.到目前为止,我已经提出以下建议;

  • 搜索时,请保留最近找到的项目的缓冲区并首先检查.通过重复搜索进行的大量处理似乎在同一区域内进行搜索.从答案到现在,这似乎是一种特定的记忆形式

  • 排序时,检查数据是否已按排序顺序排列(特别是在使用qsort的位置)

  • 将GUI和处理保持在单独的线程中(失败是易于实现的良好标准,但IMO仍然值得)

  • 如果你有本地类变量,它具有重要的构造/破坏时间,在使用频繁的成员函数中,使它们成为私有类成员.尤其是动态数组和字符串,尤其是MFC CArrays和CStrings.

  • 使用动态数组时,将初始大小设置为略微超过典型使用量,并采用指数增长策略.

  • 处理要存储在数组中的非常大的数据集时,首先调整数据大小以避免任何重新分配.

  • 避免在堆栈上创建临时对象副本的函数返回,而是使用引用参数,例如

    CString MyFunc(双x,双y)

效率低于

void  MyFunc(double x, double y, CString &Result)
Run Code Online (Sandbox Code Playgroud)

实际上,避免CStrings和大多数MFC在代码的任何性能关键区域.(编辑:这可能更常被RVO否定,但不适用于我的应用中的CStrings)

这些项似乎在我的上下文中运行良好,但有没有明显的我遗漏的,或者还有其他优秀的资源优化?

编辑: 根据提供的许多评论,显然需要进一步解释.虽然我完全意识到建议对特定代码片段进行特定优化需要查看该代码,但过去几天花在分析分析器输出上已经显示出优化候选者方面的某些模式.我也意识到自己对其他人在这个领域做得很好的事情的无知,并且看到这些技术的列举清单(至少对我而言),无论它们是否适用于我的情况.这个问题不是关于优化的危险,但对于那里的任何初学者,我建议你首先建立一个强烈的需求,在首先考虑之前优化需求.我自己的偏好是根据未来的性能要求在设计阶段进行大多数优化,但我也是分析的强力倡导者,以验证在实施中是否满足设计假设.我会请人们取悦他们自己积极优化的经验,而不是他们是否应该首先考虑优化.

FWIW,编译器优化代码与否之间的区别在于我的自动化套件中的12%,这是最终用户级别的边界可观察.

第二次编辑:我发现一些相关的帖子非常有用,特别是Mike Dunlavey关于过度依赖于profiler输出的评论.

最后的性能优化策略?

我可以用什么来分析Linux中的C++代码?

dir*_*tly 9

请不要抛弃任何旧的'优化是所有邪恶的根源'的东西,这对这个问题完全无关紧要

是的,然后你有这样的事情:

排序时,检查数据是否已按排序顺序排列

让我想知道你是否使用了有效的算法.其中,"过早优化是万恶之源"的基本前提.

并将被投票.

真?那种语气不好.IMO.因人而异.

同样地,我对让编译器为我优化它或者在整个地方抛出内联的乐趣感兴趣.FWIW,编译器优化代码与否之间的区别在于我的自动化套件中的12%,这是最终用户级别的边界可观察.

再加上您手工制作的任何优化,您仍然需要对编译器进行优化.

除此之外,由于您没有提供关于瓶颈位置的特定见解,因此很难提供任何指针.我至少猜到了你:

  • 玩自定义分配器
  • 如果您的目标机器是矢量指令,请探索使用矢量指令的可能性

编辑:因为你说你不知道RVO:尝试阅读移动语义,特别是这个库:来自Adobe的move.我想Boost会有类似的东西.

编辑#2:还有两件事:

  • 定点运算可能是一件好事
  • 尽可能多地使用查找表

  • @Shane:我使用了几十种(如果不是数百种)"优化技术",这些技术对我很有帮助.问题是我完全不知道哪些适用于你*,因为你没有告诉我们你的代码.心理调试很难,但精神优化根本不可能.在某些情况下,几乎每项优化都会变得悲观.它取决于应用它的上下文的120%,并且你没有给我们上下文. (4认同)

phi*_*red 5

CString MyFunc(double x, double y)

效率低于

void MyFunc(double x, double y, CString &Result)

如果MyFunc写得很干净,那么它们应该大致相同.编译器应该能够利用NRVO.这听起来像你已经描述并发现它不是 - 我只是说它可能更符合你的标准,例如"对代码的最小混淆",重新安排功能本身一点点以允许NRVO发生.

还有一些事情要尝试:

  1. memoization(类似于重复搜索的缓存,但更多关注树/图解析,如果你有的话).
  2. 如果您不需要额外的精度(或者如果可以的话,甚至可以使用整数),使用浮点数而不是双精度数.
  3. 使用类型来标记假设(您提到了排序数组 - 另一个常见的是小写字符串).创建一个派生或包装类型(例如Sorted<T>),使这些假设明确.这样,如果你有一个方法,Sorted<vector<T> >例如,你给它一个有序矢量,它直接通过 - 但如果你给它一个vector<T>,它将必须构造一个Sorted<vector<T> >,此时它将对它进行排序.您可以手动断言它是使用替代构造函数进行排序的,但它可以更容易地执行您的假设,也可能会捕获您可能错过的地方.
  4. 不要放弃内联等.确保你完全了解他们何时应该提供帮助以及何时应该阻止他们.在某些情况下,他们真的可以有所作为 - 但如果你只是随意处理它们可能不会.
  5. 您可能会受益于flyweight池化对象分配器.
  6. 在线程化时,尽量减少任何交互,这样可以减少需要锁定的代码量.通常,即使是相当昂贵的对象的副本也可能比互斥量更少.显而易见,尽可能利用原子类型.