搜索有关std算法性能的任何信息,我发现the Stack Overflow question关于std::max_element()
与自写函数之间的性能差异。我已经使用GCC 9.2.0测试了问题中的功能,但没有发现性能差异,即my_max_element_orig()
和my_max_element_changed()
(来自公认的答案)显示出相同的性能。因此,这似乎只是GCC 4.8.2中的优化程序问题。对于GCC 9.2.0,我真正发现的是在使用指针和迭代器的情况下的显着差异-与原始指针相比,使用迭代器的情况要差2倍。如果使用std::max_element()
,则迭代器和原始指针也有类似的区别。
让我们采用my_max_element_orig
函数实现(请参见下文)并尝试运行测试。
template<typename _ForwardIterator>
_ForwardIterator my_max_element_orig(_ForwardIterator __first, _ForwardIterator __last)
{
if (__first == __last) return __first;
_ForwardIterator __result = __first;
while (++__first != __last)
if (*__result < *__first)
__result = __first;
return __result;
}
以下用法示例
int maxValue = *my_max_element_orig(begin(vec), end(vec));
比以下(原始指针)差
int maxValue = *my_max_element_orig(vec.data(), vec.data() + vec.size());
有人可能会说,原因是迭代器类的实现带来了一些开销。但是我发现原因是下面这行的意思:
if (__first == __last) return __first;
如果从函数中删除了上面的行,则迭代器显示的性能与原始指针相同。经过一些实验,我决定干预优化器的分支预测,并用以下内容替换行:
#define unlikely(x) __builtin_expect((x),0)
...
if (unlikely(__first == __last)) return __first;
在my_max_element_orig()
以上的更改下,无论使用迭代器还是原始指针,函数均显示相同的性能。我对std::max_element()
文件中的std_algo.h
函数进行了类似的更改,并获得了相同的结果-现在std::max_element()
的迭代器和原始指针的性能相同。
事实既是我链接的原始问题,也是我发现的有关“ GCC优化器如何工作”或“是优化器问题”的问题。但是我想使用std算法,并且我不想重新编写它们以获得更优化的代码。因此,我想知道是否有一种方法可以更改std::max_element()
的分支预测,就像我上面为自己的函数所做的那样。或更笼统地说,有没有一种方法可以使标准算法更优化而不用重写它们?
g++ -DNDEBUG -O3 -Wall -fmessage-length=0 --std=c++17