Ruby基准测试准确性-分支预测处于最佳状态?
所以今天早上我决定第一次玩基准测试 我对使用“do end”块格式与使用“{}”格式的代码之间的速度差异感到好奇 因此,我将基准代码存储在一个Proc中,以便可以连续多次调用它:Ruby基准测试准确性-分支预测处于最佳状态?,ruby,processor,branch-prediction,Ruby,Processor,Branch Prediction,所以今天早上我决定第一次玩基准测试 我对使用“do end”块格式与使用“{}”格式的代码之间的速度差异感到好奇 因此,我将基准代码存储在一个Proc中,以便可以连续多次调用它: n = 100_000_000 bmp = Proc.new do Benchmark.bm do |x| x.report {n.times {a = "1"}} x.report {n.times do; a = "1"; end} end end 当我运行一次时,我的结果是预期的 >
n = 100_000_000
bmp = Proc.new do
Benchmark.bm do |x|
x.report {n.times {a = "1"}}
x.report {n.times do; a = "1"; end}
end
end
当我运行一次时,我的结果是预期的
>> bmp.call
user system total real
1.840000 0.030000 1.870000 ( 1.874507)
1.860000 0.050000 1.910000 ( 1.926101)
=> true
但后来又运行了一次
>> bmp.call
user system total real
1.870000 0.050000 1.920000 ( 1.922810)
1.840000 0.000000 1.840000 ( 1.850615)
在我看来,这与我的预期完全相反。我熟悉分支预测的概念。这是分支预测的经典示例吗?如果没有,什么?是否有任何方法可以防止此类错误(如果这被认为是错误的话)
编辑:在提出一些建议后,我确实运行了30多次这段代码。通常情况下,这两种结果会交替出现。以下是数据样本:
gist.github.com/TheLarkInn/5599676只是一个关于统计数据的快速入门: 我不确定两次跑步是否足以发现趋势。如果在第二次运行时,两个测试块之间的系统负载存在差异,该怎么办 确定两个样本之间统计差异的经验法则是,30个或更多数据点将给出统计相关的结果 我至少会运行您的测试很多次,分别存储两个版本的结果,然后在内部比较以确保它们一致,然后再将两个集相互比较
可能是您最初的前提不正确:)只是简单介绍一下统计数据: 我不确定两次跑步是否足以发现趋势。如果在第二次运行时,两个测试块之间的系统负载存在差异,该怎么办 确定两个样本之间统计差异的经验法则是,30个或更多数据点将给出统计相关的结果 我至少会运行您的测试很多次,分别存储两个版本的结果,然后在内部比较以确保它们一致,然后再将两个集相互比较
可能是您最初的前提不正确:)首先,您的基准测试毫无意义。
do
/end
语法和{
/}
语法之间的区别在于:语法。没有语义上的区别。因此,两者之间不可能存在任何运行时性能差异。这在逻辑上是不可能的。您不需要对其进行基准测试
唯一可能存在的性能差异是,一个需要比另一个更长的时间来解析。然而,这两种方法都不比另一种更难解析。唯一的区别是优先级。因此,解析过程中很可能也没有任何性能差异
即使在解析过程中存在性能差异,您的基准测试也不会显示这一点。您使用的是一个用Ruby编写的基准测试,但是为了运行Ruby代码,Ruby执行引擎必须首先解析它,这意味着在您的基准测试开始之前解析就已经发生了。因此,即使您的基准测试不是毫无意义的,它仍然是无用的,因为它不可能测量解析中的性能差异
关于分支预测的问题:代码中没有分支,没有什么可预测的
顺便说一句:即使你的基准测试是为了一个不同的目的,它仍然不会衡量任何东西,因为至少更高级的Ruby实现会认识到你的块本质上是没有操作的,只是简单地优化它们。即使它们没有被优化,它们所衡量的只是内存分配器的性能(分配几百兆字节的微小
字符串对象),而不是块的性能。首先,你的基准测试毫无意义。do
/end
语法和{
/}
语法之间的区别在于:语法。没有语义上的区别。因此,两者之间不可能存在任何运行时性能差异。这在逻辑上是不可能的。您不需要对其进行基准测试
唯一可能存在的性能差异是,一个需要比另一个更长的时间来解析。然而,这两种方法都不比另一种更难解析。唯一的区别是优先级。因此,解析过程中很可能也没有任何性能差异
即使在解析过程中存在性能差异,您的基准测试也不会显示这一点。您使用的是一个用Ruby编写的基准测试,但是为了运行Ruby代码,Ruby执行引擎必须首先解析它,这意味着在您的基准测试开始之前解析就已经发生了。因此,即使您的基准测试不是毫无意义的,它仍然是无用的,因为它不可能测量解析中的性能差异
关于分支预测的问题:代码中没有分支,没有什么可预测的
顺便说一句:即使你的基准测试是为了一个不同的目的,它仍然不会衡量任何东西,因为至少更高级的Ruby实现会认识到你的块本质上是没有操作的,只是简单地优化它们。即使它们没有被优化,它们所测量的只是内存分配器的性能(分配几百兆字节的微小字符串对象),而不是块的性能。系统负载不应该是主要因素,我认为基准测试是收集进程时钟(所以只注册代码正在做的事情,并且非常擅长忽略其他进程,尽管不是所有的事情——争用仍然可能发生在磁盘、RAM等上)。然而,这意味着尽管重复了1亿次,但在这个示例中只有约190个布尔值(“CPU正在运行我的进程”)