我有两个用C++编写的算法。据我所知,通常使用
-O0 -NDEBUG (g++),同时比较两种算法的性能(无症状地它们是相同的)。但我认为优化级别对其中之一是不公平的,因为它在所有情况下都使用STL。该程序使用普通数组,在使用-O0选项进行编译时,其性能比STL-heavy算法快5倍。但是当我用-O2 -NDEBUG编译它们时,性能差别并不大。
有没有办法在优化级别的-O0中充分利用STL (我在vector []运算符中受到了严重的性能影响)?
在比较两种算法时,您使用了什么优化级别(可能还有像-NDEBUG这样的变量)?
如果有人能提供一些关于比较用C++编写的算法的性能的学术研究趋势的想法,这也将是很有帮助的。
编辑:
好吧,为了隔离优化级别的问题,我现在使用一种算法,但现在有两种不同的实现。
我已经将一个带有原始指针(int和boolean)的函数更改为std::vector和std::vector...使用-O0 -NDEBUG时,性能为5.46s(原始指针)和11.1s(std::vector)。使用-O2 -NDEBUG时,性能分别为2.02s(原始指针)和2.21s(std::vector)。同样的算法,一种实现是使用4/5的int和boolean动态数组。另一种是使用std::vector和std::vector。它们在所有其他情况下都是相同的
您可以看到,在-O0中,std::vector的性能比指针快两倍。而在-O2中它们几乎是一样的。
但我真的很困惑,因为在学术领域,当他们在运行时发布算法的结果时,他们用-O0编译程序。
有没有我遗漏的一些编译器选项?
发布于 2009-10-03 06:33:07
这取决于您想要针对什么进行优化。
速度
我建议使用-O2 -NDEBUG -ftree-vectorize,如果您的代码专门设计为在x86或x86_64上运行,则添加-msse2。这将使您对它在GIMPLE中的性能有一个大致的了解。
大小
我认为你应该使用-Os -fno-rtti -fno-exceptions -fomit-frame-pointer。这将在一定程度上最小化可执行文件的大小(假设为C++)。
在这两种情况下,算法的速度都不依赖于编译器,但如果编译器能够“证明”它可以的话,它可以彻底改变代码的行为方式。
GCC会检测诸如手工编码的min()和max()之类的“公共”代码,并将它们转换为一条SSE指令(在x86/x86_64上,当-msse被设置时),或者在i686可用时使用cmov (SSE具有更高的优先级)。如果需要,GCC还可以自由地对循环进行重新排序,展开和内联函数,甚至删除无用的代码。
至于你的最新编辑:
你可以看到,在-O0 std::vector中,指针的速度要快两倍。而在-O2中它们几乎是一样的。
这是因为std::vector仍然有抛出异常的代码,并且可能使用rtti。尝试与-O2 -NDEBUG -ftree-vectorize -fno-rtti -fno-exceptions -fomit-frame-pointer进行比较,您会发现std::vector会比您的代码稍好一些。GCC知道什么是“内置”类型,以及如何利用它们在现实世界中使用,并且会很乐意这样做-就像它知道memset()和memcpy()做什么,以及当副本大小已知时如何进行相应的优化一样。
发布于 2009-10-03 06:33:47
在C++中实现了两种算法。如果您想要比较两种实现的相对性能,那么您应该使用最终产品中将要使用的优化级别。对我来说,这就是-O3。
如果你想分析一个算法的复杂性,那么这更多的是一个分析问题,你需要查看针对不同大小和特征的输入必须执行的操作的总数。
作为编写性能问题的代码的开发人员,了解编译器可以并可能应用于您的代码的优化范围是一个好主意。不优化会不公平地惩罚那些写得很清楚的代码,但设计成很容易针对已经“微优化”的代码进行优化。
发布于 2009-10-03 06:30:15
我认为没有理由不在O2上编译和运行它们。除非您是纯粹的学术练习(即使您是这样做的,优化也不太可能从根本上改变算法的属性--不过,如果GCC开始将O(N)源代码转换为O(lgN)汇编,我想我会很高兴),您将需要与实际运行最终程序时得到的信息一致的信息。您很可能不会发布具有O0优化的程序,因此您不希望比较O0优化下的算法。
https://stackoverflow.com/questions/1512972
复制相似问题