line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Benchmark::DKbench; |
2
|
|
|
|
|
|
|
|
3
|
3
|
|
|
3
|
|
587609
|
use strict; |
|
3
|
|
|
|
|
18
|
|
|
3
|
|
|
|
|
88
|
|
4
|
3
|
|
|
3
|
|
15
|
use warnings; |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
87
|
|
5
|
|
|
|
|
|
|
|
6
|
3
|
|
|
3
|
|
14
|
use Config; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
130
|
|
7
|
3
|
|
|
3
|
|
1599
|
use Digest; |
|
3
|
|
|
|
|
1705
|
|
|
3
|
|
|
|
|
98
|
|
8
|
3
|
|
|
3
|
|
20
|
use Digest::MD5 qw(md5_hex); |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
162
|
|
9
|
3
|
|
|
3
|
|
633
|
use Encode; |
|
3
|
|
|
|
|
16139
|
|
|
3
|
|
|
|
|
244
|
|
10
|
3
|
|
|
3
|
|
1494
|
use File::Spec::Functions; |
|
3
|
|
|
|
|
2551
|
|
|
3
|
|
|
|
|
224
|
|
11
|
3
|
|
|
3
|
|
21
|
use List::Util qw(min max sum); |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
180
|
|
12
|
3
|
|
|
3
|
|
19
|
use Time::HiRes qw(CLOCK_MONOTONIC); |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
26
|
|
13
|
3
|
|
|
3
|
|
2471
|
use Time::Piece; |
|
3
|
|
|
|
|
33372
|
|
|
3
|
|
|
|
|
12
|
|
14
|
|
|
|
|
|
|
|
15
|
3
|
|
|
3
|
|
1774
|
use Astro::Coord::Constellations 'constellation_for_eq'; |
|
3
|
|
|
|
|
58301
|
|
|
3
|
|
|
|
|
197
|
|
16
|
3
|
|
|
3
|
|
24
|
use Astro::Coord::Precession 'precess'; |
|
3
|
|
|
|
|
9
|
|
|
3
|
|
|
|
|
134
|
|
17
|
3
|
|
|
3
|
|
1948
|
use Crypt::JWT qw(encode_jwt decode_jwt); |
|
3
|
|
|
|
|
168541
|
|
|
3
|
|
|
|
|
221
|
|
18
|
3
|
|
|
3
|
|
1590
|
use CSS::Inliner; |
|
3
|
|
|
|
|
437141
|
|
|
3
|
|
|
|
|
116
|
|
19
|
3
|
|
|
3
|
|
2720
|
use DateTime; |
|
3
|
|
|
|
|
1609876
|
|
|
3
|
|
|
|
|
167
|
|
20
|
3
|
|
|
3
|
|
4980
|
use DBI; |
|
3
|
|
|
|
|
55353
|
|
|
3
|
|
|
|
|
219
|
|
21
|
3
|
|
|
3
|
|
29
|
use File::ShareDir 'dist_dir'; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
157
|
|
22
|
3
|
|
|
3
|
|
1540
|
use HTML::FormatText; |
|
3
|
|
|
|
|
21817
|
|
|
3
|
|
|
|
|
98
|
|
23
|
3
|
|
|
3
|
|
22
|
use HTML::TreeBuilder; |
|
3
|
|
|
|
|
32
|
|
|
3
|
|
|
|
|
35
|
|
24
|
3
|
|
|
3
|
|
2763
|
use Imager; |
|
3
|
|
|
|
|
153666
|
|
|
3
|
|
|
|
|
35
|
|
25
|
3
|
|
|
3
|
|
1524
|
use Imager::Filter::Mandelbrot; |
|
3
|
|
|
|
|
1828
|
|
|
3
|
|
|
|
|
104
|
|
26
|
3
|
|
|
3
|
|
1688
|
use Image::PHash; |
|
3
|
|
|
|
|
19082
|
|
|
3
|
|
|
|
|
152
|
|
27
|
3
|
|
|
3
|
|
21
|
use JSON::XS; |
|
3
|
|
|
|
|
9
|
|
|
3
|
|
|
|
|
197
|
|
28
|
3
|
|
|
3
|
|
18
|
use Math::DCT ':all'; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
421
|
|
29
|
3
|
|
|
3
|
|
3255
|
use Math::MatrixReal; |
|
3
|
|
|
|
|
89279
|
|
|
3
|
|
|
|
|
219
|
|
30
|
3
|
|
|
3
|
|
1758
|
use MCE::Loop; |
|
3
|
|
|
|
|
151230
|
|
|
3
|
|
|
|
|
54
|
|
31
|
3
|
|
|
3
|
|
3419
|
use SQL::Abstract::Classic; |
|
3
|
|
|
|
|
36309
|
|
|
3
|
|
|
|
|
109
|
|
32
|
3
|
|
|
3
|
|
1544
|
use SQL::Inserter; |
|
3
|
|
|
|
|
6470
|
|
|
3
|
|
|
|
|
147
|
|
33
|
3
|
|
|
3
|
|
1453
|
use System::CPU; |
|
3
|
|
|
|
|
8374
|
|
|
3
|
|
|
|
|
110
|
|
34
|
3
|
|
|
3
|
|
1376
|
use System::Info; |
|
3
|
|
|
|
|
56323
|
|
|
3
|
|
|
|
|
226
|
|
35
|
3
|
|
|
3
|
|
1432
|
use Text::Levenshtein::Damerau::XS; |
|
3
|
|
|
|
|
1881
|
|
|
3
|
|
|
|
|
152
|
|
36
|
3
|
|
|
3
|
|
1307
|
use Text::Levenshtein::XS; |
|
3
|
|
|
|
|
1841
|
|
|
3
|
|
|
|
|
156
|
|
37
|
|
|
|
|
|
|
|
38
|
3
|
|
|
3
|
|
20
|
use Exporter 'import'; |
|
3
|
|
|
|
|
7
|
|
|
3
|
|
|
|
|
27509
|
|
39
|
|
|
|
|
|
|
our @EXPORT = qw(system_identity suite_run calc_scalability); |
40
|
|
|
|
|
|
|
our $datadir = dist_dir("Benchmark-DKbench"); |
41
|
|
|
|
|
|
|
my $mono_clock = $^O !~ /win/i || $Time::HiRes::VERSION >= 1.9764; |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
our $VERSION = '2.4'; |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
=head1 NAME |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
Benchmark::DKbench - Perl CPU Benchmark |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
=head1 SYNOPSIS |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
# Run the suite single-threaded and then multi-threaded on multi-core systems |
52
|
|
|
|
|
|
|
# Will print scores for the two runs and multi/single thread scalability |
53
|
|
|
|
|
|
|
dkbench |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
# A dual-thread "quick" run (with times instead of scores) |
56
|
|
|
|
|
|
|
dkbench -j 2 -q |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
# If BioPerl is installed, enable the BioPerl benchmarks by downloading Genbank data |
59
|
|
|
|
|
|
|
dkbench --setup |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
# Force install the reference versions of all CPAN modules |
62
|
|
|
|
|
|
|
setup_dkbench --force |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
=head1 DESCRIPTION |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
A Perl benchmark suite for general compute, created to evaluate the comparative |
67
|
|
|
|
|
|
|
performance of systems when running computationally intensive Perl (both pure Perl |
68
|
|
|
|
|
|
|
and C/XS) workloads. It is a good overall indicator for generic CPU performance in |
69
|
|
|
|
|
|
|
real-world scenarios. It runs single and multi-threaded (able to scale to hundreds |
70
|
|
|
|
|
|
|
of CPUs) and can be fully customized to run the benchmarks that better suit your own |
71
|
|
|
|
|
|
|
scenario. |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
=head1 INSTALLATION |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
See the L</"setup_dkbench"> script below for more on the installation of a couple |
76
|
|
|
|
|
|
|
of optional benchmarks and standardizing your benchmarking environment, otherwise |
77
|
|
|
|
|
|
|
here are some general guidelines for verious systems. |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
=head2 Linux / WSL etc |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
The only non-CPAN software required to install/run the suite is a build environment |
82
|
|
|
|
|
|
|
for the C/XS modules (C compiler, make etc.) and Perl. On the most popular Linux |
83
|
|
|
|
|
|
|
package managers you can easily set up such an environment (as root or with sudo): |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
# Debian/Ubuntu etc |
86
|
|
|
|
|
|
|
apt-get update |
87
|
|
|
|
|
|
|
apt-get install build-essential perl cpanminus |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
# CentOS/Red Hat |
90
|
|
|
|
|
|
|
yum update |
91
|
|
|
|
|
|
|
yum install gcc make patch perl perl-App-cpanminus |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
After that, you can use L<App::cpanminus> to install the benchmark suite (as |
94
|
|
|
|
|
|
|
root/sudo is the easiest, will install for all users): |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
cpanm -n Benchmark::DKbench |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
=head2 Solaris |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
You will need to install the Oracle Solaris Studio development package to have a |
101
|
|
|
|
|
|
|
compiler environment, and to add its C<bin> directory to your PATH, before installing |
102
|
|
|
|
|
|
|
the benchmark suite. |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
=head2 Strawberry Perl |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
If you are on Windows, you should be using the Windows Subsystem for Linux (WSL) |
107
|
|
|
|
|
|
|
for running Perl or, if you can't (e.g. old Windows verions), cygwin instead. |
108
|
|
|
|
|
|
|
The suite should still work on Strawberry Perl, as long as you don't try to run |
109
|
|
|
|
|
|
|
tests when installing (some dependencies will not pass them). The simplest way is |
110
|
|
|
|
|
|
|
with L<App::cpanminus> (most Strawberry Perl verions have it installed): |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
cpanm -n Benchmark::DKbench |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
otherwise with the base CPAN shell: |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
perl -MCPAN -e shell |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
> notest install Benchmark::DKbench |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
and then note that the scripts get the batch extension appended, so C<dkbench.bat> |
121
|
|
|
|
|
|
|
runs the suite (and C<setup_dkbench.bat> can assist with module versions, optional |
122
|
|
|
|
|
|
|
benchmarks etc.). |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
Be aware that Strawberry Perl is slower, on my test system I get almost 50% slower |
125
|
|
|
|
|
|
|
performance than WSL and 30% slower than cygwin. |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
=head1 SCRIPTS |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
You will most likely only ever need the main script C<dkbench> which launches the |
130
|
|
|
|
|
|
|
suite, although C<setup_dkbench> can help with setup or standardizing/normalizing your |
131
|
|
|
|
|
|
|
benchmarking environment. |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
=head2 C<dkbench> |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
The main script that runs the DKbench benchmark suite. If L<BioPerl> is installed, |
136
|
|
|
|
|
|
|
you may want to start with C<dkbench --setup>. But beyond that, there are many |
137
|
|
|
|
|
|
|
options to control number of threads, iterations, which benchmarks to run etc: |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
dkbench [options] |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
Options: |
142
|
|
|
|
|
|
|
--threads <i>, -j <i> : Number of benchmark threads (default is 1). |
143
|
|
|
|
|
|
|
--multi, -m : Multi-threaded using all your CPU cores/threads. |
144
|
|
|
|
|
|
|
--max_threads <i> : Override the cpu detection to specify max cpu threads. |
145
|
|
|
|
|
|
|
--iter <i>, -i <i> : Number of suite iterations (with min/max/avg at the end). |
146
|
|
|
|
|
|
|
--stdev : Show relative standard deviation (for iter > 1). |
147
|
|
|
|
|
|
|
--include <regex> : Run only benchmarks that match regex. |
148
|
|
|
|
|
|
|
--exclude <regex> : Do not run benchmarks that match regex. |
149
|
|
|
|
|
|
|
--time, -t : Report time (sec) instead of score. |
150
|
|
|
|
|
|
|
--quick, -q : Quick benchmark run (implies -t). |
151
|
|
|
|
|
|
|
--no_mce : Do not run under MCE::Loop (implies -j 1). |
152
|
|
|
|
|
|
|
--scale <i>, -s <i> : Scale the bench workload by x times (incompatible with -q). |
153
|
|
|
|
|
|
|
--skip_bio : Skip BioPerl benchmarks. |
154
|
|
|
|
|
|
|
--skip_prove : Skip Moose prove benchmark. |
155
|
|
|
|
|
|
|
--time_piece : Run optional Time::Piece benchmark (see benchmark details). |
156
|
|
|
|
|
|
|
--bio_codons : Run optional BioPerl Codons benchmark (does not scale well). |
157
|
|
|
|
|
|
|
--sleep <i> : Sleep for <i> secs after each benchmark. |
158
|
|
|
|
|
|
|
--setup : Download the Genbank data to enable the BioPerl tests. |
159
|
|
|
|
|
|
|
--datapath <path> : Override the path where the expected benchmark data is found. |
160
|
|
|
|
|
|
|
--ver <num> : Skip benchmarks added after the specified version. |
161
|
|
|
|
|
|
|
--help -h : Show basic help and exit. |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
The default run (no options) will run all the benchmarks both single-threaded and |
164
|
|
|
|
|
|
|
multi-threaded (using all detected CPU cores/hyperthreads) and show you scores and |
165
|
|
|
|
|
|
|
multi vs single threaded scalability. |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
The scores are calibrated such that a reference CPU (Intel Xeon Platinum 8481C - |
168
|
|
|
|
|
|
|
Sapphire Rapids) would achieve a score of 1000 in a single-core benchmark run using |
169
|
|
|
|
|
|
|
the default software configuration (Linux/Perl 5.36.0 built with multiplicity and |
170
|
|
|
|
|
|
|
threads, with reference CPAN module versions). Perl built without thread support and |
171
|
|
|
|
|
|
|
multi(plicity) will be a bit faster (usually in the order of ~3-4%), while older Perl |
172
|
|
|
|
|
|
|
versions will most likely be slower. Different CPAN module versions will also impact |
173
|
|
|
|
|
|
|
scores, using C<setup_dkbench> is a way to ensure a reference environment for more |
174
|
|
|
|
|
|
|
meaningful hardware comparisons. |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
The multi-thread scalability calculated by the suite should approach 100% if each |
177
|
|
|
|
|
|
|
thread runs on a full core (i.e. no SMT), and the core can maintain the clock speed |
178
|
|
|
|
|
|
|
it had on the single-thread runs. Note that the overall scalability is an average |
179
|
|
|
|
|
|
|
of the benchmarks that drops non-scaling outliers (over 2*stdev less than the mean). |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
If you want to reduce the effects of thermal throttling, which will lower the speed |
182
|
|
|
|
|
|
|
of (mainly multi-threaded) benchmarks as the CPU temperature increases, the C<sleep> |
183
|
|
|
|
|
|
|
option can help by adding cooldown time between each benchmark. |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
The suite will report a Pass/Fail per benchmark. A failure may be caused if you have |
186
|
|
|
|
|
|
|
different CPAN module version installed - this is normal, and you will be warned. |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
L<MCE::Loop> is used to run on the desired number of parallel threads, with minimal |
189
|
|
|
|
|
|
|
overhead., There is an option to disable it, which forces a single-thread run. |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
=head2 C<setup_dkbench> |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
Simple installer to check/get the reference versions of CPAN modules and download |
194
|
|
|
|
|
|
|
the Genbank data file required for the BioPerl benchmarks of the DKbench suite. |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
It assumes that you have some software already installed (see L</"INSTALLATION"> above), |
197
|
|
|
|
|
|
|
try C<setup_dkbench --help> will give you more details. |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
setup_dkbench [--force --sudo --test --data=s --help] |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
Options: |
202
|
|
|
|
|
|
|
--sudo : Will use sudo for cpanm calls. |
203
|
|
|
|
|
|
|
--force : Will install reference CPAN module versions and re-download the genbank data. |
204
|
|
|
|
|
|
|
--test : Will run the test suites for the CPAN module (default behaviour is to skip). |
205
|
|
|
|
|
|
|
--data=s : Data dir path to copy files from. Should not need if you installed DKbench. |
206
|
|
|
|
|
|
|
--help : Print this help text and exit. |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
Running it without any options will fetch the data for the BioPerl tests (similar to |
209
|
|
|
|
|
|
|
C<dkbench --setup>) and use C<cpanm> to install any missing libraries. |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
Using it with C<--force> will install the reference CPAN module versions, including |
212
|
|
|
|
|
|
|
BioPerl which is not a requirement for DKbench, but enables the BioPerl benchmarks. |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
The reference Perl and CPAN versions are suggested if you want a fair comparison |
215
|
|
|
|
|
|
|
between systems and also for the benchmark Pass/Fail results to be reliable. |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
=head1 BENCHMARKS |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
The suite consists of 21 benchmarks, 19 will run by default. However, the |
220
|
|
|
|
|
|
|
C<BioPerl Monomers> requires the optional L<BioPerl> to be installed and Genbank |
221
|
|
|
|
|
|
|
data to be downloaded (C<dkbench --setup> can do the latter), so you will only |
222
|
|
|
|
|
|
|
see 18 benchmarks running just after a standard install. Because the overall score |
223
|
|
|
|
|
|
|
is an average, it is generally unaffected by adding or skipping a benchmark or two. |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
The optional benchmarks are enabled with the C<--time_piece> and C<--bio_codons> |
226
|
|
|
|
|
|
|
options. |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
=over 4 |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
=item * C<Astro> : Calculates precession between random epochs and finds the |
231
|
|
|
|
|
|
|
constellation for random equatorial coordinates using L<Astro::Coord::Precession> |
232
|
|
|
|
|
|
|
and L<Astro::Coord::Constellations> respectively. |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
=item * C<BioPerl Codons> : Counts codons on a sample bacterial sequence. Requires |
235
|
|
|
|
|
|
|
L<BioPerl> to be installed. |
236
|
|
|
|
|
|
|
This test does not scale well on multiple threads, so is disabled by default (use |
237
|
|
|
|
|
|
|
C<--bio_codons>) option. Requires data fetched using the C<--setup> option. |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
=item * C<BioPerl Monomers> : Counts monomers on 500 sample bacterial sequences using |
240
|
|
|
|
|
|
|
L<BioPerl> (which needs to be installed). Requires data fetched using the C<--setup> |
241
|
|
|
|
|
|
|
option. |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
=item * C<CSS::Inliner> : Inlines CSS on 2 sample wiki pages using L<CSS::Inliner>. |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
=item * C<Crypt::JWT> : Creates large JSON Web Tokens with RSA and EC crypto keys |
246
|
|
|
|
|
|
|
using L<Crypt::JWT>. |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
=item * C<DateTime> : Creates and manipulates L<DateTime> objects. |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
=item * C<DBI/SQL> : Creates a mock L<DBI> connection (using L<DBD::Mock>) and passes |
251
|
|
|
|
|
|
|
it insert/select statements using L<SQL::Inserter> and L<SQL::Abstract::Classic>. |
252
|
|
|
|
|
|
|
The latter is quite slow at creating the statements, but it is widely used. |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
=item * C<Digest> : Creates MD5, SH1 and SHA-512 digests of a large string. |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
=item * C<Encode> : Encodes/decodes large strings from/to UTF-8/16, cp-1252. |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
=item * C<HTML::FormatText> : Converts HTML to text for 2 sample wiki pages using |
259
|
|
|
|
|
|
|
L<HTML::FormatText>. |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
=item * C<Imager> : Loads a sample image and performs edits/manipulations with |
262
|
|
|
|
|
|
|
L<Imager>, including filters like gaussian, unsharp mask, mandelbrot. |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
=item * C<JSON::XS> : Encodes/decodes random data structures to/from JSON using |
265
|
|
|
|
|
|
|
L<JSON::XS>. |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
=item * C<Math::DCT> : Does 8x8, 18x18 and 32x32 DCT transforms with L<Math::DCT>. |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
=item * C<Math::MatrixReal> : Performs various manipulations on L<Math::MatrixReal> |
270
|
|
|
|
|
|
|
matrices. |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
=item * C<Moose> : Creates L<Moose> objects. |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
=item * C<Moose prove> : Runs 110 tests from the Moose 2.2201 test suite. The least |
275
|
|
|
|
|
|
|
CPU-intensive test (which is why there is the option C<--no_prove> to disable it), |
276
|
|
|
|
|
|
|
most of the time will be spent loading the interpreter and the Moose module for each |
277
|
|
|
|
|
|
|
test, which is behaviour representative of how a Perl test suite runs by default. |
278
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
=item * C<Primes> : Calculates all primes up to 7.5 million. Small number with |
280
|
|
|
|
|
|
|
repeat was chosen to keep low memory (this is a pure Perl function no Math libraries). |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
=item * C<Regex/Subst> : Concatenates 3 wiki pages into a byte string then matches |
283
|
|
|
|
|
|
|
3 typical regexes (for names, emails, URIs), replaces html tags with their contents |
284
|
|
|
|
|
|
|
(starting with the innermost) and does calls subst a few times. |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
=item * C<Regex/Subst utf8> : Exactly the same as C<Regex/Subst>, but reads into |
287
|
|
|
|
|
|
|
a utf8 string. Perl version can make a big difference, as Unicode behaviour has |
288
|
|
|
|
|
|
|
changed (old Perl versions are faster but less strict in general). |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
=item * C<Text::Levenshtein> : The edit distance for strings of various lengths (up |
291
|
|
|
|
|
|
|
to 2500) are calculated using L<Text::Levenshtein::XS> and L<Text::Levenshtein::Damerau::XS>. |
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
=item * C<Time::Piece> : Creates and manipulates/converts Time::Piece objects. It |
294
|
|
|
|
|
|
|
is disabled by default because it uses the OS time libraries, so it might skew results |
295
|
|
|
|
|
|
|
if you are trying to compare CPUs on different OS platforms. It can be enabled with |
296
|
|
|
|
|
|
|
the C<--time_piece> option. For MacOS specifically, it can only be enabled if C<--no_mce> |
297
|
|
|
|
|
|
|
is specified, as it runs extremely slow when forked. |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
=back |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
=head1 EXPORTED FUNCTIONS |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
You will normally not use the Benchmark::DKbench module itself, but here are the |
304
|
|
|
|
|
|
|
exported functions that the C<dkbench> script uses for reference: |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
=head2 C<system_identity> |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
my $cores = system_identity(); |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
Prints out software/hardware configuration and returns then number of cores detected. |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
=head2 C<suite_run> |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
my %stats = suite_run(\%options); |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
Runs the benchmark suite given the C<%options> and prints results. Returns a hash |
317
|
|
|
|
|
|
|
with run stats. |
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
The options accepted are the same as the C<dkbench> script (in their long form), |
320
|
|
|
|
|
|
|
except C<help>, C<setup> and C<max_threads> which are command-line only. |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
=head2 C<calc_scalability> |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
calc_scalability(\%options, \%stat_single, \%stat_multi); |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
Given the C<%stat_single> results of a single-threaded C<suite_run> and C<%stat_multi> |
327
|
|
|
|
|
|
|
results of a multi-threaded run, will calculate and print the multi-thread scalability. |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
=head1 NOTES |
330
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
The benchmark suite was created to compare the performance of various cloud offerings. |
332
|
|
|
|
|
|
|
You can see the L<original perl blog post|http://blogs.perl.org/users/dimitrios_kechagias/2022/03/cloud-provider-performance-comparison-gcp-aws-azure-perl.html> |
333
|
|
|
|
|
|
|
as well as the L<2023 follow-up|https://dev.to/dkechag/cloud-vm-performance-value-comparison-2023-perl-more-1kpp>. |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
The benchmarks for the first version were more tuned to what I would expect to run |
336
|
|
|
|
|
|
|
on the servers I was testing, in order to choose the optimal types for the company |
337
|
|
|
|
|
|
|
I was working for. The second version has expanded a bit over that, and is friendlier |
338
|
|
|
|
|
|
|
to use. |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
Althought this benchmark is in general a good indicator of general CPU performance |
341
|
|
|
|
|
|
|
and can be customized to your needs, no benchmark is as good as running your own |
342
|
|
|
|
|
|
|
actual workload. |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
=head2 SCORES |
345
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
Some sample DKbench score results from various systems for comparison (all on |
347
|
|
|
|
|
|
|
reference setup with Perl 5.36.0 thread-multi): |
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
CPU Cores/HT Single Multi Scalability |
350
|
|
|
|
|
|
|
Intel i7-4750HQ @ 2.0 (MacOS) 4/8 612 2332 46.9% |
351
|
|
|
|
|
|
|
AMD Ryzen 5 PRO 4650U @ 2.1 (WSL) 6/12 905 4444 40.6% |
352
|
|
|
|
|
|
|
Apple M1 Pro @ 3.2 (MacOS) 10/10 1283 10026 78.8% |
353
|
|
|
|
|
|
|
Apple M2 Pro @ 3.5 (MacOS) 12/12 1415 12394 73.1% |
354
|
|
|
|
|
|
|
Ampere Altra @ 3.0 (Linux) 48/48 708 32718 97.7% |
355
|
|
|
|
|
|
|
Intel Xeon Platinum 8481C @ 2.7 (Linux) 88/176 1000 86055 48.9% |
356
|
|
|
|
|
|
|
AMD EPYC Milan 7B13 @ 2.45 (Linux) 112/224 956 104536 49.3% |
357
|
|
|
|
|
|
|
AMD EPYC Genoa 9B14 @ 2.7 (Linux) 180/360 1197 221622 51.4% |
358
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
=head1 AUTHOR |
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
Dimitrios Kechagias, C<< <dkechag at cpan.org> >> |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
=head1 BUGS |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
Please report any bugs or feature requests either on L<GitHub|https://github.com/dkechag/Benchmark-DKbench> (preferred), or on RT (via the email |
366
|
|
|
|
|
|
|
C<bug-Benchmark-DKbench at rt.cpan.org> or L<web interface|https://rt.cpan.org/NoAuth/ReportBug.html?Queue=Benchmark-DKbench>). |
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
I will be notified, and then you'll automatically be notified of progress on your bug as I make changes. |
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
=head1 GIT |
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
L<https://github.com/dkechag/Benchmark-DKbench> |
373
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
=head1 LICENSE AND COPYRIGHT |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
This software is copyright (c) 2021-2023 by Dimitrios Kechagias. |
377
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
This is free software; you can redistribute it and/or modify it under |
379
|
|
|
|
|
|
|
the same terms as the Perl 5 programming language system itself. |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
=cut |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
sub benchmark_list { |
384
|
|
|
|
|
|
|
return { # idx : 0 = result, 1 = ref time, 2 = func, 3 = quick test, 4 = normal test, 5 = ver |
385
|
12
|
|
|
12
|
0
|
570
|
'Astro' => ['e71c7ae08f16fe26aea7cfdb72785873', 5.674, \&bench_astro, 20000, 80000], |
386
|
|
|
|
|
|
|
'BioPerl Codons' => ['97c443c099886ca60e99f7ab9df689b5', 8.752, \&bench_bioperl_codons, 3, 5, 1], |
387
|
|
|
|
|
|
|
'BioPerl Monomers' => ['d29ed0a5c205c803c112be1338d1f060', 5.241, \&bench_bioperl_mono, 6, 20], |
388
|
|
|
|
|
|
|
'Crypt::JWT' => ['d41d8cd98f00b204e9800998ecf8427e', 6.451, \&bench_jwt, 250, 900], |
389
|
|
|
|
|
|
|
'CSS::Inliner' => ['82c1b6de9ca0500a48f8a8df0998df3c', 4.603, \&bench_css, 2, 5], |
390
|
|
|
|
|
|
|
'DBI/SQL' => ['2b8252daad9568a5b39038c696df4be3', 5.700, \&bench_dbi, 5000, 15000, 2.1], |
391
|
|
|
|
|
|
|
'DateTime' => ['b08d2eeb994083b7422f6c9d86fed2c6', 6.198, \&bench_datetime, 5000, 15000], |
392
|
|
|
|
|
|
|
'Digest' => ['4b69f6cf0f53cbf6c3444f2f767dd21d', 4.513, \&bench_digest, 50, 250], |
393
|
|
|
|
|
|
|
'Encode' => ['PASS 1025', 5.725, \&bench_encode, 40, 120], |
394
|
|
|
|
|
|
|
'HTML::FormatText' => ['8c2589f0a5276252805e11301fc2ab56', 4.756, \&bench_formattext, 4, 10], |
395
|
|
|
|
|
|
|
'Imager' => ['8829cb3703e884054eb025496f336c63', 6.792, \&bench_imager, 4, 16], |
396
|
|
|
|
|
|
|
'JSON::XS' => ['PASS', 5.388, \&bench_json, 600, 2200], |
397
|
|
|
|
|
|
|
'Math::DCT' => ['766e3bfd7a2276f452bb3d1bd21939bc', 7.147, \&bench_dct, 25000, 100_000], |
398
|
|
|
|
|
|
|
'Math::MatrixReal' => ['4606231b1309fb21ae1223fa0043fd76', 4.293, \&bench_matrixreal, 200, 650], |
399
|
|
|
|
|
|
|
'Moose' => ['d1cb92c513f6378506dfa11f694cffac', 4.968, \&bench_moose, 10_000, 30_000], |
400
|
|
|
|
|
|
|
'Moose prove' => ['PASS', 7.974, \&bench_moose_prv, 0.5, 1], |
401
|
|
|
|
|
|
|
'Primes' => ['4266f70a7a9efb3484cf5d98eba32244', 3.680, \&bench_primes_m, 2, 5], |
402
|
|
|
|
|
|
|
'Regex/Subst' => ['30ce365b25f3d597578b3bdb14aa3f57', 4.652, \&bench_regex_asc, 8, 24], |
403
|
|
|
|
|
|
|
'Regex/Subst utf8' => ['857eb4e63a4d174ca4a16fe678f7626f', 5.703, \&bench_regex_utf8, 3, 10], |
404
|
|
|
|
|
|
|
'Text::Levenshtein' => ['2948a300ed9131fa0ce82bb5eabb8ded', 5.539, \&bench_textlevenshtein, 7, 25, 2.1], |
405
|
|
|
|
|
|
|
'Time::Piece' => ['2d4b149fe7f873a27109fc376d69211b', 5.907, \&bench_timepiece, 75_000, 275_000], |
406
|
|
|
|
|
|
|
}; |
407
|
|
|
|
|
|
|
} |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
sub system_identity { |
410
|
1
|
|
|
1
|
1
|
1401
|
my ($physical, $cores, $ncpu) = System::CPU::get_cpu; |
411
|
1
|
|
50
|
|
|
2304
|
$ncpu ||= 1; |
412
|
1
|
50
|
|
|
|
5
|
local $^O = 'linux' if $^O =~ /android/; |
413
|
1
|
|
|
|
|
10
|
my $info = System::Info->sysinfo_hash; |
414
|
1
|
|
0
|
|
|
15575
|
my $osn = $info->{distro} || $info->{os} || $^O; |
415
|
1
|
|
50
|
|
|
13
|
my $model = System::CPU::get_name || ''; |
416
|
1
|
|
50
|
|
|
2275
|
my $arch = System::CPU::get_arch || ''; |
417
|
1
|
50
|
|
|
|
6560
|
$arch = " ($arch)" if $arch; |
418
|
1
|
|
|
|
|
28
|
print "--------------- Software ---------------\nDKbench v$VERSION\n"; |
419
|
|
|
|
|
|
|
printf "Perl $^V (%sthreads, %smulti)\n", |
420
|
|
|
|
|
|
|
$Config{usethreads} ? '' : 'no ', |
421
|
1
|
50
|
|
|
|
301
|
$Config{usemultiplicity} ? '' : 'no ',; |
|
|
50
|
|
|
|
|
|
422
|
1
|
|
|
|
|
16
|
print "OS: $osn\n--------------- Hardware ---------------\n"; |
423
|
1
|
|
|
|
|
14
|
print "CPU type: $model$arch\n"; |
424
|
1
|
|
|
|
|
9
|
print "CPUs: $ncpu"; |
425
|
1
|
|
|
|
|
4
|
my @extra; |
426
|
1
|
50
|
33
|
|
|
36
|
push @extra, "$physical Processors" if $physical && $physical > 1; |
427
|
1
|
50
|
|
|
|
25
|
push @extra, "$cores Cores" if $cores; |
428
|
1
|
50
|
33
|
|
|
17
|
push @extra, "$ncpu Threads" if $cores && $cores != $ncpu; |
429
|
1
|
50
|
|
|
|
17
|
print " (".join(', ', @extra).")" if @extra; |
430
|
1
|
|
|
|
|
21
|
print "\n".("-"x40)."\n"; |
431
|
|
|
|
|
|
|
|
432
|
1
|
|
|
|
|
55
|
return $ncpu; |
433
|
|
|
|
|
|
|
}; |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
sub suite_run { |
436
|
6
|
|
|
6
|
1
|
33864
|
my $opt = shift; |
437
|
6
|
100
|
|
|
|
45
|
$datadir = $opt->{datapath} if $opt->{datapath}; |
438
|
6
|
|
100
|
|
|
104
|
$opt->{threads} //= 1; |
439
|
6
|
|
100
|
|
|
58
|
$opt->{scale} //= 1; |
440
|
6
|
100
|
|
|
|
40
|
$opt->{f} = $opt->{time} ? '%.3f' : '%5.0f'; |
441
|
6
|
|
|
|
|
35
|
my %stats = (threads => $opt->{threads}); |
442
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
MCE::Loop::init { |
444
|
|
|
|
|
|
|
max_workers => $opt->{threads}, |
445
|
|
|
|
|
|
|
chunk_size => 1, |
446
|
6
|
100
|
|
|
|
55
|
} unless $opt->{no_mce}; |
447
|
|
|
|
|
|
|
|
448
|
6
|
|
|
|
|
91
|
foreach (1..$opt->{iter}) { |
449
|
8
|
100
|
|
|
|
188
|
print "Iteration $_ of $opt->{iter}...\n" if $opt->{iter} > 1; |
450
|
8
|
|
|
|
|
56
|
run_iteration($opt, \%stats); |
451
|
|
|
|
|
|
|
} |
452
|
|
|
|
|
|
|
|
453
|
5
|
100
|
|
|
|
44
|
total_stats($opt, \%stats) if $opt->{iter} > 1; |
454
|
|
|
|
|
|
|
|
455
|
5
|
|
|
|
|
760
|
return %stats; |
456
|
|
|
|
|
|
|
} |
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
sub calc_scalability { |
459
|
2
|
|
|
2
|
1
|
9920
|
my ($opt, $stats1, $stats2) = @_; |
460
|
2
|
|
|
|
|
36
|
my $benchmarks = benchmark_list(); |
461
|
2
|
|
|
|
|
18
|
my $threads = $stats2->{threads}/$stats1->{threads}; |
462
|
2
|
100
|
|
|
|
32
|
my $display = $opt->{time} ? 'times' : 'scores'; |
463
|
2
|
100
|
|
|
|
32
|
$opt->{f} = $opt->{time} ? '%.3f' : '%5.0f'; |
464
|
2
|
|
|
|
|
19
|
my (@perf, @scal); |
465
|
2
|
|
|
|
|
25
|
print "Multi thread Scalability:\n".pad_to("Benchmark",24).pad_to("Multi perf xSingle",24).pad_to("Multi scalability %",24); |
466
|
2
|
|
|
|
|
131
|
print "\n"; |
467
|
2
|
|
|
|
|
21
|
my $cnt; |
468
|
2
|
|
|
|
|
53
|
foreach my $bench (sort keys %$benchmarks) { |
469
|
42
|
100
|
100
|
|
|
277
|
next unless $stats1->{$bench}->{times} && $stats2->{$bench}->{times}; |
470
|
2
|
|
|
|
|
16
|
$cnt++; |
471
|
2
|
|
|
|
|
18
|
my @res1 = min_max_avg($stats1->{$bench}->{times}); |
472
|
2
|
|
|
|
|
21
|
my @res2 = min_max_avg($stats2->{$bench}->{times}); |
473
|
2
|
50
|
|
|
|
26
|
push @perf, $res1[2]/$res2[2]*$threads if $res2[2]; |
474
|
2
|
50
|
|
|
|
30
|
push @scal, $res1[2]/$res2[2]*100 if $res2[2]; |
475
|
2
|
|
|
|
|
29
|
print pad_to("$bench:",24).pad_to(sprintf("%.2f",$perf[-1]),24).pad_to(sprintf("%2.0f",$scal[-1]),24)."\n"; |
476
|
|
|
|
|
|
|
} |
477
|
2
|
|
|
|
|
130
|
print (("-"x40)."\n"); |
478
|
2
|
|
|
|
|
56
|
my $avg1 = min_max_avg($stats1->{total}->{$display}); |
479
|
2
|
|
|
|
|
21
|
my $avg2 = min_max_avg($stats2->{total}->{$display}); |
480
|
2
|
|
|
|
|
79
|
print "DKbench summary ($cnt benchmark"; |
481
|
2
|
50
|
|
|
|
25
|
print "s" if $cnt > 1; |
482
|
2
|
50
|
33
|
|
|
28
|
print " x$opt->{scale} scale" if $opt->{scale} && $opt->{scale} > 1; |
483
|
2
|
50
|
66
|
|
|
39
|
print ", $opt->{iter} iterations" if $opt->{iter} && $opt->{iter} > 1; |
484
|
2
|
|
|
|
|
51
|
print ", $stats2->{threads} thread"; |
485
|
2
|
50
|
|
|
|
94
|
print "s" if $stats2->{threads} > 1; |
486
|
2
|
|
|
|
|
103
|
print "):\n"; |
487
|
2
|
100
|
|
|
|
22
|
$opt->{f} .= "s" if $opt->{time}; |
488
|
2
|
|
|
|
|
18
|
print pad_to("Single:").sprintf($opt->{f}, $avg1)."\n"; |
489
|
2
|
|
|
|
|
25
|
print pad_to("Multi:").sprintf($opt->{f}, $avg2)."\n"; |
490
|
2
|
|
|
|
|
26
|
my @newperf = Benchmark::DKbench::drop_outliers(\@perf, -1); |
491
|
2
|
|
|
|
|
58
|
my @newscal = Benchmark::DKbench::drop_outliers(\@scal, -1); |
492
|
2
|
|
|
|
|
25
|
@perf = min_max_avg(\@newperf); |
493
|
2
|
|
|
|
|
19
|
@scal = min_max_avg(\@newscal); |
494
|
2
|
|
|
|
|
24
|
print pad_to("Multi/Single perf:").sprintf("%.2fx\t(%.2f - %.2f)", $perf[2], $perf[0], $perf[1])."\n"; |
495
|
2
|
|
|
|
|
27
|
print pad_to("Multi scalability:").sprintf("%2.1f%% \t(%.0f%% - %.0f%%)", $scal[2], $scal[0], $scal[1])."\n"; |
496
|
|
|
|
|
|
|
} |
497
|
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
sub run_iteration { |
499
|
8
|
|
|
8
|
0
|
42
|
my ($opt, $stats) = @_; |
500
|
8
|
|
|
|
|
79
|
my $benchmarks = benchmark_list(); |
501
|
8
|
100
|
|
|
|
61
|
my $title = $opt->{time} ? 'Time (sec)' : 'Score'; |
502
|
8
|
|
|
|
|
39
|
print pad_to("Benchmark").pad_to($title); |
503
|
8
|
100
|
|
|
|
105
|
print "Pass/Fail" unless $opt->{time}; |
504
|
8
|
|
|
|
|
91
|
print "\n"; |
505
|
8
|
|
|
|
|
44
|
my ($total_score, $total_time, $i) = (0, 0, 0); |
506
|
8
|
|
|
|
|
139
|
foreach my $bench (sort keys %$benchmarks) { |
507
|
168
|
100
|
100
|
|
|
663
|
next if $opt->{skip_bio} && $bench =~ /Monomers/; |
508
|
166
|
100
|
100
|
|
|
533
|
next if $opt->{skip_prove} && $bench =~ /prove/; |
509
|
164
|
100
|
100
|
|
|
676
|
next if !$opt->{bio_codons} && $bench =~ /Codons/; |
510
|
158
|
100
|
100
|
|
|
536
|
next if !$opt->{time_piece} && $bench =~ /Time::Piece/; |
511
|
152
|
100
|
100
|
|
|
502
|
next if $opt->{ver} && $benchmarks->{$bench}->[5] && $opt->{ver} < $benchmarks->{$bench}->[5]; |
|
|
|
100
|
|
|
|
|
512
|
150
|
100
|
100
|
|
|
618
|
next if $opt->{exclude} && $bench =~ /$opt->{exclude}/; |
513
|
144
|
100
|
100
|
|
|
792
|
next if $opt->{include} && $bench !~ /$opt->{include}/; |
514
|
23
|
50
|
|
|
|
146
|
if ($bench =~ /Bio/) { |
515
|
0
|
|
|
|
|
0
|
require Bio::SeqIO; |
516
|
0
|
|
|
|
|
0
|
require Bio::Tools::SeqStats; |
517
|
|
|
|
|
|
|
} |
518
|
23
|
|
|
|
|
94
|
my ($time, $res) = mce_bench_run($opt, $benchmarks->{$bench}); |
519
|
23
|
|
50
|
|
|
405
|
my $score = int(1000*$opt->{threads}*$benchmarks->{$bench}->[1]/($time || 1)+0.5); |
520
|
23
|
|
|
|
|
98
|
$total_score += $score; |
521
|
23
|
|
|
|
|
73
|
$total_time += $time; |
522
|
23
|
|
|
|
|
68
|
$i++; |
523
|
23
|
|
|
|
|
57
|
push @{$stats->{$bench}->{times}}, $time; |
|
23
|
|
|
|
|
352
|
|
524
|
23
|
|
|
|
|
77
|
push @{$stats->{$bench}->{scores}}, $score; |
|
23
|
|
|
|
|
164
|
|
525
|
23
|
100
|
|
|
|
191
|
my $d = $stats->{$bench}->{$opt->{time} ? 'times' : 'scores'}->[-1]; |
526
|
23
|
100
|
|
|
|
180
|
$stats->{$bench}->{fail}++ if $res ne 'Pass'; |
527
|
23
|
|
|
|
|
212
|
print pad_to("$bench:").pad_to(sprintf($opt->{f}, $d)); |
528
|
23
|
100
|
|
|
|
250
|
print "$res" unless $opt->{time}; |
529
|
23
|
|
|
|
|
351
|
print "\n"; |
530
|
23
|
50
|
|
|
|
198
|
sleep $opt->{sleep} if $opt->{sleep}; |
531
|
|
|
|
|
|
|
} |
532
|
8
|
100
|
|
|
|
254
|
die "No tests to run\n" unless $i; |
533
|
7
|
|
|
|
|
44
|
my $s = int($total_score/$i+0.5); |
534
|
7
|
100
|
|
|
|
62
|
print pad_to("Overall $title: ").sprintf($opt->{f}."\n", $opt->{time} ? $total_time : $s); |
535
|
7
|
|
|
|
|
39
|
push @{$stats->{total}->{times}}, $total_time; |
|
7
|
|
|
|
|
97
|
|
536
|
7
|
|
|
|
|
21
|
push @{$stats->{total}->{scores}}, $s; |
|
7
|
|
|
|
|
766
|
|
537
|
|
|
|
|
|
|
} |
538
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
sub mce_bench_run { |
540
|
23
|
|
|
23
|
0
|
73
|
my $opt = shift; |
541
|
23
|
|
|
|
|
48
|
my $benchmark = shift; |
542
|
23
|
100
|
|
|
|
129
|
$benchmark->[3] = $benchmark->[4] unless $opt->{quick}; |
543
|
23
|
100
|
|
|
|
124
|
return bench_run($benchmark) if $opt->{no_mce}; |
544
|
|
|
|
|
|
|
|
545
|
|
|
|
|
|
|
my @stats = mce_loop { |
546
|
0
|
|
|
0
|
|
0
|
my ($mce, $chunk_ref, $chunk_id) = @_; |
547
|
0
|
|
|
|
|
0
|
for (@{$chunk_ref}) { |
|
0
|
|
|
|
|
0
|
|
548
|
0
|
|
|
|
|
0
|
my ($time, $res) = bench_run($benchmark); |
549
|
0
|
|
|
|
|
0
|
MCE->gather([$time, $res]); |
550
|
|
|
|
|
|
|
} |
551
|
|
|
|
|
|
|
} |
552
|
1
|
|
|
|
|
34
|
(1 .. $opt->{threads} * $opt->{scale}); |
553
|
|
|
|
|
|
|
|
554
|
1
|
|
|
|
|
21341410
|
my ($res, $time) = ('Pass', 0); |
555
|
1
|
|
|
|
|
16
|
foreach (@stats) { |
556
|
2
|
|
|
|
|
22
|
$time += $_->[0]; |
557
|
2
|
50
|
|
|
|
29
|
$res = $_->[1] if $_->[1] ne 'Pass'; |
558
|
|
|
|
|
|
|
} |
559
|
|
|
|
|
|
|
|
560
|
1
|
|
50
|
|
|
40
|
return $time/($opt->{threads}*$opt->{scale} || 1), $res; |
561
|
|
|
|
|
|
|
} |
562
|
|
|
|
|
|
|
|
563
|
|
|
|
|
|
|
sub bench_run { |
564
|
23
|
|
|
23
|
0
|
224
|
my ($benchmark, $srand) = @_; |
565
|
23
|
|
100
|
|
|
158
|
$srand //= 1; |
566
|
23
|
|
|
|
|
86
|
srand($srand); # For repeatability |
567
|
23
|
|
|
|
|
97
|
my $t0 = _get_time(); |
568
|
23
|
|
|
|
|
257
|
my $out = $benchmark->[2]->($benchmark->[3]); |
569
|
22
|
|
|
|
|
40045
|
my $time = sprintf("%.3f", _get_time()-$t0); |
570
|
22
|
100
|
|
|
|
933
|
my $r = $out eq $benchmark->[0] ? 'Pass' : "Fail ($out)"; |
571
|
22
|
|
|
|
|
251
|
return $time, $r; |
572
|
|
|
|
|
|
|
} |
573
|
|
|
|
|
|
|
|
574
|
|
|
|
|
|
|
sub bench_astro { |
575
|
1
|
|
|
1
|
0
|
2
|
my $iter = shift; |
576
|
1
|
|
|
|
|
15
|
my $d = Digest->new("MD5"); |
577
|
|
|
|
|
|
|
my $precessed = precess([rand(24), rand(180)-90], rand(200)+1900, rand(200)+1900) |
578
|
1
|
|
|
|
|
61
|
for (1..$iter*10); |
579
|
1
|
|
|
|
|
10233624
|
my $constellation_abbrev; |
580
|
|
|
|
|
|
|
$d->add(constellation_for_eq(rand(24), rand(180)-90, rand(200)+1900)) |
581
|
1
|
|
|
|
|
21
|
for (1..$iter); |
582
|
1
|
|
|
|
|
7975509
|
return $d->hexdigest; |
583
|
|
|
|
|
|
|
} |
584
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
sub bench_bioperl_codons { |
586
|
0
|
|
|
0
|
0
|
0
|
my $skip = shift; |
587
|
0
|
|
|
|
|
0
|
my $iter = shift; |
588
|
0
|
|
|
|
|
0
|
my $d = Digest->new("MD5"); |
589
|
0
|
|
|
|
|
0
|
my $file = catfile($datadir, "gbbct5.seq"); |
590
|
0
|
|
|
|
|
0
|
foreach (1..$iter) { |
591
|
0
|
|
|
|
|
0
|
my $in = Bio::SeqIO->new(-file => $file, -format => "genbank"); |
592
|
0
|
|
|
|
|
0
|
$in->next_seq for (1..$skip); |
593
|
0
|
|
|
|
|
0
|
my $seq = $in->next_seq; |
594
|
0
|
|
|
|
|
0
|
my $seq_stats = Bio::Tools::SeqStats->new($seq); |
595
|
0
|
|
|
|
|
0
|
my $codon_ref = $seq_stats->count_codons(); |
596
|
0
|
|
|
|
|
0
|
$d->add($_, $codon_ref->{$_}) for sort keys %$codon_ref; |
597
|
|
|
|
|
|
|
} |
598
|
0
|
|
|
|
|
0
|
return $d->hexdigest; |
599
|
|
|
|
|
|
|
} |
600
|
|
|
|
|
|
|
|
601
|
|
|
|
|
|
|
sub bench_bioperl_mono { |
602
|
0
|
|
|
0
|
0
|
0
|
my $iter = shift; |
603
|
0
|
|
|
|
|
0
|
my $file = catfile($datadir, "gbbct5.seq"); |
604
|
0
|
|
|
|
|
0
|
my $in = Bio::SeqIO->new(-file => $file, -format => "genbank"); |
605
|
0
|
|
|
|
|
0
|
my $d = Digest->new("MD5"); |
606
|
0
|
|
|
|
|
0
|
my $builder = $in->sequence_builder(); |
607
|
0
|
|
|
|
|
0
|
$builder->want_none(); |
608
|
0
|
|
|
|
|
0
|
$builder->add_wanted_slot('display_id','seq'); |
609
|
0
|
|
|
|
|
0
|
for (1..$iter) { |
610
|
0
|
|
|
|
|
0
|
my $seq = $in->next_seq; |
611
|
0
|
|
|
|
|
0
|
my $seq_stats = Bio::Tools::SeqStats->new($seq); |
612
|
0
|
|
|
|
|
0
|
my $weight = $seq_stats->get_mol_wt(); |
613
|
0
|
|
|
|
|
0
|
$d->add(int($weight->[0])); |
614
|
0
|
|
|
|
|
0
|
my $monomer_ref = $seq_stats->count_monomers(); |
615
|
0
|
|
|
|
|
0
|
$d->add($_, $monomer_ref->{$_}) for sort keys %$monomer_ref; |
616
|
|
|
|
|
|
|
} |
617
|
0
|
|
|
|
|
0
|
return $d->hexdigest; |
618
|
|
|
|
|
|
|
} |
619
|
|
|
|
|
|
|
|
620
|
|
|
|
|
|
|
sub bench_css { |
621
|
1
|
|
|
1
|
0
|
4
|
my $iter = shift; |
622
|
1
|
|
|
|
|
8
|
my $d = Digest->new("MD5"); |
623
|
1
|
|
|
|
|
54
|
my $file; |
624
|
|
|
|
|
|
|
my $html; |
625
|
1
|
|
|
|
|
5
|
for (1..$iter) { |
626
|
2
|
|
|
|
|
3318
|
my $inliner = new CSS::Inliner(); |
627
|
2
|
|
|
|
|
1979
|
my $i = $_ % 2 + 1; |
628
|
2
|
|
|
|
|
24
|
$file = catfile($datadir, "wiki$i.html"); |
629
|
2
|
|
|
|
|
28
|
$inliner->read_file({ filename => $file }); |
630
|
2
|
|
|
|
|
14781962
|
$html = $inliner->inlinify(); |
631
|
2
|
|
|
|
|
16065715
|
$d->add(Encode::encode_utf8($html)); |
632
|
|
|
|
|
|
|
} |
633
|
1
|
|
|
|
|
28017
|
return $d->hexdigest; |
634
|
|
|
|
|
|
|
} |
635
|
|
|
|
|
|
|
|
636
|
|
|
|
|
|
|
sub bench_datetime { |
637
|
1
|
|
|
1
|
0
|
14
|
my $iter = shift; |
638
|
1
|
|
|
|
|
1351
|
my @tz = map {DateTime::TimeZone->new( name => $_ )} qw(UTC Europe/London America/New_York); |
|
3
|
|
|
|
|
19488
|
|
639
|
1
|
|
|
|
|
4250
|
my $d = Digest->new("MD5"); |
640
|
1
|
|
|
|
|
38
|
my $str; |
641
|
|
|
|
|
|
|
|
642
|
1
|
|
|
|
|
5
|
for (1..$iter) { |
643
|
5000
|
|
|
|
|
124495
|
my $dt = DateTime->now(); |
644
|
5000
|
|
|
|
|
1316471
|
my $dt1 = DateTime->from_epoch( |
645
|
|
|
|
|
|
|
epoch => 946684800 + rand(100000000), |
646
|
|
|
|
|
|
|
); |
647
|
5000
|
|
|
|
|
1344484
|
my $dt2 = DateTime->from_epoch( |
648
|
|
|
|
|
|
|
epoch => 946684800 + rand(100000000), |
649
|
|
|
|
|
|
|
); |
650
|
5000
|
|
|
|
|
1317818
|
$str = $dt2->strftime('%FT%T')."\n"; |
651
|
5000
|
|
|
|
|
548143
|
$d->add($str); |
652
|
5000
|
|
|
|
|
8620
|
eval {$dt2->set_time_zone($tz[int(rand(3))])}; |
|
5000
|
|
|
|
|
20376
|
|
653
|
5000
|
|
|
|
|
1071767
|
my $dur = $dt2->subtract_datetime($dt1); |
654
|
5000
|
|
|
|
|
6037743
|
eval {$dt2->add_duration($dur)}; |
|
5000
|
|
|
|
|
15522
|
|
655
|
5000
|
|
|
|
|
6008393
|
eval {$dt2->subtract(days => int(rand(1000)+1))}; |
|
5000
|
|
|
|
|
22180
|
|
656
|
5000
|
|
|
|
|
6519491
|
$dt->week; |
657
|
5000
|
|
|
|
|
124908
|
$dt->epoch; |
658
|
5000
|
|
|
|
|
38323
|
$d->add($dt2->strftime('%FT%T')); |
659
|
5000
|
|
|
|
|
572509
|
eval {$dt2->set( year => int(rand(2030)))}; |
|
5000
|
|
|
|
|
18363
|
|
660
|
5000
|
|
|
|
|
3225837
|
$d->add($dt2->ymd('/')); |
661
|
|
|
|
|
|
|
} |
662
|
1
|
|
|
|
|
36
|
return $d->hexdigest; |
663
|
|
|
|
|
|
|
} |
664
|
|
|
|
|
|
|
|
665
|
|
|
|
|
|
|
sub bench_dbi { |
666
|
1
|
|
|
1
|
0
|
4
|
my $iter = shift; |
667
|
1
|
|
|
|
|
11
|
my $d = Digest->new("MD5"); |
668
|
1
|
|
|
|
|
96
|
my $dbh = DBI->connect( 'DBI:Mock:', '', '' ); |
669
|
1
|
|
|
|
|
17107
|
my ($data, $cols) = _db_data(); |
670
|
|
|
|
|
|
|
|
671
|
1
|
|
|
|
|
7
|
foreach (1..$iter) { |
672
|
5000
|
|
|
|
|
2273617
|
my $inserter = SQL::Inserter->new( |
673
|
|
|
|
|
|
|
dbh => $dbh, |
674
|
|
|
|
|
|
|
table => 'table', |
675
|
|
|
|
|
|
|
cols => $cols, |
676
|
|
|
|
|
|
|
buffer => 2 |
677
|
|
|
|
|
|
|
); |
678
|
5000
|
|
|
|
|
162005
|
$inserter->insert($data->[int(rand(20))]) for 1..2; |
679
|
5000
|
|
|
|
|
3687674
|
$d->add($dbh->last_insert_id); |
680
|
5000
|
|
|
|
|
55101
|
my $sql = SQL::Abstract::Classic->new(); |
681
|
5000
|
|
|
|
|
229956
|
my ($stmt, @bind) = $sql->insert('table', $data->[int(rand(20))]); |
682
|
5000
|
|
|
|
|
3881232
|
$d->add($dbh->quote($stmt)); |
683
|
5000
|
|
|
|
|
88306
|
($stmt, @bind) = $sql->select('table', $cols->[int(rand(20))], [map {_rand_where()} 1..int(rand(3)+1)]); |
|
10091
|
|
|
|
|
19908
|
|
684
|
5000
|
|
|
|
|
5989110
|
$d->add($dbh->quote($stmt._random_str(5))); |
685
|
5000
|
|
|
|
|
90354
|
my $dbh2 = DBI->connect( 'DBI:Mock:', '', '' ); |
686
|
|
|
|
|
|
|
} |
687
|
1
|
|
|
|
|
555
|
return $d->hexdigest; |
688
|
|
|
|
|
|
|
} |
689
|
|
|
|
|
|
|
|
690
|
|
|
|
|
|
|
sub bench_dct { |
691
|
2
|
|
|
2
|
0
|
8
|
my $iter = shift; |
692
|
2
|
|
|
|
|
32
|
my $d = Digest->new("MD5"); |
693
|
2
|
|
|
|
|
117
|
$d->add(bench_dct_sz(@$_)) foreach [$iter, 32], [$iter, 18], [$iter*8,8]; |
694
|
|
|
|
|
|
|
|
695
|
2
|
|
|
|
|
56
|
return $d->hexdigest; |
696
|
|
|
|
|
|
|
} |
697
|
|
|
|
|
|
|
|
698
|
|
|
|
|
|
|
sub bench_dct_sz { |
699
|
6
|
|
|
6
|
0
|
41
|
my $iter = shift; |
700
|
6
|
|
|
|
|
31
|
my $sz = shift; |
701
|
6
|
|
|
|
|
76
|
my $d = Digest->new("MD5"); |
702
|
6
|
|
|
|
|
261
|
my @arrays; |
703
|
6
|
|
|
|
|
181
|
push @arrays, [map { rand(256) } ( 1..$sz*$sz )] foreach 1..10; |
|
28240
|
|
|
|
|
39527
|
|
704
|
6
|
|
|
|
|
40
|
foreach (1..$iter) { |
705
|
500000
|
|
|
|
|
1008142
|
my $dct = dct2d($arrays[$iter % 10], $sz); |
706
|
500000
|
100
|
|
|
|
16201531
|
$d->add($dct->[0]) if $_ % 10 == 1; |
707
|
|
|
|
|
|
|
} |
708
|
6
|
|
|
|
|
1041
|
return $d->hexdigest; |
709
|
|
|
|
|
|
|
} |
710
|
|
|
|
|
|
|
|
711
|
|
|
|
|
|
|
sub bench_digest { |
712
|
1
|
|
|
1
|
0
|
4
|
my $iter = shift; |
713
|
1
|
|
|
|
|
6
|
my $str = _read_wiki_files(); |
714
|
1
|
|
|
|
|
16
|
my $d = Digest->new("MD5"); |
715
|
1
|
|
|
|
|
53
|
my $hex; |
716
|
1
|
|
|
|
|
6
|
foreach (1..$iter) { |
717
|
50
|
|
|
|
|
221
|
my $d2 = Digest->new("MD5"); |
718
|
50
|
|
|
|
|
428826
|
$d2->add($str); |
719
|
50
|
|
|
|
|
473
|
$hex = $d2->hexdigest; |
720
|
50
|
|
|
|
|
187
|
$d->add($hex); |
721
|
50
|
|
|
|
|
233
|
$d2 = Digest->new("SHA-512"); |
722
|
50
|
|
|
|
|
1130910
|
$d2->add($str); |
723
|
50
|
|
|
|
|
753
|
$hex = $d2->hexdigest; |
724
|
50
|
|
|
|
|
288
|
$d->add($hex); |
725
|
50
|
|
|
|
|
210
|
$d2 = Digest->new("SHA-1"); |
726
|
50
|
|
|
|
|
659103
|
$d2->add($str); |
727
|
50
|
|
|
|
|
537
|
$hex = $d2->hexdigest; |
728
|
50
|
|
|
|
|
450
|
$d->add($hex); |
729
|
|
|
|
|
|
|
} |
730
|
1
|
|
|
|
|
12
|
return $d->hexdigest; |
731
|
|
|
|
|
|
|
} |
732
|
|
|
|
|
|
|
|
733
|
|
|
|
|
|
|
sub bench_encode { |
734
|
1
|
|
|
1
|
0
|
4
|
my $iter = shift; |
735
|
1
|
|
|
|
|
7
|
my $str = _read_wiki_files('utf8'); |
736
|
1
|
|
|
|
|
10
|
my $UTF8 = Encode::find_encoding('UTF-8'); |
737
|
1
|
|
|
|
|
67
|
my $UTF16 = Encode::find_encoding('UTF-16'); |
738
|
1
|
|
|
|
|
4028
|
our $cp1252 = Encode::find_encoding('cp-1252'); |
739
|
1
|
|
|
|
|
467
|
my $res = 'PASS'; |
740
|
1
|
|
|
|
|
5
|
my $unenc = 0; |
741
|
|
|
|
|
|
|
|
742
|
1
|
|
|
|
|
7
|
foreach (1..$iter) { |
743
|
40
|
|
|
|
|
56786
|
my $bytes = encode_utf8($str); |
744
|
40
|
50
|
|
|
|
16275
|
$res = 'Fail' unless length($bytes) > length($str); |
745
|
40
|
|
|
|
|
52232
|
my $cp = decode_utf8($bytes); |
746
|
40
|
100
|
|
|
|
178343
|
my $enc = rand(1) > 0.25 ? $UTF8 : $UTF16; |
747
|
40
|
|
|
|
|
854638
|
$bytes = $enc->encode($cp); |
748
|
40
|
|
|
|
|
521693
|
$cp = $enc->decode($bytes); |
749
|
40
|
50
|
|
|
|
114927
|
$res = 'Fail' unless $cp eq $str; |
750
|
40
|
|
|
|
|
935331
|
my $str2 = $cp1252->encode($cp); |
751
|
40
|
|
|
|
|
1841733
|
$enc->encode($cp1252->decode($str2)); |
752
|
40
|
|
|
|
|
43836
|
$unenc = () = $str2 =~ /\?/g; # Non-encodable |
753
|
|
|
|
|
|
|
} |
754
|
1
|
|
|
|
|
16
|
return "$res $unenc"; |
755
|
|
|
|
|
|
|
} |
756
|
|
|
|
|
|
|
|
757
|
|
|
|
|
|
|
sub bench_imager { |
758
|
2
|
|
|
2
|
0
|
18
|
my $iter = shift; |
759
|
2
|
|
|
|
|
20
|
my $d = Digest->new("MD5"); |
760
|
|
|
|
|
|
|
|
761
|
2
|
|
|
|
|
372
|
my $data; |
762
|
2
|
100
|
|
|
|
264
|
open (my $fh, '<:raw', catfile($datadir,'M31.bmp')) or die $!; |
763
|
1
|
|
|
|
|
10299
|
read($fh, $data, -s $fh); |
764
|
1
|
|
|
|
|
33
|
close($fh); |
765
|
|
|
|
|
|
|
|
766
|
1
|
|
|
|
|
10
|
foreach (1..$iter) { |
767
|
4
|
50
|
|
|
|
528761
|
my $img = Imager->new(data=>$data, type=>'bmp') or die Imager->errstr(); |
768
|
4
|
|
|
|
|
103982
|
my $thumb = $img->scale(scalefactor=>.3); |
769
|
4
|
|
|
|
|
302209
|
my $newimg = $img->scale(scalefactor=>1.15); |
770
|
4
|
|
|
|
|
696568
|
$newimg->filter(type=>'autolevels'); |
771
|
4
|
|
|
|
|
75479
|
$newimg->filter(type=>"gaussian", stddev=>0.5); |
772
|
4
|
|
|
|
|
640102
|
$newimg->paste(left=>40,top=>20,img=>$thumb); |
773
|
4
|
|
|
|
|
3005
|
$newimg->rubthrough(src=>$thumb,tx=>30, ty=>50); |
774
|
4
|
|
|
|
|
2816
|
$newimg->compose(src => $thumb, tx => 30, ty => 20, combine => 'color'); |
775
|
4
|
|
|
|
|
36379
|
$newimg->flip(dir=>"h"); |
776
|
4
|
|
|
|
|
36258
|
$newimg->flip(dir=>"vh"); |
777
|
4
|
|
|
|
|
36288
|
$d->add(scalar(Image::PHash->new($newimg)->pHash)); |
778
|
4
|
|
|
|
|
154621
|
$newimg = $img->crop(left=>50, right=>100, top=>10, bottom=>100); |
779
|
4
|
|
|
|
|
1050
|
$newimg = $img->crop(left=>50, top=>10, width=>50, height=>90); |
780
|
4
|
|
|
|
|
697
|
$newimg = $img->copy(); |
781
|
4
|
|
|
|
|
27240
|
$newimg->filter(type=>"unsharpmask", stddev=>1, scale=>0.5); |
782
|
4
|
|
|
|
|
754604
|
$newimg = $img->rotate(degrees=>20); |
783
|
4
|
|
|
|
|
398874
|
$newimg->filter(type=>"contrast", intensity=>1.4); |
784
|
4
|
|
|
|
|
133159
|
$newimg = $img->convert(matrix => [[0, 1, 0], [1, 0, 0], [0, 0, 1]]); |
785
|
4
|
|
|
|
|
45952
|
$newimg = $img->convert(preset=>'grey'); |
786
|
4
|
|
|
|
|
44527
|
$d->add(scalar(Image::PHash->new($newimg)->pHash)); |
787
|
4
|
|
|
|
|
132407
|
$img->filter(type=>'mandelbrot'); |
788
|
|
|
|
|
|
|
} |
789
|
1
|
|
|
|
|
176402
|
return $d->hexdigest; |
790
|
|
|
|
|
|
|
} |
791
|
|
|
|
|
|
|
|
792
|
|
|
|
|
|
|
sub bench_json { |
793
|
1
|
|
|
1
|
0
|
5
|
my $iter = shift; |
794
|
1
|
|
|
|
|
6
|
my $res = 'PASS'; |
795
|
1
|
|
|
|
|
5
|
for (1..$iter) { |
796
|
600
|
|
|
|
|
2061
|
my $len = int(rand(40)) + 1; |
797
|
600
|
|
|
|
|
1629
|
my $obj = rand_hash($len); |
798
|
600
|
|
|
|
|
23469
|
my $str = encode_json($obj); |
799
|
600
|
|
|
|
|
1449
|
foreach (1..100) { |
800
|
60000
|
|
|
|
|
2385851
|
$obj = decode_json($str); |
801
|
60000
|
|
|
|
|
1973581
|
$str = encode_json($obj); |
802
|
|
|
|
|
|
|
} |
803
|
600
|
|
|
|
|
21667
|
my $obj2 = decode_json($str); |
804
|
600
|
50
|
|
|
|
1677
|
$res = 'FAIL' unless compare_obj($obj, $obj2); |
805
|
|
|
|
|
|
|
} |
806
|
1
|
|
|
|
|
4
|
return $res; |
807
|
|
|
|
|
|
|
} |
808
|
|
|
|
|
|
|
|
809
|
|
|
|
|
|
|
sub bench_jwt { |
810
|
1
|
|
|
1
|
0
|
2
|
my $iter = shift; |
811
|
1
|
|
|
|
|
9
|
my $d = Digest->new("MD5"); |
812
|
1
|
|
|
|
|
112
|
my $data = _random_str(5000); |
813
|
1
|
|
|
|
|
11
|
my $rsa ='-----BEGIN PRIVATE KEY----- |
814
|
|
|
|
|
|
|
MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAqPfgaTEWEP3S9w0t |
815
|
|
|
|
|
|
|
gsicURfo+nLW09/0KfOPinhYZ4ouzU+3xC4pSlEp8Ut9FgL0AgqNslNaK34Kq+NZ |
816
|
|
|
|
|
|
|
jO9DAQIDAQABAkAgkuLEHLaqkWhLgNKagSajeobLS3rPT0Agm0f7k55FXVt743hw |
817
|
|
|
|
|
|
|
Ngkp98bMNrzy9AQ1mJGbQZGrpr4c8ZAx3aRNAiEAoxK/MgGeeLui385KJ7ZOYktj |
818
|
|
|
|
|
|
|
hLBNAB69fKwTZFsUNh0CIQEJQRpFCcydunv2bENcN/oBTRw39E8GNv2pIcNxZkcb |
819
|
|
|
|
|
|
|
NQIgbYSzn3Py6AasNj6nEtCfB+i1p3F35TK/87DlPSrmAgkCIQDJLhFoj1gbwRbH |
820
|
|
|
|
|
|
|
/bDRPrtlRUDDx44wHoEhSDRdy77eiQIgE6z/k6I+ChN1LLttwX0galITxmAYrOBh |
821
|
|
|
|
|
|
|
BVl433tgTTQ= |
822
|
|
|
|
|
|
|
-----END PRIVATE KEY-----'; |
823
|
1
|
|
|
|
|
4
|
my $key = '-----BEGIN PRIVATE KEY----- |
824
|
|
|
|
|
|
|
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgYirTZSx+5O8Y6tlG |
825
|
|
|
|
|
|
|
cka6W6btJiocdrdolfcukSoTEk+hRANCAAQkvPNu7Pa1GcsWU4v7ptNfqCJVq8Cx |
826
|
|
|
|
|
|
|
zo0MUVPQgwJ3aJtNM1QMOQUayCrRwfklg+D/rFSUwEUqtZh7fJDiFqz3 |
827
|
|
|
|
|
|
|
-----END PRIVATE KEY-----'; |
828
|
1
|
|
|
|
|
5
|
foreach (1..$iter) { |
829
|
250
|
|
|
|
|
721
|
my $extra = _random_str(100); |
830
|
250
|
|
|
|
|
978
|
my $data_in = $data.$extra; |
831
|
250
|
|
|
|
|
844
|
my $token = encode_jwt( |
832
|
|
|
|
|
|
|
payload => $data_in, |
833
|
|
|
|
|
|
|
alg => 'ES256', |
834
|
|
|
|
|
|
|
key => \$key, |
835
|
|
|
|
|
|
|
); |
836
|
|
|
|
|
|
|
|
837
|
250
|
|
|
|
|
2181073
|
my $data_out = _decode_jwt2(token=>$token, key=>\$key); |
838
|
250
|
50
|
|
|
|
1115
|
$d->add($token) if $data_in eq $data_out.$extra; |
839
|
|
|
|
|
|
|
|
840
|
250
|
|
|
|
|
889
|
$token = encode_jwt( |
841
|
|
|
|
|
|
|
payload => $data_in, |
842
|
|
|
|
|
|
|
alg => 'RS256', |
843
|
|
|
|
|
|
|
key => \$rsa, |
844
|
|
|
|
|
|
|
); |
845
|
|
|
|
|
|
|
|
846
|
250
|
|
|
|
|
211591
|
$data_out = _decode_jwt2(token=>$token, key=>\$rsa); |
847
|
250
|
50
|
|
|
|
1336
|
$d->add($token) if $data_in eq $data_out.$extra; |
848
|
|
|
|
|
|
|
} |
849
|
1
|
|
|
|
|
31
|
return $d->hexdigest; |
850
|
|
|
|
|
|
|
} |
851
|
|
|
|
|
|
|
|
852
|
|
|
|
|
|
|
sub bench_formattext { |
853
|
1
|
|
|
1
|
0
|
5
|
my $iter = shift; |
854
|
1
|
|
|
|
|
15
|
my $d = Digest->new("MD5"); |
855
|
1
|
|
|
|
|
76
|
my $file; |
856
|
1
|
|
|
|
|
6
|
for (0..$iter-1) { |
857
|
4
|
|
|
|
|
4430401
|
my $i = $_ % 2; |
858
|
4
|
|
|
|
|
58
|
$file = catfile($datadir, "wiki$i.html"); |
859
|
4
|
|
|
|
|
59
|
my $tree = HTML::TreeBuilder->new->parse_file($file); |
860
|
4
|
|
|
|
|
12109785
|
my $formatter = HTML::FormatText->new(); |
861
|
4
|
|
|
|
|
187
|
my $text = $formatter->format($tree); |
862
|
4
|
|
|
|
|
8884045
|
$formatter = HTML::FormatText->new(leftmargin => 0, rightmargin => 30); |
863
|
4
|
|
|
|
|
16347
|
$d->add(Encode::encode_utf8($formatter->format($tree))); |
864
|
|
|
|
|
|
|
} |
865
|
1
|
|
|
|
|
4965672
|
return $d->hexdigest; |
866
|
|
|
|
|
|
|
} |
867
|
|
|
|
|
|
|
|
868
|
|
|
|
|
|
|
sub bench_matrixreal { |
869
|
2
|
|
|
2
|
0
|
13
|
my $iter = shift; |
870
|
2
|
|
|
|
|
46
|
my $d = Digest->new("MD5"); |
871
|
2
|
|
|
|
|
246
|
my $smatrix = Math::MatrixReal->new_random(13); |
872
|
2
|
|
|
|
|
2485
|
my $matrix = Math::MatrixReal->new_random(20); |
873
|
2
|
|
|
|
|
4765
|
my $bmatrix = Math::MatrixReal->new_random(72); |
874
|
|
|
|
|
|
|
|
875
|
2
|
|
|
|
|
49344
|
for (1..$iter) { |
876
|
1300
|
|
|
|
|
16406
|
my $r = rand(10); |
877
|
1300
|
|
|
|
|
9373
|
my $m1 = $r*$bmatrix; |
878
|
1300
|
|
|
|
|
10110513
|
my $m2 = $bmatrix*$r; |
879
|
1300
|
|
|
|
|
9790164
|
my $m3 = $bmatrix->multiply_scalar($bmatrix,$r); |
880
|
|
|
|
|
|
|
# Should be zero |
881
|
1300
|
100
|
|
|
|
8876181
|
$d->add($m1->element(1, 1) + $m2->element(1, 1) - 2 * $bmatrix->element(1, 1)) |
882
|
|
|
|
|
|
|
if $_ % 10 == 1; |
883
|
|
|
|
|
|
|
|
884
|
1300
|
|
|
|
|
15719
|
my $m = $matrix->det; |
885
|
1300
|
100
|
|
|
|
16736480
|
$d->add($m) if $_ % 10 == 1; |
886
|
1300
|
|
|
|
|
6611
|
$m =$matrix->decompose_LR->det_LR; |
887
|
1300
|
100
|
|
|
|
16541820
|
$d->add($m) if $_ % 10 == 1; |
888
|
1300
|
|
|
|
|
9929
|
$m1 = $matrix ** 2; |
889
|
1300
|
|
|
|
|
17688720
|
$m2 = $matrix * $matrix; |
890
|
|
|
|
|
|
|
#should be zero |
891
|
1300
|
100
|
|
|
|
16961805
|
$d->add($m1->element(1, 1) - $m2->element(1, 1)) |
892
|
|
|
|
|
|
|
if $_ % 10 == 1; |
893
|
1300
|
|
|
|
|
14560
|
$m1 = $smatrix->inverse(); |
894
|
1300
|
|
|
|
|
15568941
|
$m2 = $smatrix ** -1; |
895
|
1300
|
|
|
|
|
15982546
|
$m3 = $smatrix->decompose_LR->invert_LR; |
896
|
1300
|
100
|
|
|
|
15399409
|
$d->add($m1->element(1, 1), $m2->element(1, 1), $m3->element(1, 1)) |
897
|
|
|
|
|
|
|
if $_ % 10 == 1; |
898
|
|
|
|
|
|
|
} |
899
|
|
|
|
|
|
|
|
900
|
2
|
|
|
|
|
360
|
return $d->hexdigest; |
901
|
|
|
|
|
|
|
} |
902
|
|
|
|
|
|
|
|
903
|
|
|
|
|
|
|
sub bench_moose { |
904
|
1
|
|
|
1
|
0
|
2
|
my $iter = shift; |
905
|
1
|
|
|
|
|
3
|
my $cnt = 0; |
906
|
|
|
|
|
|
|
|
907
|
1
|
|
|
|
|
4
|
for (1..$iter) { |
908
|
10000
|
|
|
|
|
4158705
|
my $p = rand(1000); |
909
|
10000
|
|
|
|
|
29348
|
my $root = Benchmark::DKbench::MooseTree->new(node => 'root'); |
910
|
10000
|
|
|
|
|
11032447
|
$root->price($p); |
911
|
10000
|
|
|
|
|
268103
|
$root->node; |
912
|
10000
|
|
|
|
|
29989
|
$root->cost; |
913
|
10000
|
|
|
|
|
35471
|
my $lchild = $root->left; |
914
|
10000
|
|
|
|
|
277436
|
$lchild->node('child'); |
915
|
10000
|
|
|
|
|
267951
|
$lchild->price($p); |
916
|
10000
|
|
|
|
|
262305
|
$lchild->tax; |
917
|
10000
|
|
|
|
|
31008
|
my $child = $root->right; |
918
|
10000
|
|
|
|
|
29150
|
$child->cost; |
919
|
10000
|
|
|
|
|
33688
|
my $grandchild = $child->left; |
920
|
10000
|
|
|
|
|
277958
|
$grandchild->node('grandchild'); |
921
|
10000
|
|
|
|
|
306414
|
$grandchild->has_parent; |
922
|
10000
|
|
|
|
|
264996
|
$grandchild->parent; |
923
|
10000
|
|
|
|
|
265593
|
$grandchild->price($p); |
924
|
10000
|
|
|
|
|
28469
|
$grandchild->cost; |
925
|
10000
|
|
|
|
|
32390
|
my $ggchild = $grandchild->right; |
926
|
10000
|
|
|
|
|
30584
|
$ggchild->cost; |
927
|
10000
|
|
|
|
|
43614
|
$cnt += 5; |
928
|
|
|
|
|
|
|
} |
929
|
1
|
|
|
|
|
428
|
return md5_hex("$cnt objects"); |
930
|
|
|
|
|
|
|
} |
931
|
|
|
|
|
|
|
|
932
|
|
|
|
|
|
|
sub bench_moose_prv { |
933
|
2
|
|
|
2
|
0
|
7
|
my $iter = shift; |
934
|
2
|
|
|
|
|
29
|
my $tdir = catfile($datadir, 't'); |
935
|
2
|
|
|
|
|
10
|
my $result; |
936
|
2
|
100
|
|
|
|
13
|
if ($iter < 1) { |
937
|
1
|
|
|
|
|
9
|
$tdir = catfile($tdir, 'recipes'); |
938
|
1
|
|
|
|
|
19199724
|
$result = `prove -rQ $tdir`; |
939
|
|
|
|
|
|
|
} else { |
940
|
1
|
|
|
|
|
73522895
|
$result = `prove -rQ $tdir` for (1..$iter); |
941
|
|
|
|
|
|
|
} |
942
|
2
|
50
|
|
|
|
167
|
if ($result =~ /Result: (\w*)/) { |
943
|
2
|
|
|
|
|
97
|
return $1; |
944
|
|
|
|
|
|
|
} else { |
945
|
0
|
|
|
|
|
0
|
return '?'; |
946
|
|
|
|
|
|
|
} |
947
|
|
|
|
|
|
|
} |
948
|
|
|
|
|
|
|
|
949
|
|
|
|
|
|
|
sub bench_primes_m { |
950
|
1
|
|
|
1
|
0
|
17
|
my $iter = shift; |
951
|
1
|
|
|
|
|
23
|
return bench_primes($iter, 7_500_000); |
952
|
|
|
|
|
|
|
} |
953
|
|
|
|
|
|
|
|
954
|
|
|
|
|
|
|
sub bench_primes { |
955
|
1
|
|
|
1
|
0
|
16
|
my $iter = shift; |
956
|
1
|
|
|
|
|
20
|
my $max = shift; |
957
|
1
|
|
|
|
|
23
|
my @primes; |
958
|
1
|
|
|
|
|
29
|
@primes = _get_primes($max) for (1..$iter); |
959
|
1
|
|
|
|
|
9312
|
return md5_hex(scalar(@primes)." primes up to $max"); |
960
|
|
|
|
|
|
|
} |
961
|
|
|
|
|
|
|
|
962
|
|
|
|
|
|
|
sub bench_regex_asc { |
963
|
1
|
|
|
1
|
0
|
4
|
my $iter = shift; |
964
|
1
|
|
|
|
|
15
|
return bench_regex_subst($iter, ''); |
965
|
|
|
|
|
|
|
} |
966
|
|
|
|
|
|
|
|
967
|
|
|
|
|
|
|
sub bench_regex_utf8 { |
968
|
1
|
|
|
1
|
0
|
13
|
my $iter = shift; |
969
|
1
|
|
|
|
|
13
|
return bench_regex_subst($iter, 'utf8'); |
970
|
|
|
|
|
|
|
} |
971
|
|
|
|
|
|
|
|
972
|
|
|
|
|
|
|
sub bench_regex_subst { |
973
|
2
|
|
|
2
|
0
|
15
|
my $iter = shift; |
974
|
2
|
|
|
|
|
23
|
my $enc = shift; |
975
|
2
|
|
|
|
|
34
|
my $str = _read_wiki_files($enc); |
976
|
2
|
|
|
|
|
22
|
my $match = bench_regex($str, $iter); |
977
|
2
|
|
|
|
|
42
|
my $repl = bench_subst($str, $iter); |
978
|
2
|
|
|
|
|
43
|
return md5_hex($match, $repl); |
979
|
|
|
|
|
|
|
} |
980
|
|
|
|
|
|
|
|
981
|
|
|
|
|
|
|
sub bench_regex { |
982
|
2
|
|
|
2
|
0
|
12
|
my $str = shift; |
983
|
2
|
|
|
|
|
10
|
my $iter = shift; |
984
|
2
|
|
|
|
|
7
|
my $count; |
985
|
2
|
|
|
|
|
14
|
for (1..$iter) { |
986
|
11
|
|
|
|
|
91
|
$count = 0; |
987
|
11
|
|
|
|
|
1118350
|
$count += () = $str =~ /\b[A-Z][a-z]+/g; |
988
|
11
|
|
|
|
|
1351781
|
$count += () = $str =~ /([\w\.+-]+)@[\w\.-]+\.([\w\.-]+)/g; |
989
|
11
|
|
|
|
|
971892
|
$count += () = $str =~ m![\w]+://[^/\s?#]+[^\s?#]+(?:\?[^\s#]*)?(?:#[^\s]*)?!g; |
990
|
|
|
|
|
|
|
} |
991
|
2
|
|
|
|
|
31
|
return "$count Matched"; |
992
|
|
|
|
|
|
|
} |
993
|
|
|
|
|
|
|
|
994
|
|
|
|
|
|
|
sub bench_subst { |
995
|
2
|
|
|
2
|
0
|
14
|
my $str = shift; |
996
|
2
|
|
|
|
|
11
|
my $iter = shift; |
997
|
2
|
|
|
|
|
15
|
my $count; |
998
|
2
|
|
|
|
|
17
|
for (1..$iter) { |
999
|
11
|
|
|
|
|
167
|
my $copy = $str; |
1000
|
11
|
|
|
|
|
36
|
$count = 0; |
1001
|
11
|
|
|
|
|
997583
|
while (my $s = $copy =~ s#<([^>]+)>([^>]*?)</\1>#$2#g) { |
1002
|
44
|
|
|
|
|
3892791
|
$count += $s; |
1003
|
|
|
|
|
|
|
} |
1004
|
11
|
|
|
|
|
580580
|
$copy = substr($copy, int(rand(100))+1) for 1..10; |
1005
|
|
|
|
|
|
|
} |
1006
|
2
|
|
|
|
|
49
|
return "$count Replaced"; |
1007
|
|
|
|
|
|
|
} |
1008
|
|
|
|
|
|
|
|
1009
|
|
|
|
|
|
|
sub bench_textlevenshtein { |
1010
|
1
|
|
|
1
|
0
|
14
|
my $iter = shift; |
1011
|
1
|
|
|
|
|
46
|
my $d = Digest->new("MD5"); |
1012
|
1
|
|
|
|
|
137
|
my $data = _fuzzy_data(); |
1013
|
1
|
|
|
|
|
8
|
my $diff; |
1014
|
1
|
|
|
|
|
6
|
foreach (1..$iter) { |
1015
|
7
|
|
|
|
|
34
|
foreach my $sz (qw/10 100 1000 2500/) { |
1016
|
28
|
|
|
|
|
108
|
my $n = scalar @{$data->{$sz}}; |
|
28
|
|
|
|
|
172
|
|
1017
|
28
|
|
|
|
|
149
|
my $i = int(rand($n)); |
1018
|
|
|
|
|
|
|
$diff = Text::Levenshtein::XS::distance( |
1019
|
|
|
|
|
|
|
$data->{$sz}->[$i], $data->{$sz}->[$_] |
1020
|
28
|
|
|
|
|
256
|
) for 0..$n-1; |
1021
|
28
|
|
100
|
|
|
1881763
|
$d->add($diff || -1); |
1022
|
28
|
100
|
|
|
|
138
|
next if $sz > 1000; |
1023
|
|
|
|
|
|
|
$diff = Text::Levenshtein::Damerau::XS::xs_edistance( |
1024
|
|
|
|
|
|
|
$data->{$sz}->[$i], $data->{$sz}->[$_] |
1025
|
21
|
|
|
|
|
179
|
) for 0..$n-1; |
1026
|
21
|
|
|
|
|
1675177
|
$d->add($diff); |
1027
|
|
|
|
|
|
|
} |
1028
|
|
|
|
|
|
|
} |
1029
|
1
|
|
|
|
|
92
|
return $d->hexdigest; |
1030
|
|
|
|
|
|
|
} |
1031
|
|
|
|
|
|
|
|
1032
|
|
|
|
|
|
|
sub bench_timepiece { |
1033
|
1
|
|
|
1
|
0
|
20
|
my $iter = shift; |
1034
|
1
|
|
|
|
|
27
|
my $t = Time::Piece::localtime(1692119499); |
1035
|
1
|
|
|
|
|
873
|
my $d = Digest->new("MD5"); |
1036
|
1
|
|
|
|
|
59
|
my $day = 3600*24; |
1037
|
1
|
|
|
|
|
32
|
local $ENV{TZ} = 'UTC'; |
1038
|
|
|
|
|
|
|
|
1039
|
1
|
|
|
|
|
13
|
for (1..$iter) { |
1040
|
75000
|
|
|
|
|
348203
|
$t += int(rand(1000)-500)*$day; |
1041
|
75000
|
50
|
|
|
|
2459357
|
$t += 100000*$day if $t->year < 1970; |
1042
|
75000
|
|
|
|
|
522500
|
my $str = $t->strftime("%w, %d %m %Y %H:%M:%S"); |
1043
|
75000
|
|
|
|
|
5910489
|
eval '$t = Time::Piece->strptime($str, "%w, %d %m %Y %H:%M:%S")'; |
1044
|
75000
|
|
|
|
|
1732448
|
my $jd = $t->julian_day; |
1045
|
75000
|
|
|
|
|
6343128
|
$d->add($str,$jd); |
1046
|
|
|
|
|
|
|
} |
1047
|
1
|
|
|
|
|
25
|
return $d->hexdigest; |
1048
|
|
|
|
|
|
|
} |
1049
|
|
|
|
|
|
|
|
1050
|
|
|
|
|
|
|
sub total_stats { |
1051
|
2
|
|
|
2
|
0
|
25
|
my ($opt, $stats) = @_; |
1052
|
2
|
|
|
|
|
27
|
my $benchmarks = benchmark_list(); |
1053
|
2
|
100
|
|
|
|
34
|
my $display = $opt->{time} ? 'times' : 'scores'; |
1054
|
2
|
100
|
|
|
|
26
|
my $title = $opt->{time} ? 'Time (sec)' : 'Score'; |
1055
|
2
|
|
|
|
|
23
|
print "Aggregates ($opt->{iter} iterations):\n".pad_to("Benchmark",24).pad_to("Avg $title").pad_to("Min $title").pad_to("Max $title"); |
1056
|
2
|
100
|
|
|
|
40
|
print pad_to("stdev %") if $opt->{stdev}; |
1057
|
2
|
100
|
|
|
|
32
|
print pad_to("Pass %") unless $opt->{time}; |
1058
|
2
|
|
|
|
|
33
|
print "\n"; |
1059
|
2
|
|
|
|
|
63
|
foreach my $bench (sort keys %$benchmarks) { |
1060
|
42
|
100
|
|
|
|
155
|
next unless $stats->{$bench}->{$display}; |
1061
|
2
|
|
|
|
|
16
|
my $str = calc_stats($opt, $stats->{$bench}->{$display}); |
1062
|
2
|
|
|
|
|
20
|
print pad_to("$bench:",24).$str; |
1063
|
|
|
|
|
|
|
print pad_to( |
1064
|
|
|
|
|
|
|
sprintf("%d", 100 * ($opt->{iter}-($stats->{$bench}->{fail} || 0)) / $opt->{iter})) |
1065
|
2
|
100
|
50
|
|
|
46
|
unless $opt->{time}; |
1066
|
2
|
|
|
|
|
30
|
print "\n"; |
1067
|
|
|
|
|
|
|
} |
1068
|
2
|
|
|
|
|
22
|
my $str = calc_stats($opt, $stats->{total}->{$display}); |
1069
|
2
|
|
|
|
|
32
|
print pad_to("Overall Avg $title:", 24)."$str\n"; |
1070
|
|
|
|
|
|
|
} |
1071
|
|
|
|
|
|
|
|
1072
|
|
|
|
|
|
|
sub calc_stats { |
1073
|
4
|
|
|
4
|
0
|
20
|
my $opt = shift; |
1074
|
4
|
|
|
|
|
15
|
my $arr = shift; |
1075
|
4
|
|
|
|
|
17
|
my $pad = shift; |
1076
|
4
|
|
|
|
|
28
|
my ($min, $max, $avg) = min_max_avg($arr); |
1077
|
4
|
|
|
|
|
17
|
my $str = join '', map {pad_to(sprintf($opt->{f}, $_), $pad)} ($avg,$min,$max); |
|
12
|
|
|
|
|
83
|
|
1078
|
4
|
100
|
66
|
|
|
29
|
if ($opt->{stdev} && $avg) { |
1079
|
2
|
|
|
|
|
19
|
my $stdev = avg_stdev($arr); |
1080
|
2
|
|
|
|
|
14
|
$stdev *= 100/$avg; |
1081
|
2
|
|
|
|
|
33
|
$str .= pad_to(sprintf("%0.2f%%", $stdev), $pad); |
1082
|
|
|
|
|
|
|
} |
1083
|
4
|
|
|
|
|
46
|
return $avg, $str; |
1084
|
|
|
|
|
|
|
} |
1085
|
|
|
|
|
|
|
|
1086
|
|
|
|
|
|
|
sub min_max_avg { |
1087
|
26
|
|
|
26
|
0
|
68
|
my $arr = shift; |
1088
|
26
|
100
|
|
|
|
83
|
return (0, 0, 0) unless @$arr; |
1089
|
25
|
|
|
|
|
219
|
return min(@$arr), max(@$arr), sum(@$arr)/scalar(@$arr); |
1090
|
|
|
|
|
|
|
} |
1091
|
|
|
|
|
|
|
|
1092
|
|
|
|
|
|
|
sub avg_stdev { |
1093
|
10
|
|
|
10
|
0
|
26
|
my $arr = shift; |
1094
|
10
|
100
|
|
|
|
48
|
return (0, 0) unless @$arr; |
1095
|
9
|
|
|
|
|
43
|
my $sum = sum(@$arr); |
1096
|
9
|
|
|
|
|
35
|
my $avg = $sum/scalar(@$arr); |
1097
|
9
|
|
|
|
|
24
|
my @sq; |
1098
|
9
|
|
|
|
|
78
|
push @sq, ($avg - $_)**2 for (@$arr); |
1099
|
9
|
|
|
|
|
33
|
my $dev = min_max_avg(\@sq); |
1100
|
9
|
|
|
|
|
46
|
return $avg, sqrt($dev); |
1101
|
|
|
|
|
|
|
} |
1102
|
|
|
|
|
|
|
|
1103
|
|
|
|
|
|
|
# $single = single tail of dist curve outlier, 1 for over (right), -1 for under (left) |
1104
|
|
|
|
|
|
|
sub drop_outliers { |
1105
|
7
|
|
|
7
|
0
|
25
|
my $arr = shift; |
1106
|
7
|
|
|
|
|
21
|
my $single = shift; |
1107
|
7
|
|
|
|
|
29
|
my ($avg, $stdev) = avg_stdev($arr); |
1108
|
7
|
|
|
|
|
19
|
my @newarr; |
1109
|
7
|
|
|
|
|
29
|
foreach (@$arr) { |
1110
|
43
|
100
|
|
|
|
89
|
if ($single) { |
1111
|
30
|
100
|
|
|
|
83
|
push @newarr, $_ unless $single*($_ - $avg) > 2*$stdev; |
1112
|
|
|
|
|
|
|
} else { |
1113
|
13
|
100
|
|
|
|
44
|
push @newarr, $_ unless abs($avg - $_) > 2*$stdev; |
1114
|
|
|
|
|
|
|
} |
1115
|
|
|
|
|
|
|
} |
1116
|
7
|
|
|
|
|
48
|
return @newarr; |
1117
|
|
|
|
|
|
|
} |
1118
|
|
|
|
|
|
|
|
1119
|
|
|
|
|
|
|
sub pad_to { |
1120
|
118
|
|
|
118
|
0
|
346
|
my $str = shift; |
1121
|
118
|
|
100
|
|
|
509
|
my $len = shift || 20; |
1122
|
118
|
|
|
|
|
23163
|
return $str." "x($len-length($str)); |
1123
|
|
|
|
|
|
|
} |
1124
|
|
|
|
|
|
|
|
1125
|
|
|
|
|
|
|
sub _read_wiki_files { |
1126
|
4
|
|
100
|
4
|
|
56
|
my $enc = shift || ''; |
1127
|
4
|
|
|
|
|
23
|
my $str = ""; |
1128
|
4
|
|
|
|
|
19
|
for (0..2) { |
1129
|
12
|
50
|
|
|
|
1002
|
open my $fh, "<:$enc", catfile($datadir,"wiki$_.html") or die $!; |
1130
|
12
|
|
|
|
|
66
|
$str .= do { local $/; <$fh> }; |
|
12
|
|
|
|
|
72
|
|
|
12
|
|
|
|
|
34100
|
|
1131
|
|
|
|
|
|
|
} |
1132
|
4
|
|
|
|
|
30
|
return $str; |
1133
|
|
|
|
|
|
|
} |
1134
|
|
|
|
|
|
|
|
1135
|
|
|
|
|
|
|
sub _random_str { |
1136
|
5264
|
|
100
|
5264
|
|
18197
|
my $length = shift || 1; |
1137
|
5264
|
|
|
|
|
8914
|
my $abc = shift; |
1138
|
5264
|
100
|
|
|
|
14138
|
my ($base, $rng) = $abc ? (65, 26) : (32, 95); |
1139
|
5264
|
|
|
|
|
9223
|
my $str = ""; |
1140
|
5264
|
|
|
|
|
46610
|
$str .= chr(int(rand($rng))+$base) for 1..$length; |
1141
|
5264
|
|
|
|
|
37113
|
return $str; |
1142
|
|
|
|
|
|
|
} |
1143
|
|
|
|
|
|
|
|
1144
|
|
|
|
|
|
|
sub _random_uchar { |
1145
|
46303
|
|
|
46303
|
|
63384
|
my $chr = int(rand(800))+32; |
1146
|
46303
|
100
|
|
|
|
74719
|
$chr += 128 if $chr > 127; # Skip Latin 1 supplement |
1147
|
46303
|
100
|
|
|
|
69485
|
$chr += 288 if $chr > 591; # Skip pre-Greek blocks |
1148
|
46303
|
|
|
|
|
119080
|
return chr($chr); |
1149
|
|
|
|
|
|
|
} |
1150
|
|
|
|
|
|
|
|
1151
|
|
|
|
|
|
|
sub _fuzzy_data { |
1152
|
1
|
|
|
1
|
|
8
|
my %data; |
1153
|
100
|
|
|
|
|
241
|
push @{$data{10}}, join('', map {_random_uchar()} 1..(8+int(rand(5)))) |
|
996
|
|
|
|
|
1535
|
|
1154
|
1
|
|
|
|
|
13
|
for 0..99; |
1155
|
1
|
|
|
|
|
13
|
push @{$data{100}}, $data{10}->[$_]x10 for 0..49; |
|
50
|
|
|
|
|
177
|
|
1156
|
1
|
|
|
|
|
6
|
push @{$data{1000}}, _random_str(50,1)x20 for 0..7; |
|
8
|
|
|
|
|
35
|
|
1157
|
1
|
|
|
|
|
6
|
push @{$data{2500}}, _random_str(50,1)x50 for 0..3; |
|
4
|
|
|
|
|
189
|
|
1158
|
1
|
|
|
|
|
9
|
return \%data; |
1159
|
|
|
|
|
|
|
} |
1160
|
|
|
|
|
|
|
|
1161
|
|
|
|
|
|
|
sub _rand_where { |
1162
|
16477
|
|
|
16477
|
|
24911
|
my $p = rand(); |
1163
|
16477
|
100
|
|
|
|
36153
|
if ($p > 0.5) { |
|
|
100
|
|
|
|
|
|
1164
|
8377
|
|
|
|
|
30562
|
return {foo => rand(10)}; |
1165
|
|
|
|
|
|
|
} elsif ($p > 0.2) { |
1166
|
4922
|
|
|
|
|
28299
|
return {bar => {-in => [int($p*10)..int($p*20)]}}; |
1167
|
|
|
|
|
|
|
} else { |
1168
|
3178
|
100
|
|
|
|
6608
|
my $op = $p > 0.1 ? '-and' : '-or'; |
1169
|
3178
|
|
|
|
|
6469
|
my @cond = map {_rand_where()} 1..int(rand(3)+1); |
|
6386
|
|
|
|
|
11255
|
|
1170
|
3178
|
|
|
|
|
12547
|
return {$op => [@cond]}; |
1171
|
|
|
|
|
|
|
} |
1172
|
|
|
|
|
|
|
} |
1173
|
|
|
|
|
|
|
|
1174
|
|
|
|
|
|
|
sub _db_data { |
1175
|
1
|
|
|
1
|
|
6
|
my (@data, @cols); |
1176
|
1
|
|
|
|
|
5
|
foreach (1..20) { |
1177
|
|
|
|
|
|
|
my $d = { |
1178
|
|
|
|
|
|
|
id => int(rand(10000000)), |
1179
|
|
|
|
|
|
|
date => \"NOW()", |
1180
|
20
|
|
|
|
|
54
|
map {"data".$_ => "foo bar" x int(rand(5)+1)} 1..int(rand(20)+1) |
|
202
|
|
|
|
|
705
|
|
1181
|
|
|
|
|
|
|
}; |
1182
|
20
|
|
|
|
|
67
|
push @data, $d; |
1183
|
20
|
|
|
|
|
158
|
push @cols, [sort keys %$d]; |
1184
|
|
|
|
|
|
|
} |
1185
|
1
|
|
|
|
|
8
|
return \@data, \@cols; |
1186
|
|
|
|
|
|
|
} |
1187
|
|
|
|
|
|
|
|
1188
|
|
|
|
|
|
|
sub compare_obj { |
1189
|
28701
|
|
|
28701
|
0
|
41211
|
my ($obj1, $obj2) = @_; |
1190
|
28701
|
|
|
|
|
37419
|
my $t1 = ref($obj1); |
1191
|
28701
|
|
|
|
|
34395
|
my $t2 = ref($obj2); |
1192
|
28701
|
100
|
|
|
|
45420
|
return 0 if $t1 ne $t2; |
1193
|
28700
|
100
|
|
|
|
72327
|
return $obj1 eq $obj2 unless $t1; |
1194
|
3496
|
100
|
|
|
|
7794
|
return $t1 eq 'ARRAY' ? compare_arr($obj1, $obj2) : compare_hash($obj1, $obj2); |
1195
|
|
|
|
|
|
|
} |
1196
|
|
|
|
|
|
|
|
1197
|
|
|
|
|
|
|
sub compare_arr { |
1198
|
1461
|
|
|
1461
|
0
|
2289
|
my ($arr1, $arr2) = @_; |
1199
|
1461
|
|
|
|
|
2078
|
my $sz = scalar @$arr1; |
1200
|
1461
|
100
|
|
|
|
2569
|
return 0 if $sz != scalar @$arr2; |
1201
|
1460
|
|
|
|
|
2998
|
for (0..$sz-1) { |
1202
|
8156
|
100
|
|
|
|
12684
|
return 0 unless compare_obj($arr1->[$_], $arr2->[$_]); |
1203
|
|
|
|
|
|
|
} |
1204
|
1459
|
|
|
|
|
3305
|
return 1; |
1205
|
|
|
|
|
|
|
} |
1206
|
|
|
|
|
|
|
|
1207
|
|
|
|
|
|
|
sub compare_hash { |
1208
|
2039
|
|
|
2039
|
0
|
3777
|
my ($h1, $h2) = @_; |
1209
|
2039
|
100
|
|
|
|
5189
|
return 0 if scalar keys %$h1 != scalar keys %$h2; |
1210
|
2038
|
|
|
|
|
7100
|
for (keys %$h1) { |
1211
|
19944
|
100
|
|
|
|
32770
|
return 0 unless compare_obj($h1->{$_}, $h2->{$_}); |
1212
|
|
|
|
|
|
|
} |
1213
|
2037
|
|
|
|
|
12626
|
return 1; |
1214
|
|
|
|
|
|
|
} |
1215
|
|
|
|
|
|
|
|
1216
|
|
|
|
|
|
|
sub rand_arr { |
1217
|
1468
|
|
|
1468
|
0
|
1966
|
my $sz = shift; |
1218
|
1468
|
|
|
|
|
2020
|
my @arr; |
1219
|
1468
|
|
|
|
|
2402
|
for (1..$sz) { |
1220
|
8203
|
|
|
|
|
11862
|
my $len = int(rand(10)) + 1; |
1221
|
8203
|
100
|
|
|
|
15239
|
my $item = rand(1) < 0.9 ? _random_uchar()x($len*5) : rand(1) < 0.5 ? rand_arr($len) : rand_hash($len); |
|
|
100
|
|
|
|
|
|
1222
|
8203
|
|
|
|
|
14269
|
push @arr, $item; |
1223
|
|
|
|
|
|
|
} |
1224
|
1468
|
|
|
|
|
2339
|
return \@arr; |
1225
|
|
|
|
|
|
|
} |
1226
|
|
|
|
|
|
|
|
1227
|
|
|
|
|
|
|
sub rand_hash { |
1228
|
2044
|
|
|
2044
|
0
|
2965
|
my $sz = shift; |
1229
|
2044
|
|
|
|
|
2740
|
my %hash; |
1230
|
2044
|
|
|
|
|
3398
|
for (1..$sz) { |
1231
|
20008
|
|
|
|
|
31160
|
my $len = int(rand(10)) + 1; |
1232
|
20008
|
100
|
|
|
|
36975
|
my $item = rand(1) < 0.9 ? _random_uchar()x($len*5) : rand(1) < 0.5 ? rand_arr($len) : rand_hash($len); |
|
|
100
|
|
|
|
|
|
1233
|
20008
|
|
|
|
|
32400
|
$hash{_random_uchar()x($len*4)} = $item; |
1234
|
|
|
|
|
|
|
} |
1235
|
2044
|
|
|
|
|
3881
|
return \%hash; |
1236
|
|
|
|
|
|
|
} |
1237
|
|
|
|
|
|
|
|
1238
|
|
|
|
|
|
|
# modified from https://github.com/famzah/langs-performance/blob/master/primes.pl |
1239
|
|
|
|
|
|
|
sub _get_primes { |
1240
|
2
|
|
|
2
|
|
27
|
my $n = shift; |
1241
|
2
|
|
|
|
|
19
|
my @s = (); |
1242
|
2
|
|
|
|
|
36
|
for (my $i = 3; $i < $n + 1; $i += 2) { |
1243
|
7499998
|
|
|
|
|
12822575
|
push(@s, $i); |
1244
|
|
|
|
|
|
|
} |
1245
|
2
|
|
|
|
|
30
|
my $mroot = $n**0.5; |
1246
|
2
|
|
|
|
|
17
|
my $half = scalar @s; |
1247
|
2
|
|
|
|
|
15
|
my $i = 0; |
1248
|
2
|
|
|
|
|
6
|
my $m = 3; |
1249
|
2
|
|
|
|
|
27
|
while ($m <= $mroot) { |
1250
|
2736
|
100
|
|
|
|
5735
|
if ($s[$i]) { |
1251
|
796
|
|
|
|
|
2587
|
for (my $j = int(($m * $m - 3) / 2); $j < $half; $j += $m) { |
1252
|
13244400
|
|
|
|
|
24848962
|
$s[$j] = 0; |
1253
|
|
|
|
|
|
|
} |
1254
|
|
|
|
|
|
|
} |
1255
|
2736
|
|
|
|
|
3701
|
$i++; |
1256
|
2736
|
|
|
|
|
5679
|
$m = 2 * $i + 3; |
1257
|
|
|
|
|
|
|
} |
1258
|
|
|
|
|
|
|
|
1259
|
2
|
|
|
|
|
655628
|
return 2, grep($_, @s); |
1260
|
|
|
|
|
|
|
} |
1261
|
|
|
|
|
|
|
|
1262
|
|
|
|
|
|
|
# Fix for Crypt::JWT that was submitted as a patch. Will remove if it is merged. |
1263
|
|
|
|
|
|
|
sub _decode_jwt2 { |
1264
|
501
|
|
|
501
|
|
1915
|
my %args = @_; |
1265
|
501
|
|
|
|
|
934
|
my ($header, $payload); |
1266
|
|
|
|
|
|
|
|
1267
|
501
|
100
|
|
|
|
9726
|
if ($args{token} =~ |
1268
|
|
|
|
|
|
|
/^([a-zA-Z0-9_-]+)=*\.([a-zA-Z0-9_-]*)=*\.([a-zA-Z0-9_-]*)=*(?:\.([a-zA-Z0-9_-]+)=*\.([a-zA-Z0-9_-]+)=*)?$/ |
1269
|
|
|
|
|
|
|
) { |
1270
|
500
|
50
|
|
|
|
2191
|
if (length($5)) { |
1271
|
|
|
|
|
|
|
# JWE token (5 segments) |
1272
|
0
|
|
|
|
|
0
|
($header, $payload) = |
1273
|
|
|
|
|
|
|
Crypt::JWT::_decode_jwe($1, $2, $3, $4, $5, undef, {}, {}, |
1274
|
|
|
|
|
|
|
%args); |
1275
|
|
|
|
|
|
|
} else { |
1276
|
|
|
|
|
|
|
# JWS token (3 segments) |
1277
|
500
|
|
|
|
|
2463
|
($header, $payload) = |
1278
|
|
|
|
|
|
|
Crypt::JWT::_decode_jws($1, $2, $3, {}, %args); |
1279
|
|
|
|
|
|
|
} |
1280
|
|
|
|
|
|
|
} |
1281
|
501
|
100
|
|
|
|
2050748
|
return ($header, $payload) if $args{decode_header}; |
1282
|
500
|
|
|
|
|
1804
|
return $payload; |
1283
|
|
|
|
|
|
|
} |
1284
|
|
|
|
|
|
|
|
1285
|
|
|
|
|
|
|
sub _get_time { |
1286
|
45
|
50
|
|
45
|
|
509
|
return $mono_clock ? Time::HiRes::clock_gettime(CLOCK_MONOTONIC) : Time::HiRes::time(); |
1287
|
|
|
|
|
|
|
} |
1288
|
|
|
|
|
|
|
|
1289
|
|
|
|
|
|
|
# Helper package for Moose benchmark |
1290
|
|
|
|
|
|
|
|
1291
|
|
|
|
|
|
|
{ |
1292
|
|
|
|
|
|
|
package Benchmark::DKbench::MooseTree; |
1293
|
|
|
|
|
|
|
|
1294
|
3
|
|
|
3
|
|
2030
|
use Moose; |
|
3
|
|
|
|
|
1335921
|
|
|
3
|
|
|
|
|
21
|
|
1295
|
|
|
|
|
|
|
|
1296
|
|
|
|
|
|
|
has 'price' => (is => 'rw', default => 10); |
1297
|
|
|
|
|
|
|
has 'tax' => (is => 'rw', lazy_build => 1); |
1298
|
|
|
|
|
|
|
has 'node' => (is => 'rw', isa => 'Any'); |
1299
|
|
|
|
|
|
|
has 'parent' => ( |
1300
|
|
|
|
|
|
|
is => 'rw', |
1301
|
|
|
|
|
|
|
isa => 'Benchmark::DKbench::MooseTree', |
1302
|
|
|
|
|
|
|
predicate => 'has_parent', |
1303
|
|
|
|
|
|
|
weak_ref => 1, |
1304
|
|
|
|
|
|
|
); |
1305
|
|
|
|
|
|
|
has 'left' => ( |
1306
|
|
|
|
|
|
|
is => 'rw', |
1307
|
|
|
|
|
|
|
isa => 'Benchmark::DKbench::MooseTree', |
1308
|
|
|
|
|
|
|
predicate => 'has_left', |
1309
|
|
|
|
|
|
|
lazy => 1, |
1310
|
|
|
|
|
|
|
builder => '_build_child_tree', |
1311
|
|
|
|
|
|
|
); |
1312
|
|
|
|
|
|
|
has 'right' => ( |
1313
|
|
|
|
|
|
|
is => 'rw', |
1314
|
|
|
|
|
|
|
isa => 'Benchmark::DKbench::MooseTree', |
1315
|
|
|
|
|
|
|
predicate => 'has_right', |
1316
|
|
|
|
|
|
|
lazy => 1, |
1317
|
|
|
|
|
|
|
builder => '_build_child_tree', |
1318
|
|
|
|
|
|
|
); |
1319
|
|
|
|
|
|
|
before 'right', 'left' => sub { |
1320
|
|
|
|
|
|
|
my ($self, $tree) = @_; |
1321
|
|
|
|
|
|
|
$tree->parent($self) if defined $tree; |
1322
|
|
|
|
|
|
|
}; |
1323
|
|
|
|
|
|
|
|
1324
|
|
|
|
|
|
|
sub _build_tax { |
1325
|
50000
|
|
|
50000
|
|
80542
|
my $self = shift; |
1326
|
50000
|
|
|
|
|
1295193
|
$self->price * 0.2; |
1327
|
|
|
|
|
|
|
} |
1328
|
|
|
|
|
|
|
|
1329
|
|
|
|
|
|
|
sub _build_child_tree { |
1330
|
40000
|
|
|
40000
|
|
67233
|
my $self = shift; |
1331
|
40000
|
|
|
|
|
122664
|
return Benchmark::DKbench::MooseTree->new( parent => $self ); |
1332
|
|
|
|
|
|
|
} |
1333
|
|
|
|
|
|
|
|
1334
|
|
|
|
|
|
|
sub cost { |
1335
|
40000
|
|
|
40000
|
0
|
74290
|
my $self = shift; |
1336
|
40000
|
|
|
|
|
1058856
|
$self->price + $self->tax; |
1337
|
|
|
|
|
|
|
} |
1338
|
|
|
|
|
|
|
} |
1339
|
|
|
|
|
|
|
|
1340
|
|
|
|
|
|
|
1; |