【问题标题】:Extreme slow-down when starting at second permutation从第二个排列开始时极度减速
【发布时间】:2017-11-28 15:58:05
【问题描述】:

考虑以下代码:

#include <algorithm>
#include <chrono>
#include <iostream>
#include <numeric>
#include <vector>

int main() {
    std::vector<int> v(12);
    std::iota(v.begin(), v.end(), 0);

    //std::next_permutation(v.begin(), v.end());

    using clock = std::chrono::high_resolution_clock;
    clock c;
    auto start = c.now();

    unsigned long counter = 0;
    do {
        ++counter;
    } while (std::next_permutation(v.begin(), v.end()));

    auto end = c.now();
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);    
    std::cout << counter << " permutations took " << duration.count() / 1000.0f << " s";
}

在我的 AMD 4.1 GHz CPU 上使用 GCC (MinGW) 5.3 -O2 编译,这需要 2.3 s。但是,如果我在未注释的行中发表评论,它会减慢到 3.4 s。我期望最小的加速,因为我们测量的时间减少了一个排列。使用 -O3 时,2.0 s2.4 s 之间的差异不那么极端。

谁能解释一下?超级智能的编译器能否检测到我想要遍历所有排列并优化这段代码?

【问题讨论】:

  • 两次调用next_permutation导致它没有被内联
  • 您是否看到与 -O0 类似的行为?
  • Fwiw,Compiler Explorer 清楚地显示了 -O2 中缺少内联 - 请参阅 commented codeuncommented code。更奇怪的情况实际上是 -O3,其中所有调用都是内联的,但程序集的排列方式略有不同。为什么重新排序会产生更差的性能(根据 OP 的报告)尚不清楚。
  • @Serge no 和 -O0 都运行同样慢
  • 谢谢,我觉得它很有教育意义。顺便说一句,我认为 -O3 没有任何区别。实际上,“慢”版本的运行速度比快速版本快几分之一秒 :-)。

标签: c++ performance function permutation compiler-optimization


【解决方案1】:

我认为编译器会因为你在代码的两行单独调用函数而感到困惑,导致它不是内联的。

GCC 8.0.0 的行为也和你的一样。

Benefits of inline functions in C++?它为编译器提供了一种简单的机制来应用更多的优化,因此在某些情况下丢失内联标识可能会导致性能严重下降。

【讨论】:

  • 这似乎确实是问题的一部分:将行放入不可优化但总是错误的if 语句会导致相同的下降,尽管该函数从未被调用。有位置。 但是如果函数被执行,代码运行速度仍然0.1 s慢。
猜你喜欢
  • 2018-06-25
  • 2018-11-16
  • 1970-01-01
  • 2016-11-07
  • 1970-01-01
  • 1970-01-01
  • 2020-11-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多