Benchmark - Perl 代码运行时间的基准测试
use Benchmark qw(:all) ;
timethis ($count, "code");
# Use Perl code in strings...
timethese($count, {
'Name1' => '...code1...',
'Name2' => '...code2...',
});
# ... or use subroutine references.
timethese($count, {
'Name1' => sub { ...code1... },
'Name2' => sub { ...code2... },
});
# cmpthese can be used both ways as well
cmpthese($count, {
'Name1' => '...code1...',
'Name2' => '...code2...',
});
cmpthese($count, {
'Name1' => sub { ...code1... },
'Name2' => sub { ...code2... },
});
# ...or in two stages
$results = timethese($count,
{
'Name1' => sub { ...code1... },
'Name2' => sub { ...code2... },
},
'none'
);
cmpthese( $results ) ;
$t = timeit($count, '...other code...')
print "$count loops of other code took:",timestr($t),"\n";
$t = countit($time, '...other code...')
$count = $t->iters ;
print "$count loops of other code took:",timestr($t),"\n";
# enable hires wallclock timing if possible
use Benchmark ':hireswallclock';
Benchmark 模块封装了许多例程,帮助你了解执行某些代码需要多长时间。
timethis - 多次运行一段代码
timethese - 多次运行多段代码
cmpthese - 将 timethese 的结果打印为比较图表
timeit - 运行一段代码并查看它运行了多长时间
countit - 查看一段代码在给定时间内运行了多少次
返回当前时间。示例
use Benchmark;
$t0 = Benchmark->new;
# ... your code here ...
$t1 = Benchmark->new;
$td = timediff($t1, $t0);
print "the code took:",timestr($td),"\n";
通过设置 $Benchmark::Debug
标志启用或禁用调试
Benchmark->debug(1);
$t = timeit(10, ' 5 ** $Global ');
Benchmark->debug(0);
返回迭代次数。
如果您使用 Benchmark 模块,以下例程将导出到您的命名空间中
参数:COUNT 是运行循环的次数,CODE 是要运行的代码。CODE 可以是代码引用或要评估的字符串;无论哪种方式,它都将在调用者的包中运行。
返回:Benchmark 对象。
对 CODE 进行 COUNT 次迭代。CODE 可以是用于评估的字符串或代码引用;无论哪种方式,CODE 都将在调用者的包中运行。结果将以 TITLE 后跟时间的方式打印到 STDOUT。如果未提供 TITLE,则默认为“timethis COUNT”。STYLE 确定输出的格式,如下面 timestr() 所述。
COUNT 可以为零或负数:这意味着运行的最少 CPU 秒数。零表示默认值 3 秒。例如,要至少运行 10 秒
timethis(-10, $code)
或至少运行 3 秒的两段代码测试
timethese(0, { test1 => '...', test2 => '...'})
CPU 秒数在 UNIX 术语中是指进程本身的用户时间加上系统时间,而不是实际(时钟)时间和子进程花费的时间。小于 0.1 秒的时间不被接受(例如,-0.01 作为计数将导致致命运行时异常)。
请注意,CPU 秒数是最少时间:CPU 调度和其他操作系统因素可能会使尝试变得复杂,从而花费更多时间。但是,基准输出也会告诉 $code
运行/秒的次数,这应该是一个比实际花费的秒数更有趣的数据。
返回 Benchmark 对象。
CODEHASHREF 是对哈希的引用,其中包含名称作为键,以及每个值的字符串以进行评估或代码引用。对于 CODEHASHREF 中的每个 (KEY, VALUE) 对,此例程将调用
timethis(COUNT, VALUE, KEY, STYLE)
例程按 KEY 的字符串比较顺序调用。
COUNT 可以为零或负数,请参见 timethis()。
返回按名称键入的 Benchmark 对象的哈希引用。
返回两个 Benchmark 时间之间的差值,作为适合传递给 timestr() 的 Benchmark 对象。
返回一个字符串,该字符串以请求的 STYLE 格式化 TIMEDIFF 对象中的时间。TIMEDIFF 预计是类似于 timediff() 返回的 Benchmark 对象。
STYLE 可以是 'all'、'none'、'noc'、'nop' 或 'auto' 中的任何一个。'all' 显示 5 个可用时间中的每一个('wallclock' 时间、用户时间、系统时间、子进程的用户时间和子进程的系统时间)。'noc' 显示除两个子进程时间之外的所有时间。'nop' 仅显示 wallclock 和两个子进程时间。'auto'(默认值)将作为 'all',除非子进程时间都为零,在这种情况下它将作为 'noc'。'none' 阻止输出。
FORMAT 是 printf(3)- 样式格式说明符(不带前导 '%'),用于打印时间。其默认值为 '5.2f'。
如果您明确要求导入以下例程,它们将导出到您的名称空间中
清除空循环的 COUNT 轮的缓存时间。
清除所有缓存时间。
可选地调用 timethese(),然后输出比较图表。此
cmpthese( -1, { a => "++\$i", b => "\$i *= 2" } ) ;
输出类似于
Rate b a
b 2831802/s -- -61%
a 7208959/s 155% --
此图表按从最慢到最快的顺序排序,并显示每对测试之间的百分比速度差。
cmpthese
还可以传递 timethese() 返回的数据结构
$results = timethese( -1,
{ a => "++\$i", b => "\$i *= 2" } ) ;
cmpthese( $results );
以防您想同时查看两组结果。如果第一个参数是未祝福的哈希引用,那就是 RESULTSHASHREF;否则就是 COUNT。
返回对行的 ARRAY 的引用,每行都是来自上述图表的一个 ARRAY 的单元格,包括标签。此
my $rows = cmpthese( -1,
{ a => '++$i', b => '$i *= 2' }, "none" );
返回类似于
[
[ '', 'Rate', 'b', 'a' ],
[ 'b', '2885232/s', '--', '-59%' ],
[ 'a', '7099126/s', '146%', '--' ],
]
注意:此结果值与返回 timethese()
结果结构的旧版本不同。如果您需要旧版本,只需使用上面所示的两条语句 timethese
...cmpthese
惯用语即可。
顺便说一句,请注意两个示例之间结果值的差异;这是基准测试的典型情况。如果这是真正的基准测试,您可能需要运行更多迭代。
参数:TIME 是运行 CODE 的最短时间,而 CODE 是要运行的代码。CODE 可以是代码引用或要进行 eval 的字符串;无论哪种方式,它都将在调用者的程序包中运行。
TIME 不是负数。countit() 将多次运行循环,以计算在运行 TIME 之前 CODE 的速度。由于系统时钟分辨率,实际运行时间通常会大于 TIME,因此最好查看迭代次数除以您关注的时间,而不仅仅是迭代次数。
返回:Benchmark 对象。
禁用空循环的计时缓存。这将强制 Benchmark 为每个新计时代码重新计算这些计时。
启用空循环的计时缓存。空循环的 COUNT 轮所花费的时间仅针对使用的每个不同的 COUNT 计算一次。
将两个 Benchmark 时间相加,并返回一个 Benchmark 对象,该对象适合传递给 timestr()。
如果已安装 Time::HiRes 模块,则可以为 Benchmark 指定特殊标记 :hireswallclock
(如果 Time::HiRes 不可用的,则该标记将被忽略)。此标记将使时钟时间以微秒为单位测量,而不是整数秒。但请注意,速度计算仍以 CPU 时间进行,而不是时钟时间。
此模块中的许多函数返回基准对象,或者在 timethese()
的情况下,返回对哈希的引用,其值是基准对象。如果您想存储或进一步处理基准函数的结果,这将非常有用。
基准对象在内部保存计时值,如下面 "NOTES" 中所述。可以使用以下方法访问它们
主(父)进程的总 CPU(用户 + 系统)。
任何子进程的总 CPU(用户 + 系统)。
父进程和任何子进程的总 CPU。
实际经过时间“时钟秒”。
运行的迭代次数。
以下说明了基准对象的用法
$result = timethis(100000, sub { ... });
print "total CPU = ", $result->cpu_a, "\n";
数据存储为 time 和 times 函数的值列表
($real, $user, $system, $children_user, $children_system, $iters)
以整个循环的秒数为单位(不除以回合数)。
计时使用 time(3) 和 times(3) 完成。
代码在调用者的包中执行。
空循环的时间(具有相同回合数但循环体为空的循环)从实际循环的时间中减去。
可以缓存空循环时间,键是回合数。可以使用如下调用控制缓存
clearcache($key);
clearallcache();
disablecache();
enablecache();
默认情况下,缓存处于关闭状态,因为它(通常会轻微地)降低准确性,并且通常不会明显影响运行时间。
例如,
use Benchmark qw( cmpthese ) ;
$x = 3;
cmpthese( -5, {
a => sub{$x*$x},
b => sub{$x**2},
} );
输出类似以下内容
Benchmark: running a, b, each for at least 5 CPU seconds...
Rate b a
b 1559428/s -- -62%
a 4152037/s 166% --
而
use Benchmark qw( timethese cmpthese ) ;
$x = 3;
$r = timethese( -5, {
a => sub{$x*$x},
b => sub{$x**2},
} );
cmpthese $r;
输出类似以下内容
Benchmark: running a, b, each for at least 5 CPU seconds...
a: 10 wallclock secs ( 5.14 usr + 0.13 sys = 5.27 CPU) @ 3835055.60/s (n=20210743)
b: 5 wallclock secs ( 5.41 usr + 0.00 sys = 5.41 CPU) @ 1574944.92/s (n=8520452)
Rate b a
b 1574945/s -- -59%
a 3835056/s 144% --
Benchmark 不从除 Exporter 之外的任何其他类继承。
将 eval 后的字符串与代码引用进行比较会得到不准确的结果:代码引用显示的执行时间会比等效的 eval 后的字符串略慢。
实际时间计时使用 time(2) 完成,因此粒度仅为一秒。
短测试可能会产生负数,因为 perl 看起来执行空循环的时间比短测试的时间长;请尝试
timethis(100,'1');
空循环的系统时间可能略长于具有实际代码的循环的系统时间,因此差值最终可能为 < 0。
Devel::NYTProf - Perl 代码分析器
Jarkko Hietaniemi <[email protected]>、Tim Bunce <[email protected]>
1994 年 9 月 8 日;作者 Tim Bunce。
1997 年 3 月 28 日;作者 Hugo van der Sanden:增加了对代码引用的支持和已记录的“debug”方法;改进了文档。
1997 年 4 月 4 日至 7 日:作者 Jarkko Hietaniemi,增加了运行一段时间的功能。
1999 年 9 月;作者 Barrie Slaymaker:数学修正以及准确性和效率调整。添加了 cmpthese()。现在从 timethese() 返回结果。公开了 countit()(以前是 runfor())。
2001 年 12 月;作者 Nicholas Clark:让 timestr() 识别“none”样式并返回空字符串。如果 cmpthese 调用 timethese,则让它传递样式。(以便“none”会禁止输出)。让子 new 将其调试输出转储到 STDERR,以与其他所有内容保持一致。在编写回归测试时发现的所有错误。
2002 年 9 月;作者 Jarkko Hietaniemi:添加“:hireswallclock”特殊标记。
2004 年 2 月;作者 Chia-liang Kao:当样式为“nop”时,让 cmpthese 和 timestr 对子项使用时间统计信息,而不是父项。
2007 年 11 月;作者 Christophe Grosjean:让 cmpthese 和 timestr 根据样式参数一致地计算时间,默认值不再是“noc”而是“all”。