我们有一个项目,我们在其中运行几个测试,持续时间约为 3 小时。而且我观察到在生成结果的步骤中会浪费很多时间。例如:我有这个脚本harness.pl
use strict;
use TAP::Harness;
use TAP::Formatter::HTML;
use TAP::Formatter::Console;
# Define Tests
my $tests = {
"test_1" => {
test => 'script.t',
args => ['--server', "server_1"]
},
# "test_2" => {
# test => 'script.t',
# args => ['--server', "server_2"]
# },
};
# Get arguments
my $test_args = {};
$test_args->{$_} = $tests->{$_}->{args} foreach (sort keys %$tests);
# Define formatter
# my $fmt = TAP::Formatter::HTML->new();
# $fmt->output_file( "report.html" );
my $fmt = TAP::Formatter::Console->new({verbosity=>1});
# Start testing
my $harness = TAP::Harness->new( {
test_args => $test_args,
formatter => $fmt,
merge => 1,
jobs => 1,
} );
my $result = $harness->runtests(get_tests($tests));
print( "$0 Run Time: " . ( time - $^T ) . " second(s).\n");
print "Passed: ". scalar $result->passed . "\n";
print "Failed: ". scalar $result->failed . "\n";
print "Errors: ". scalar $result->has_errors . "\n";
sub get_tests{
my ($tests) = @_;
my @tests_to_run;
TEST: foreach my $test (sort keys %$tests){
# some filtering...
push @tests_to_run, [$tests->{$test}->{test}, $test]
}
# some prints...
return @tests_to_run;
}
还有几个测试,让我们举一个例子script.
:
use strict;
use warnings;
use Test::More;
use Getopt::Long qw(GetOptions);
my ($server);
GetOptions(
'server|s=s' => \$server,
) or die "[ERROR] Invalid options passed to $0\n";
my $number_of_tests = 100000;
plan tests => 2 + $number_of_tests;
ok (1, "start");
foreach my $test_nr (0..$number_of_tests-1){
ok(1,"Test numbber: $test_nr in $server");
}
ok ($server eq 'server_1', "Finished");
done_testing;
print( "$0 Run Time: " . ( time - $^T ) . " second(s).\n");
现在我使用 HTML 报告运行测试:
# Define formatter
my $fmt = TAP::Formatter::HTML->new();
$fmt->output_file( "report.html" );
我得到以下结果:
ok 100002 - 完成
script.t 运行时间:34 秒。harness.pl 运行时间:42 秒。
通过:100002
失败:0
错误:0
完成脚本后 8 秒。
之后我尝试使用默认的控制台格式化程序:
# Define formatter
my $fmt = TAP::Formatter::Console->new({verbosity=>1});
结果:
ok 100002 - 完成
script.t 运行时间:34 秒。
ok
所有测试成功。
Files=1, Tests=100002, 34 wallclock secs (16.20 usr + 3.61 sys = 19.81 CPU)
结果:
PASSharness.pl 运行时间:34 秒。
通过:100002
失败:0
错误:0
所以这看起来相当不错,这让我认为问题出在创建一个非常大的 HTML 报告,在本例中将生成一个13,854 KB
HTML 文件。
所以我把这个简单的例子放到我的项目之外。并运行我的测试的简化版本,它会生成如下报告:
正如你所看到的,这不是大量的测试,只有 35 个左右的文件,
35 KB
我认为没有任何可能有很多计算问题的文件。
然后我查看具有相同结构的日志,在其中打印脚本的最后一行,我得到了这个时间差:
t/long-test.t 运行时间:117 秒。
# 看起来你没有通过 34 的 2 次测试。
通过:32
失败:2
错误:2
Harness.pl 运行时间:212 秒。
我又想了想,好吧,这个 HTML 库一定有问题。所以我全力以赴并删除 HTML 报告并仅使用控制台格式化程序:
# 在 t/mylongtest.t 第 237 行。t
/mylongtest.t 运行时间:128 秒。
# 看起来你没有通过 34 的 2 次测试。
可疑,测试返回 2 (wstat 512, 0x200)
失败 2/34 子测试测试总结报告
-------------------
mylongtest (Wstat: 512 测试: 34 失败: 2)
失败测试: 33-34
非零退出状态: 2
Files=1 , Tests=34, 215 wallclock secs (0.22 usr + 0.12 sys = 0.34 CPU)
结果: FAIL
Passed: 32
Failed: 2
Errors: 2
Harness.pl 运行时间: 216 秒。
然后我再次得到了从测试结束时的 128 秒到线束结束时的 216 秒的这种克雷差异。
我试图完全删除线束脚本,只使用证明,我得到了同样的结果
所以我的问题是。在 done_testing / end of a test 和报告测试工具的结果之间发生了什么,我能做些什么来改进它?
更新:我终于能够在一个最小的例子中重现这个问题,而且似乎问题不是 TAP,而是在脚本末尾使用垃圾收集器或类似的东西发生了什么。我创建了两个脚本,第一个delete_me.pl
:
use strict;
use JSON;
my $huge_json_string = '{';
foreach my $i (0..20000000){
$huge_json_string .= '"key_'.$i.'": "some_value'.$i.'",';
}
$huge_json_string =~ s/,$/}/;#
print "String generated\n";
my $all_to_ram = decode_json($huge_json_string);
print "Hash generated\n";
print( "$0 Run Time: " . ( time - $^T ) . " second(s).\n");
现在我从其他脚本中调用它delete_me_caller.pl
:
use strict;
system("perl delete_me.pl");
print( "$0 Run Time: " . ( time - $^T ) . " second(s).\n");
这是惊喜:
字符串生成
哈希生成
delete_me.pl 运行时间:20 秒。
delete_me_caller.pl 运行时间:42 秒。
因此,结束脚本比生成数据并将其加载到内存需要更多的时间。 注意:对于这个脚本,我使用的是带有 32GB ram 和 i7 8650 U 的个人计算机,因此这可能需要更长的时间,而 RAM 或电源更少。