我们应该测量例程的平均执行时间还是最短执行时间?

WeG*_*ars 4 c++ delphi profiling timing execution

当我们测量例程的执行时间(始终使用相同的输入)时,即使我们应该得到相同的结果(时间),我们也不会得到相同的结果(时间),因为程序在多任务环境中运行。即使我们以“高优先级”运行我们的程序,CPU 中运行的其他程序的一些干扰当然也会稍微影响结果。

测量的目的是在代码优化之前和之后对例程进行计时。

大多数人会对这个函数进行多次计时并取平均值。为什么我们不看最小执行时间而不是平均值呢?

Joh*_*ica 6

您应该始终以最短时间为目标。
因为如果你这样做,你确定你只是对你自己的代码进行计时,而没有其他任何事情。

争取最短时间
如果您的代码只有一个执行路径,那么您应该始终将最短时间(在多次重复中)作为实际花费的时间。
通过这种方式,您可以获得精确到一两个 CPU 周期内的计时。需要明确的是,您运行代码片段数百万次,并采用该运行的最低样本作为计时。
然后,您将这数百万次运行包装在一个运行 10 倍或 100 倍的循环中,并再次采用最低的计时。就像这样:

Lowest = MaxInt;
loop 100x 
  loop million times
     Clock.Start;
     DoTest;
     Timing = Clock.Time;
     if (timing < Lowest) {Lowest = timing}
Run Code Online (Sandbox Code Playgroud)

另一个循环重置上下文,这有时会有所帮助。例如,如果 JIT 编译器启动较晚,这一点很重要。外循环给它一个改变来重置。

如果代码片段特别快,您还可以在外循环中计时,然后除以一百万。在这种情况下,您将运行一个额外的空计时循环,并从繁忙循环中花费的时间减去空循环花费的时间。
不过,您必须变得聪明,以防止代码优化消除空循环:-)。

如果您的代码有多个可能的路径,那么您无法真正计算其执行时间。仅运行一个具有固定输入的简单循环,因为这只会为您提供一个代码路径的部分时间。这可能并不代表现实世界的表现。

使您的运行具有确定性
始终尝试修复代码,以便代码只能采用一条路径。
或者尝试设置测试,以便连续采用所有可能的路径,然后计算所有内容所花费的最短时间,然后除以测试的代码路径数。

一切和厨房水槽分析
如果不可能,您将不得不取平均值,但请注意,在这种情况下,您不再真正只对代码进行计时,您还需要考虑系统开销、HDD 中断和后台进程考虑到。