我在以下文件中修改了TCL8.4.20源代码以测量TCL脚本的运行时间:
void save() { struct timespec t; clock_gettime(CLOCK_MONOTONIC_RAW, &t); save_to_an_array(); }
tclMain.c,在Tcl_Main()函数中,在调用Tcl_FSEvalFile()之前,记录时间
tclBasic.c,在Tcl_EvalEx()中,在开始,记录时间;每个出口都有多个出口,记录时间。
tclMain.c,在退出Tcl_Main()之前,转储所有录音。
像往常一样构建TCL源代码,可执行文件tclsh8.4现在有了我的内置函数来记录脚本运行时间并在最后转出时间。
我使用单行脚本:puts hello
令我惊讶的是,运行时间差异很大。这是一个连续的时间:
run1 - 232.00ms
run2 - 7886.00ms
run3 - 6973.00ms
run4 - 5749.00ms
run5 - 224.00ms
run6 - 6820.00ms
run7 - 6074.00ms
run8 - 221.00ms
也许字节码版本具有更好的一致性?所以我向Tcl_EvalObjEx和TclExecuteByteCode()添加了更多探测器。这是新脚本:
proc p {} {
puts hello
}
p
但它也不一致:
run1 - 226.00ms
run2 - 7877.00ms
run3 - 6964.00ms
run4 - 5740.00ms
run5 - 218.00ms
run6 - 6809.00ms
run7 - 6064.00ms
run8 - 216.00ms
你看到可能出现什么问题吗?
[ 更新 ]
也许puts
是一个糟糕的选择,因为它是受许多系统问题影响的I / O函数,因此我将脚本更改为一些随机命令:
set a 100
set b 200
append a 300
array set arr1 {one 1 two 2}
绝对更好:
run1 - 9.00ms
run2 - 9.00ms
run3 - 19.00ms
run4 - 9.00ms
run5 - 9.00ms
run6 - 9.00ms
run7 - 9.00ms
run8 - 9.00ms
run9 - 9.00ms
run10 - 9.00ms
但是,19ms的run3怎么来自?
答案 0 :(得分:0)
使用挂钟计时的问题在于它对系统上正在发生的任何事情非常敏感。操作系统可以随时决定暂停您的进程,理由是让CPU执行其他“更重要”的工作。它并不知道您正在尝试进行性能测量。
解决这个问题的常用方法是执行时序脚本的多次运行并采用最小的测量时序,同时要记住执行时序的成本非零且可能会对输出。
标准Tcl中的time
命令适用于此类事情。这是一个使用示例:
puts [time {
set a 100
set b 200
append a 300
array set arr1 {one 1 two 2}
} 100]
这将运行100次之前的代码片段并打印平均执行时间。 (在我的性能密集型测试中,我将使用一大堆稳定代码,以便我从甚至微基准测试中获得合理的信息,但他们真正做的就是猜测迭代和打印的良好价值一堆样本的最小值。此外,微基准测试最终可能会导致数十万或数百万的迭代计数。)
请注意,您使用的是已经过终结的Tcl版本。 8.5是当前的LTS版本(即,它主要只接收安全修复程序 - 如果有的话;我们没有多少漏洞 - 并且更新以支持不断发展的OS API),而8.6则用于新工作。 (8.7和9.0正在开发中,但仍然是pre-alpha。)