我正在为我的quicksort实施执行一些执行时间基准测试。在完全相同的输入数据上进行的100次连续测量中,第一次调用quicksort似乎比所有连续调用花费的时间长大约10倍。这是操作系统准备执行该程序的结果,还是有其他解释?而且,在计算平均运行时间时是否丢弃第一次测量值是否合理?
下面的条形图说明了执行时间(毫秒)与方法调用号的关系。每次调用该方法时,它都会处理完全相同的数据。
要生成此特定图形,主要方法将调用quicksort_timer::time_fpi_quicksort(5, 100)
,其实现如下所示。
static void time_fpi_quicksort(int size, int runs)
{
std::vector<int> vector(size);
for (int i = 0; i < runs; i++)
{
vector = utilities::getRandomIntVectorWithConstantSeed(size);
Timer timer;
quicksort(vector, ver::FixedPivotInsertion);
}
}
getRandomIntVectorWithConstantSeed
的实现方式如下
std::vector<int> getRandomIntVectorWithConstantSeed(int size)
{
std::vector<int> vector(size);
srand(6475307);
for (int i = 0; i < size; i++)
vector[i] = rand();
return vector;
}
CPU和编译
CPU:Broadwell 2.7 GHz Intel Core i5(5257U)
编译器版本:Apple LLVM版本10.0.0(clang-1000.11.45.5)
编译器选项:-std=c++17 -O2 -march=native
答案 0 :(得分:3)
是的,可能是页面上的页面错误,其中包含排序功能的代码(以及计时代码本身)。 10倍可能还包括加速到最大Turbo时钟速度。
不过,缓存是不合理的:但是,您是在定时区域之外编写(小)数组,除非编译器以某种方式用d2
的构造函数对init进行了重新排序。第一次的内存分配要慢得多,这很容易解释,也许第一次必须进行系统调用才能获得新页面,但是后来调用Timer
(以构造std :: vector)已经抓到了-空闲列表中的高速缓存中的内存。
训练分支预测器也可能是一个重要因素,但是您希望它花费超过1次才能运行现代Intel CPU中的TAGE分支预测器,或者使用感知器预测器中的感知器。现代AMD“学习”了所有分支的完整模式。但是也许它们在第一次运行后就接近了。
请注意,您每次每次调用都会使用new
来生成 same 随机数组。要测试分支预测是否是解释,请删除srand()
,以便您每次都获得不同的数组,并查看时间是否仍然更长。
您使用什么CPU,编译器版本/选项等?
答案 1 :(得分:0)
可能是由于缓存的缘故,因为需要从DRAM提取内存并在第一次将其分配到CPU的数据缓存中。与在CPU缓存中命中的负载相比,这需要更多(更多)的延迟。
然后,由于您的指令位于管道中,因此它们遵循相同的分支,因为它是来自同一内存源的指令,因为它是相同的指针,因此不需要使它无效。
如果您实现4种方法或多或少具有相同的功能,然后在它们之间进行互换以查看会发生什么,将会很有趣。