繁体   English   中英

埃拉托色尼 C++ 代码的筛选在连续运行中加速 - 为什么?

[英]Sieve of eratosthenes c++ code speeds up in consecutive runs - why?

我对这个问题进行了快速检查,但找不到答案 - 尽管我猜它之前可能已经在这里提出过。

我正在忙着用 C++ 编写一个简单的埃拉托色尼筛实现,并为结果计时:

#include <iostream> 
#include <math.h>


int main() {

  int n = 100000;
  int seive [n];

  for (int i=0; i<n; i++) {
    seive[i] = i;
  }

  for (int i=2; i < ceil(sqrt(n)); i++) {
    for (int j=i*2; j<=n; j+=i) {
      seive[j-1] = -9;
    }
  }

  for (int i=0; i<n; i++) {
    if (seive[i] != -9) {
      std::cout << i+1 << "\n";
    }
  }

  return 0;
}

我使用以下方法编译它:

g++ seive.cpp -o seiveCpp

然后使用它计时:

time ./seiveCpp

第一次:

./seiveCpp  0.01s user 0.01s system 10% cpu 0.184 total

第二次:

./seiveCpp  0.01s user 0.01s system 58% cpu 0.034 total

第三次:

./seiveCpp  0.01s user 0.01s system 59% cpu 0.037 total

等等。

如果我多次重复此操作,似乎第一次运行代码总是比所有连续时间慢 5 倍左右。

这背后的原因是什么?

我在 2017 款 MacBook Pro、2.3 GHz 双核 Intel Core i5 上运行它,并使用 Apple clang 版本 11.0.0 (clang-1100.0.33.12

原因是因为分支预测器。 第一次运行时,计算机对程序一无所知,但在执行它时,会在代码(for 和 if)的跳转中找到逻辑,然后可以更好地预测它应该采用哪个分支。 在现代处理器中,有很长的命令管道,因此正确预测跳转可以显着减少工作时间。

因此,要按执行时间比较几个算法,最好运行一百次并花费最少的时间。

鉴于非常大的差异,我猜想 CPU 在您开始第一次运行时处于较低的性能模式,但是在第一次运行的负载下,操作系统将其切换到较高的性能模式,您观察到执行时间降低.

如果您想避免这种影响,请确保您的笔记本电脑连接到交流电源并且禁用所有节能选项。

在任何情况下,仍然会存在缓存效果(例如,可执行文件中的内容可能会缓存在内存中)。 但我认为这些不应该是 100 毫秒的数量级。

一般来说,当您对代码进行基准测试时,您应该始终进行热身运行,因为出于某种原因,总会在某种程度上产生这种影响。 可以这么说,您通常希望在环境达到平衡状态时执行实际测试运行。

当操作系统第一次将文件加载到内存中多次运行程序时,下一次它很可能已经存在(尽管根据编译器/链接器的设置,重定位可能仍然是必要的,即位置无关代码生成)。 如果您在单个进程中多次运行相同的代码(这是收集性能数据时的一个好主意 - 将计时代码放入程序中并多次运行感兴趣的代码),分支位置答案将更有可能适用,为每个循环计时,而不是多次运行整个程序并使用外部时间程序)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM