line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Dumbbench::Instance; |
2
|
3
|
|
|
3
|
|
16
|
use strict; |
|
3
|
|
|
|
|
21
|
|
|
3
|
|
|
|
|
76
|
|
3
|
3
|
|
|
3
|
|
12
|
use warnings; |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
63
|
|
4
|
3
|
|
|
3
|
|
12
|
use Carp (); |
|
3
|
|
|
|
|
4
|
|
|
3
|
|
|
|
|
70
|
|
5
|
3
|
|
|
3
|
|
14
|
use List::Util qw/min max/; |
|
3
|
|
|
|
|
3
|
|
|
3
|
|
|
|
|
473
|
|
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
require Dumbbench::Instance::Cmd; |
8
|
|
|
|
|
|
|
require Dumbbench::Instance::PerlEval; |
9
|
|
|
|
|
|
|
require Dumbbench::Instance::PerlSub; |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
use Class::XSAccessor { |
12
|
3
|
|
|
|
|
29
|
constructor => 'new', |
13
|
|
|
|
|
|
|
accessors => [qw( |
14
|
|
|
|
|
|
|
name |
15
|
|
|
|
|
|
|
dry_result |
16
|
|
|
|
|
|
|
result |
17
|
|
|
|
|
|
|
)], |
18
|
|
|
|
|
|
|
getters => [qw(timings dry_timings)], |
19
|
3
|
|
|
3
|
|
17
|
}; |
|
3
|
|
|
|
|
5
|
|
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
=encoding utf8 |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
=head1 NAME |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
Dumbbench::Instance - A benchmark instance within a Dumbbench |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
=head1 SYNOPSIS |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
use Dumbbench; |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
my $bench = Dumbbench->new( |
32
|
|
|
|
|
|
|
target_rel_precision => 0.005, # seek ~0.5% |
33
|
|
|
|
|
|
|
initial_runs => 20, # the higher the more reliable |
34
|
|
|
|
|
|
|
); |
35
|
|
|
|
|
|
|
$bench->add_instances( |
36
|
|
|
|
|
|
|
Dumbbench::Instance::Cmd->new(name => 'mauve', command => [qw(perl -e 'something')]), |
37
|
|
|
|
|
|
|
# ... more things to benchmark ... |
38
|
|
|
|
|
|
|
); |
39
|
|
|
|
|
|
|
$bench->run(); |
40
|
|
|
|
|
|
|
# ... |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
=head1 DESCRIPTION |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
This module is the base class for all benchmark instances. For example, |
45
|
|
|
|
|
|
|
for benchmarking external commands, you should use L. |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
The synopsis shows how instances of subclasses of |
48
|
|
|
|
|
|
|
C are added to a benchmark run. |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
=head1 METHODS |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
=head2 new |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
Constructor that takes named arguments. In this base class, |
55
|
|
|
|
|
|
|
the only recognized argument is an instance C. |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
=head2 timings |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
Returns the internal array reference of timings or undef if |
60
|
|
|
|
|
|
|
there aren't any. |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
=head2 dry_timings |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
Same as C but for dry-run timings. |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
=head2 name |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
Returns the name of the instance. |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
=head2 clone |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
Returns a full (deep) copy of the object. May have to be |
73
|
|
|
|
|
|
|
augmented in subclasses. |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
=cut |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
sub clone { |
78
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
79
|
0
|
|
|
|
|
0
|
my $clone = bless({%$self} => ref($self)); |
80
|
|
|
|
|
|
|
|
81
|
0
|
0
|
|
|
|
0
|
if (defined $clone->dry_result) { |
82
|
0
|
|
|
|
|
0
|
$clone->dry_result($clone->dry_result->new); |
83
|
|
|
|
|
|
|
} |
84
|
0
|
0
|
|
|
|
0
|
if (defined $clone->result) { |
85
|
0
|
|
|
|
|
0
|
$clone->result($clone->result->new); |
86
|
|
|
|
|
|
|
} |
87
|
0
|
|
|
|
|
0
|
return $clone; |
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
=head2 single_run |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
Needs to be implemented in subclasses: |
93
|
|
|
|
|
|
|
A method that performs a single benchmark run and returns the |
94
|
|
|
|
|
|
|
duration of the run in seconds. |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
=cut |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
sub single_run { |
99
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
100
|
0
|
|
|
|
|
0
|
Carp::croak("Can't single_run Dumbbench::Instance: Choose a subclass that implements running."); |
101
|
|
|
|
|
|
|
} |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
=head2 single_dry_run |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
Needs to be implemented in subclasses: |
106
|
|
|
|
|
|
|
A method that performs a single dry-run and returns the |
107
|
|
|
|
|
|
|
duration of the run in seconds. |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
=cut |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
sub single_dry_run { |
112
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
113
|
0
|
|
|
|
|
0
|
Carp::croak("Can't single_dry_run Dumbbench::Instance: Choose a subclass that implements dry-running."); |
114
|
|
|
|
|
|
|
} |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
=head2 timings_as_histogram |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
If the optional L module is installed, |
119
|
|
|
|
|
|
|
C can generate histograms of the timing distributions. |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
This method creates such a histogram object (of type C) |
122
|
|
|
|
|
|
|
and returns it. If C is not available, this method |
123
|
|
|
|
|
|
|
returns the empty list. |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
=cut |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
sub timings_as_histogram { |
128
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
129
|
0
|
|
0
|
|
|
0
|
my $timings = $self->timings||[]; |
130
|
0
|
|
|
|
|
0
|
return $self->_timings_as_histogram($timings); |
131
|
|
|
|
|
|
|
} |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
=head2 dry_timings_as_histogram |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
Same as C, but for the timings |
136
|
|
|
|
|
|
|
from dry-runs. |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
=cut |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
sub dry_timings_as_histogram { |
141
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
142
|
0
|
|
0
|
|
|
0
|
my $timings = $self->dry_timings||[]; |
143
|
0
|
|
|
|
|
0
|
return $self->_timings_as_histogram($timings, 'dry'); |
144
|
|
|
|
|
|
|
} |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
sub _timings_as_histogram { |
147
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
148
|
0
|
|
|
|
|
0
|
eval "require SOOT;"; |
149
|
0
|
0
|
|
|
|
0
|
return() if $@; |
150
|
|
|
|
|
|
|
|
151
|
0
|
|
|
|
|
0
|
my $timings = shift; |
152
|
0
|
|
|
|
|
0
|
my $is_dry = shift; |
153
|
0
|
0
|
|
|
|
0
|
my $min = (@$timings ? min(@$timings)*0.95 : 0); |
154
|
0
|
0
|
|
|
|
0
|
my $max = (@$timings ? max(@$timings)*1.05 : 1); |
155
|
0
|
|
|
|
|
0
|
my $n = max(@$timings/8, 100); |
156
|
0
|
0
|
|
|
|
0
|
my $prefix = $is_dry ? 'dry_' : ''; |
157
|
0
|
0
|
|
|
|
0
|
my $name = defined($self->name) ? "${prefix}timings_" . $self->name : "${prefix}timings"; |
158
|
0
|
|
|
|
|
0
|
my $hist = TH1D->new($name, "distribution of benchmark ${prefix}timings", int($n), $min, $max); |
159
|
0
|
|
|
|
|
0
|
$hist->GetXaxis()->SetTitle("run time [s]"); |
160
|
0
|
|
|
|
|
0
|
$hist->GetYaxis()->SetTitle("#"); |
161
|
0
|
|
|
|
|
0
|
$hist->Fill($_) for @$timings; |
162
|
0
|
|
|
|
|
0
|
return $hist; |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
sub _name_prefix { |
166
|
8
|
|
|
8
|
|
32
|
my $name = $_[0]->name; |
167
|
8
|
50
|
|
|
|
39
|
return defined($name) ? "$name: " : ''; |
168
|
|
|
|
|
|
|
} |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
1; |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
__END__ |