ErasoStIES C++代码的筛选器在连续运行中加速了——为什么?
我快速查看了一下这个问题,但找不到答案——尽管我猜它可能是以前在这里提出来的 我在写一个C++中的ErasoStEes筛选器的简单实现,然后给出结果:ErasoStIES C++代码的筛选器在连续运行中加速了——为什么?,c++,performance,cpu,C++,Performance,Cpu,我快速查看了一下这个问题,但找不到答案——尽管我猜它可能是以前在这里提出来的 我在写一个C++中的ErasoStEes筛选器的简单实现,然后给出结果: #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
#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版编译。原因在于分支预测器。第一次运行时,计算机对程序一无所知,但在执行程序时,它会在代码的跳转中找到逻辑,if和then可以更好地预测它应该采用哪个分支。在现代处理器中,有很长的命令管道,因此正确预测跳转可以显著减少工作时间
因此,通过执行时间来比较几种算法,最好是运行100次并占用最少的时间 原因在于分支预测器。第一次运行时,计算机对程序一无所知,但在执行程序时,它会在代码的跳转中找到逻辑,if和then可以更好地预测它应该采用哪个分支。在现代处理器中,有很长的命令管道,因此正确预测跳转可以显著减少工作时间
因此,通过执行时间来比较几种算法,最好是运行100次并占用最少的时间 考虑到非常大的差异,我猜当您开始第一次运行时,CPU处于较低的性能模式,但在第一次运行的负载下,操作系统将其切换到较高的性能模式,您会发现这是较低的执行时间 确保您的笔记本电脑已连接到交流电源,并且如果要避免这种影响,请禁用所有节能选项 在任何情况下,仍然会留下缓存效果,例如,可执行文件中的内容可能会缓存在内存中。但我认为这些不应该是100毫秒左右
一般来说,当您对代码进行基准测试时,您应该始终进行预热运行,因为在某种程度上,由于某种原因,总会有这样的影响。一般来说,您希望在环境达到平衡状态时执行实际的测试运行。考虑到非常大的差异,我猜当您开始第一次运行时,CPU处于较低的性能模式,但在第一次运行的负载下,操作系统将其切换到较高的性能模式,您观察到执行时间缩短了 确保您的笔记本电脑已连接到交流电源,并且如果要避免这种影响,请禁用所有节能选项 在任何情况下,仍然会留下缓存效果,例如,可执行文件中的内容可能会缓存在内存中。但我认为这些不应该是100毫秒左右
一般来说,当您对代码进行基准测试时,您应该始终进行预热运行,因为在某种程度上,由于某种原因,总会有这样的影响。一般来说,您希望在环境达到平衡状态时执行实际测试运行。当操作系统第一次必须将文件加载到内存时多次运行程序,下一次可能已经存在该文件,尽管根据编译器/链接器的设置可能仍需要重新定位,即是否生成位置独立代码。如果您在单个进程中多次运行同一代码,分支位置答案将更有可能适用,这在收集性能数据时是一个好主意-将计时代码放入程序中,并多次运行感兴趣的代码,为每个循环计时,而不是使用外部计时程序多次运行整个程序。当操作系统第一次必须将文件加载到内存中时,程序多次运行时,下一次可能已经存在,尽管根据编译器/链接器的设置可能仍需要重新定位,即是否生成位置独立代码。如果您在单个进程中多次运行同一代码,分支位置答案将更有可能适用,这在收集性能数据时是一个好主意-将计时代码放入程序中,并多次运行感兴趣的代码,为每个循环计时,而不是多次运行整个程序并使用外部计时程序。int seive[n];-这不是C++。C++中的数组必须具有由编译时Excel表示的大小。
session,而不是运行时变量或表达式,如n。使用std::vector seiven;相反,如果您正在对您的程序进行基准测试,那么启用优化将是一个好主意。尝试添加-O2或-O3选项标志。您测量筛网性能的机制不合适。最大的影响是,你的时间安排显然包括了所有素数的成本。连接到控制台是非常昂贵的。您可以将输出重定向到文件。您可能会将结果保存到内存中,也许是stringstream?,然后在计时器停止后将其保存。事实上,我并不担心这段特定代码的性能—我只是碰巧对其计时,并注意到它在第二次运行时总是比较慢。这更像是一个通过这个例子说明的一般性问题。也许你什么都没学到,因为到终端的cout是非常可变的,而且通常很慢。也许你太依赖、太相信“时间”这个实用工具的使用了这不是C++。C++中的数组必须用编译时表达式表示它们的大小,而不是运行时变量或表达式,如N。使用std::vector seiven;相反,如果您正在对您的程序进行基准测试,那么启用优化将是一个好主意。尝试添加-O2或-O3选项标志。您测量筛网性能的机制不合适。最大的影响是,你的时间安排显然包括了所有素数的成本。连接到控制台是非常昂贵的。您可以将输出重定向到文件。您可能会将结果保存到内存中,也许是stringstream?,然后在计时器停止后将其保存。事实上,我并不担心这段特定代码的性能—我只是碰巧对其计时,并注意到它在第二次运行时总是比较慢。这更像是一个通过这个例子说明的一般性问题。也许你什么都没学到,因为到终端的cout是非常可变的,而且通常很慢。也许你太依赖,太相信“时间”效用的使用。