1#!/usr/bin/perl
2
3# Check the functionality of the Porting/bench.pl executable;
4# in particular, its argument handling and its ability to produce
5# the expected output for particular arguments.
6#
7# See also t/porting/bench_selftest.pl
8
9BEGIN {
10    chdir '..' if -f 'test.pl';
11    @INC = ( './lib' );
12    require './t/test.pl';
13}
14
15use warnings;
16use strict;
17use Config;
18
19
20# Only test on git checkouts - this is more of a perl core developer
21# tool than an end-user tool.
22# Only test on a platform likely to support forking, pipes, cachegrind
23# etc.  Add other platforms if you think they're safe.
24
25skip_all "not devel"   unless -d "./.git";
26skip_all "not linux"   unless $^O eq 'linux';
27skip_all "no valgrind" unless -x '/bin/valgrind' || -x '/usr/bin/valgrind';
28# Address sanitizer clashes horribly with cachegrind
29skip_all "not with ASAN" if $Config{ccflags} =~ /sanitize=address/;
30skip_all "cachegrind broken" if system "( ulimit -c 0; valgrind -q --tool=cachegrind --cachegrind-out-file=/dev/null $^X -e0 ) 2>/dev/null";
31
32
33my $bench_pl = "Porting/bench.pl";
34
35ok -e $bench_pl, "$bench_pl exists and is executable";
36
37my $bench_cmd = "$^X -Ilib $bench_pl";
38
39my ($out, $cmd);
40
41# Read in the expected output format templates and create qr//s from them.
42
43my %formats;
44my %format_qrs;
45
46{
47    my $cur;
48    while (<DATA>) {
49        next if /^#/;
50        if (/^FORMAT:/) {
51            die "invalid format line: $_" unless /^FORMAT:\s+(\w+)\s*$/;
52            $cur = $1;
53            die "duplicate format: '$cur'\n" if exists $formats{$cur};
54            next;
55        }
56        $formats{$cur} .= $_;
57    }
58
59    for my $name (sort keys %formats) {
60        my $f = $formats{$name};
61
62        # expand "%%SUB_FORMAT%%
63        $f =~ s{^ \s* %% (\w+) %% [ \t]* \n}
64               {
65                    my $f1 = $formats{$1};
66                    die "No such sub-format '%%$1%%' in format '$name'\n"
67                        unless defined $f1;
68                    $f1;
69               }gmxe;
70
71        $f = quotemeta $f;
72
73        # convert NNNN.NN placeholders into a regex
74        $f =~ s{(N+)\\.(N+)}
75               {
76                    my $l = length($2);
77                    "("
78                    . "\\s*-?\\d+\\."
79                    . "\\d" x $l
80                    ."|\\s*-)"
81               }ge;
82
83        # convert run of space chars into ' +' or ' *'
84
85        $f =~ s/(\A|\n)(\\ )+/$1 */g;
86        $f =~ s/(\\ )+/ +/g;
87
88        # convert '---' placeholders into a regex
89        $f =~ s/(\\-){2,}/-+/g;
90
91        $format_qrs{$name} = qr/\A$f\z/;
92    }
93}
94
95
96# ---------------------------------------------------
97# check croaks
98
99for my $test (
100    [
101        "--boz",
102        "Unknown option: boz\nUse the -h option for usage information.\n",
103        "croak: basic unknown option"
104    ],
105    [
106        "--fields=Ir,Boz",
107        "Error: --fields: unknown field 'Boz'\n",
108        "croak: unknown --field"
109    ],
110    [
111        "--action=boz",
112        "Error: unrecognised action 'boz'\nmust be one of: grind, selftest\n",
113        "croak: unknown --action"
114    ],
115    [
116        "--sort=boz",
117        "Error: --sort argument should be of the form field:perl: 'boz'\n",
118        "croak: invalid --sort"
119    ],
120    [
121        "--sort=boz:perl",
122        "Error: --sort: unknown field 'boz'\n",
123        "croak: unknown --sort field"
124    ],
125    [
126        "-action=selftest perl",
127        "Error: no perl executables may be specified with selftest\n",
128        "croak: --action-selftest with executable"
129    ],
130    [
131        "--tests=/boz perl",
132        "Error: --tests regex must be of the form /.../\n",
133        "croak: invalid --tests regex"
134    ],
135    [
136        "--tests=call::sub::empty,foo::bar::baz::boz perl",
137          "Error: no such test found: 'foo::bar::baz::boz'\n"
138        . "Re-run with --verbose for a list of valid tests.\n",
139        "croak: unknown test in --tests"
140    ],
141    [
142        "--verbose --tests=call::sub::empty,foo::bar::baz::boz --read=t/porting/bench/callsub.json",
143            "Error: no such test found: 'foo::bar::baz::boz'\n"
144          . "Valid test names are:\n"
145          . "  call::sub::amp_empty\n"
146          . "  call::sub::empty\n",
147        "croak: unknown test in --tests --verbose"
148    ],
149    [
150        "--tests=/foo::bar::baz::boz/ perl",
151        "Error: no tests to run\n",
152        "croak: no --tests to run "
153    ],
154    [
155        "--benchfile=no-such-file-boz perl",
156        qr/\AError: can't read 'no-such-file-boz':/,
157        "croak: non-existent --benchfile "
158    ],
159    [
160        "--benchfile=t/porting/bench/synerr perl",
161        qr{\AError: can't parse 't/porting/bench/synerr':\nsyntax error},
162        "croak: --benchfile with syntax error"
163    ],
164    [
165        "--benchfile=t/porting/bench/ret0 perl",
166        "Error: can't load 't/porting/bench/ret0': code didn't return a true value\n",
167        "croak: --benchfile which returns 0"
168    ],
169    [
170        "--benchfile=t/porting/bench/oddentry perl",
171        qr{\AError: 't/porting/bench/oddentry' does not contain evenly paired test names and hashes\n},
172        "croak: --benchfile with odd number of entries"
173    ],
174    [
175        "--benchfile=t/porting/bench/badname perl",
176        qr{\AError: 't/porting/bench/badname': invalid test name: '1='\n},
177        "croak: --benchfile with invalid test name"
178    ],
179    [
180        "--benchfile=t/porting/bench/badhash perl",
181        qr{\AError: 't/porting/bench/badhash': invalid key 'blah' for test 'foo::bar'\n},
182        "croak: --benchfile with invalid test hash key"
183    ],
184    [
185        "--norm=2 ./miniperl ./perl",
186        "Error: --norm value 2 outside range 0..1\n",
187        "croak: select-a-perl out of range"
188    ],
189    [
190        "--norm=-0 ./miniperl ./perl",
191        "Error: --norm value -0 outside range -1..-2\n",
192        "croak: select-a-perl out of range"
193    ],
194    [
195        "--norm=-3 ./miniperl ./perl",
196        "Error: --norm value -3 outside range -1..-2\n",
197        "croak: select-a-perl out of range"
198    ],
199    [
200        "--sort=Ir:myperl ./miniperl ./perl",
201        "Error: --sort: unrecognised perl 'myperl'\n"
202        . "Valid perl names are:\n"
203        . "    ./miniperl\n"
204        . "    ./perl\n",
205        "croak: select-a-perl unrecognised"
206    ],
207    [
208        "--compact=./perl ./perl=A ./perl=B",
209        "Error: --compact: ambiguous perl './perl'\n",
210        "croak: select-a-perl ambiguous"
211    ],
212    [
213        "./perl --foo",
214        "Error: unrecognised executable switch '--foo'\n",
215        "croak: ./perl --foo"
216    ],
217    [
218        "-- --args=foo",
219        "Error: --args without a preceding executable name\n",
220        "croak: --args without perl"
221    ],
222    [
223        "-- --env=foo=bar",
224        "Error: --env without a preceding executable name\n",
225        "croak: --env without perl"
226    ],
227    [
228        "./perl --args",
229        "Error: --args is missing value\n",
230        "croak: --args without value"
231    ],
232    [
233        "./perl --env",
234        "Error: --env is missing value\n",
235        "croak: --env without value"
236    ],
237    [
238        "./perl --env='FOO'",
239        "Error: --env is missing =value\n",
240        "croak: --env without =value"
241    ],
242    [
243        "./perl ./perl",
244        "Error: duplicate label './perl': each executable must have a unique label\n",
245        "croak: duplicate label ./perl ./perl"
246    ],
247    [
248        "./perl=A ./miniperl=A",
249        "Error: duplicate label 'A': each executable must have a unique label\n",
250        "croak: duplicate label =A =A"
251    ],
252    [
253        "--read=t/porting/bench/callsub.json --read=t/porting/bench/callsub.json",
254        "Error: duplicate label './perl': seen in file 't/porting/bench/callsub.json'\n",
255        "croak: duplicate label --read=... --read=..."
256    ],
257    [
258        "--read=t/porting/bench/callsub.json ./perl",
259        "Error: duplicate label './perl': seen both in --read file and on command line\n",
260        "croak: duplicate label --read=... ./perl"
261    ],
262    [
263        "./nosuch-perl",
264        qr{^\QError: unable to execute './nosuch-perl': },
265        "croak:  no such perl"
266    ],
267    [
268        "--grindargs=Boz --debug --tests=call::sub::empty ./perl=A ./perl=B",
269        qr{Error: .*?(unexpected code or cachegrind output|gave return status)}s,
270        "croak: cachegrind output format "
271    ],
272    [
273        "--bisect=Ir",,
274        "Error: --bisect option must be of form 'field,integer,integer'\n",
275        "croak: --bisect=Ir"
276    ],
277    [
278        "--bisect=Ir,1",,
279        "Error: --bisect option must be of form 'field,integer,integer'\n",
280        "croak: --bisect=Ir,1"
281    ],
282    [
283        "--bisect=Ir,1,2,3",
284        "Error: --bisect option must be of form 'field,integer,integer'\n",
285        "croak: --bisect=Ir,1,2,3"
286    ],
287    [
288        "--bisect=Ir,1,x",
289        "Error: --bisect option must be of form 'field,integer,integer'\n",
290        "croak: --bisect=Ir,1,x"
291    ],
292    [
293        "--bisect=Ir,x,2",
294        "Error: --bisect option must be of form 'field,integer,integer'\n",
295        "croak: --bisect=Ir,x,2"
296    ],
297    [
298        "--bisect=boz,1,2",
299        "Error: unrecognised field 'boz' in --bisect option\n",
300        "croak: --bisect=boz,1,2"
301    ],
302    [
303        "--bisect=Ir,2,1",
304        "Error: --bisect min (2) must be <= max (1)\n",
305        "croak: --bisect=boz,2,1"
306    ],
307    [
308        "--read=no-such-file-boz",
309        qr/\AError: can't open 'no-such-file-boz' for reading:/,
310        "croak: non-existent --read file "
311    ],
312    [
313        "--read=t/porting/bench/badversion.json",
314        "Error: unsupported version 9999.9 in file 't/porting/bench/badversion.json' (too new)\n",
315        "croak: --read version"
316    ],
317    [
318        "--read=t/porting/bench/callsub.json --benchfile=t/perf/benchmarks ./perl ",
319        "Error: --benchfile cannot be used when --read is present\n",
320        "croak: benchfile with read"
321    ],
322    [
323        "",
324        "Error: nothing to do: no perls to run, no data to read.\n",
325        "croak: no input"
326    ],
327    [
328        "./perl",
329        "Error: need at least 2 perls for comparison.\n",
330        "croak: need 2 perls"
331    ],
332    [
333        "--bisect=Ir,1,2 ./perl=A ./perl=B",
334        "Error: exactly one perl executable must be specified for bisect\n",
335        "croak: --bisect, need 1 perls"
336    ],
337    [
338        "--bisect=Ir,1,2 --tests=/call/ ./perl=A",
339        "Error: only a single test may be specified with --bisect\n",
340        "croak: --bisect one test only"
341    ],
342    # note that callsub.json was created using
343    # ./perl -Ilib Porting/bench.pl --tests='/call::sub::(amp_)?empty/' \
344    #                     --write=t/porting/bench/callsub.json ./perl
345    [
346        "--read=t/porting/bench/callsub.json --write=no/such/file/boz",
347        qr{\AError: can't open 'no/such/file/boz' for writing: },
348        "croak: --write open error"
349    ],
350    # note that callsub2.json was created using
351    # ./perl -Ilib Porting/bench.pl \
352    #    --tests='call::sub::empty,call::sub::args3' \
353    #                     --write=t/porting/bench/callsub2.json ./perl=perl2
354    [
355           "--read=t/porting/bench/callsub.json "
356        . " --read=t/porting/bench/callsub2.json",
357        "Can't merge multiple read files: they contain differing test sets.\n"
358        . "Re-run with --verbose to see the differences.\n",
359        "croak: --read callsub, callsub2"
360    ],
361    [
362           "--read=t/porting/bench/callsub.json "
363        . " --read=t/porting/bench/callsub2.json"
364        . " --verbose",
365        "Can't merge multiple read files: they contain differing test sets.\n"
366        . "Previous tests:\n"
367        . "  call::sub::amp_empty\n"
368        . "  call::sub::empty\n"
369        . "tests from 't/porting/bench/callsub2.json':\n"
370        . "  call::sub::args3\n"
371        . "  call::sub::empty\n",
372        "croak: --read callsub, callsub2 --verbose"
373    ],
374
375    # these ones aren't tested (and nor are any "Panic:" ones):
376
377    # Error: can't parse '$field' field from cachegrind output
378    # Error: while starting cachegrind subprocess for NNNN:
379    # File '$file' contains no results
380    # File '$file' contains differing test and results names
381    # File '$file' contains differing test and sort order names
382    # Can't merge multiple read files: differing loop counts:
383)
384{
385    my ($args, $expected, $desc) = @$test;
386    $out = qx($bench_cmd $args 2>&1);
387    if (ref($expected)) {
388        like $out, $expected, $desc;
389    }
390    else {
391        is $out, $expected, $desc;
392    }
393}
394
395# ---------------------------------------------------
396# run benchmarks
397
398
399my $resultfile1 = tempfile(); # benchmark results for 1 perl
400my $resultfile2 = tempfile(); # benchmark results for 2 perls
401
402# Run a real cachegrind session and write results to file.
403# the -j 2 is to minimally exercise its parallel facility.
404
405note("running cachegrind for 1st perl; may be slow...");
406$out = qx($bench_cmd -j 2 --write=$resultfile1 --tests=call::sub::empty $^X=p0 2>&1);
407is $out, "", "--write should produce no output (1 perl)";
408ok -s $resultfile1, "--write should create a non-empty results file (1 perl)";
409
410# and again with 2 perls. This is also tests the 'mix read and new new
411# perls' functionality.
412
413note("running cachegrind for 2nd perl; may be slow...");
414$out = qx($bench_cmd -j 2 --read=$resultfile1 --write=$resultfile2 $^X=p1 2>&1);
415is $out, "", "--write should produce no output (2 perls)"
416    or diag("got: $out");
417ok -s $resultfile2, "--write should create a non-empty results file (2 perls)";
418
419# 1 perl:
420
421# read back the results in raw form
422
423$out = qx($bench_cmd --read=$resultfile1 --raw 2>&1);
424like $out, $format_qrs{raw1}, "basic cachegrind raw format; 1 perl";
425
426# and read back the results in raw compact form
427
428$out = qx($bench_cmd --read=$resultfile1 --raw --compact=0 2>&1);
429like $out, $format_qrs{raw_compact}, "basic cachegrind raw compact format; 1 perl";
430
431# and read back the results in raw average form
432
433$out = qx($bench_cmd --read=$resultfile1 --raw --average 2>&1);
434like $out, $format_qrs{raw_average1}, "basic cachegrind raw average format; 1 perl";
435
436# and read back the results with raw selected fields
437
438$out = qx($bench_cmd --read=$resultfile1 --raw --fields=Ir,Dr 2>&1);
439like $out, $format_qrs{fields1}, "basic cachegrind --fields; 1 perl";
440
441# 2 perls:
442
443# read back the results in relative-percent form
444
445$out = qx($bench_cmd --read=$resultfile2 2>&1);
446like $out, $format_qrs{percent2}, "basic cachegrind percent format; 2 perls";
447
448# read back the results in relative-percent form with norm
449
450$out = qx($bench_cmd --read=$resultfile2 --norm=0 2>&1);
451like $out, $format_qrs{percent2}, "basic cachegrind percent format, norm; 2 perls";
452
453# ditto with negative norm
454
455$out = qx($bench_cmd --read=$resultfile2 --norm=-2 2>&1);
456like $out, $format_qrs{percent2}, "basic cachegrind percent format, norm -2; 2 perls";
457
458# read back the results in relative-percent form with sort
459
460$out = qx($bench_cmd --read=$resultfile2 --sort=Ir:0 2>&1);
461like $out, $format_qrs{percent2}, "basic cachegrind percent format, sort; 2 perls";
462
463# read back the results in relative-percent form with sort and norm
464
465$out = qx($bench_cmd --read=$resultfile2 --sort=Ir:0 --norm=0 2>&1);
466like $out, $format_qrs{percent2}, "basic cachegrind percent format, sort, norm; 2 perls";
467
468# and read back the results in raw form
469
470$out = qx($bench_cmd --read=$resultfile2 --raw 2>&1);
471like $out, $format_qrs{raw2}, "basic cachegrind raw format; 2 perls";
472
473# and read back the results in raw form with norm
474
475$out = qx($bench_cmd --read=$resultfile2 --raw --norm=0 2>&1);
476like $out, $format_qrs{raw2}, "basic cachegrind raw format, norm; 2 perls";
477
478# and read back the results in raw form with sort
479
480$out = qx($bench_cmd --read=$resultfile2 --raw --sort=Ir:0 2>&1);
481like $out, $format_qrs{raw2}, "basic cachegrind raw format, sort, norm; 2 perls";
482
483# and read back the results in raw form with sort and norm
484
485$out = qx($bench_cmd --read=$resultfile2 --raw --sort=Ir:0 --norm=0 2>&1);
486like $out, $format_qrs{raw2}, "basic cachegrind raw format, sort, norm; 2 perls";
487
488# and read back the results in compact form
489
490$out = qx($bench_cmd --read=$resultfile2 --compact=1 2>&1);
491like $out, $format_qrs{compact}, "basic cachegrind compact format; 2 perls";
492
493# and read back the results in average form
494
495$out = qx($bench_cmd --read=$resultfile2 --average 2>&1);
496like $out, $format_qrs{average}, "basic cachegrind average format; 2 perls";
497
498# and read back the results with selected fields
499
500$out = qx($bench_cmd --read=$resultfile2 --fields=Ir,Dr 2>&1);
501like $out, $format_qrs{fields2}, "basic cachegrind --fields; 2 perls";
502
503# and read back the results in compact form with selected fields
504
505$out = qx($bench_cmd --read=$resultfile2 --compact=1  --fields=Ir,Dr 2>&1);
506like $out, $format_qrs{compact_fields}, "basic cachegrind compact, fields; 2 perls";
507
508# and read back the results with 1 selected fields (this is more compact)
509
510$out = qx($bench_cmd --read=$resultfile2 --fields=Ir 2>&1);
511like $out, $format_qrs{'1field'}, "basic cachegrind 1 field; 2 perls";
512
513
514# bisect
515
516# the Ir range here is intended such that the bisect will always fail
517$out = qx($bench_cmd --read=t/porting/bench/callsub.json --tests=call::sub::empty --bisect=Ir,100000,100001 2>&1);
518
519is $?, 1 << 8, "--bisect: exit result: should not match";
520like $out, qr/^Bisect: Ir had the value -?\d+\n/,
521        "--bisect: got expected output";
522
523# multiple reads with differing test sets but common --tests subset
524
525$out = qx($bench_cmd --read=t/porting/bench/callsub.json  --read=t/porting/bench/callsub2.json --tests=call::sub::empty 2>&1);
526$out =~ s{\Q./perl  perl2}{    p0     p1};
527$out =~ s{^\./perl}{p0}m;
528like $out, $format_qrs{percent2}, "2 reads; overlapping test sets";
529
530# A read defines what benchmarks to run
531
532note("running cachegrind on 1 perl; may be slow...");
533$out = qx($bench_cmd --read=t/porting/bench/callsub.json --tests=call::sub::empty $^X=p1 2>&1);
534$out =~ s{^\./perl}{p0}m;
535$out =~ s{\Q./perl}{    p0};
536like $out, $format_qrs{percent2}, "1 read; 1 generate";
537
538# Process environment and optional args.
539# This is a minimal test that it runs - it doesn't test whether
540# the environment and args are getting applied correctly, apart from the
541# fact that the perls in question are being successfully executed.
542#
543# Also check the --autolabel feature
544
545note("running cachegrind on 2 perls; may be slow...");
546$cmd = <<EOF;
547$bench_cmd
548    --read=t/porting/bench/callsub.json
549    --read=t/porting/bench/callsub2.json
550    --tests=call::sub::empty
551    --autolabel
552    --perlargs=-Ilib
553    $^X --args='-Ifoo/bar -Mstrict' --env='FOO=foo'
554    $^X --args='-Ifoo/bar'          --env='BAR=bar' --env='BAZ=baz'
555    2>&1
556EOF
557$cmd =~ s/\n\s+/ /g;
558$out = qx($cmd);
559$out =~ s{^\./perl}{p0}m;
560$out =~ s{\Q       ./perl  perl2    p-0    p-1}
561         {           p0     p1     p2     p3};
562like $out, $format_qrs{percent4}, "4 perls with autolabel and args and env";
563
564
565done_testing();
566
567
568# Templates for expected output formats.
569#
570# Lines starting with '#' are skipped.
571#
572# Lines of the form 'FORMAT: foo' start and name a new template
573#
574# All other lines are part of the template
575#
576# Entries of the form NNNN.NN are converted into a regex of the form
577#    ( \s* -? \d+\.\d\d | - )
578# i.e. it expects number with a fixed number of digits after the point,
579# or a '-'.
580#
581# Any runs of space chars (but not tab) are converted into ' +',
582# or ' *' if at the start of a line
583#
584# Entries of the form --- are converted into [-]+
585#
586# Lines of the form %%FOO%% are substituted with format 'FOO'
587
588
589__END__
590# ===================================================================
591FORMAT: STD_HEADER
592Key:
593    Ir   Instruction read
594    Dr   Data read
595    Dw   Data write
596    COND conditional branches
597    IND  indirect branches
598    _m   branch predict miss
599    _m1  level 1 cache miss
600    _mm  last cache (e.g. L3) miss
601    -    indeterminate percentage (e.g. 1/0)
602# ===================================================================
603FORMAT: percent2
604%%STD_HEADER%%
605
606The numbers represent relative counts per loop iteration, compared to
607p0 at 100.0%.
608Higher is better: for example, using half as many instructions gives 200%,
609while using twice as many gives 50%.
610
611call::sub::empty
612function call with no args or body
613
614           p0     p1
615       ------ ------
616    Ir 100.00 NNN.NN
617    Dr 100.00 NNN.NN
618    Dw 100.00 NNN.NN
619  COND 100.00 NNN.NN
620   IND 100.00 NNN.NN
621
622COND_m 100.00 NNN.NN
623 IND_m 100.00 NNN.NN
624
625 Ir_m1 100.00 NNN.NN
626 Dr_m1 100.00 NNN.NN
627 Dw_m1 100.00 NNN.NN
628
629 Ir_mm 100.00 NNN.NN
630 Dr_mm 100.00 NNN.NN
631 Dw_mm 100.00 NNN.NN
632# ===================================================================
633FORMAT: percent4
634%%STD_HEADER%%
635
636The numbers represent relative counts per loop iteration, compared to
637p0 at 100.0%.
638Higher is better: for example, using half as many instructions gives 200%,
639while using twice as many gives 50%.
640
641call::sub::empty
642function call with no args or body
643
644           p0     p1     p2     p3
645       ------ ------ ------ ------
646    Ir 100.00 NNN.NN NNN.NN NNN.NN
647    Dr 100.00 NNN.NN NNN.NN NNN.NN
648    Dw 100.00 NNN.NN NNN.NN NNN.NN
649  COND 100.00 NNN.NN NNN.NN NNN.NN
650   IND 100.00 NNN.NN NNN.NN NNN.NN
651
652COND_m 100.00 NNN.NN NNN.NN NNN.NN
653 IND_m 100.00 NNN.NN NNN.NN NNN.NN
654
655 Ir_m1 100.00 NNN.NN NNN.NN NNN.NN
656 Dr_m1 100.00 NNN.NN NNN.NN NNN.NN
657 Dw_m1 100.00 NNN.NN NNN.NN NNN.NN
658
659 Ir_mm 100.00 NNN.NN NNN.NN NNN.NN
660 Dr_mm 100.00 NNN.NN NNN.NN NNN.NN
661 Dw_mm 100.00 NNN.NN NNN.NN NNN.NN
662# ===================================================================
663FORMAT: fields2
664%%STD_HEADER%%
665
666The numbers represent relative counts per loop iteration, compared to
667p0 at 100.0%.
668Higher is better: for example, using half as many instructions gives 200%,
669while using twice as many gives 50%.
670
671call::sub::empty
672function call with no args or body
673
674           p0     p1
675       ------ ------
676    Ir 100.00 NNN.NN
677    Dr 100.00 NNN.NN
678# ===================================================================
679FORMAT: raw1
680%%STD_HEADER%%
681
682The numbers represent raw counts per loop iteration.
683
684call::sub::empty
685function call with no args or body
686
687             p0
688       --------
689    Ir NNNNNN.N
690    Dr NNNNNN.N
691    Dw NNNNNN.N
692  COND NNNNNN.N
693   IND NNNNNN.N
694
695COND_m NNNNNN.N
696 IND_m NNNNNN.N
697
698 Ir_m1 NNNNNN.N
699 Dr_m1 NNNNNN.N
700 Dw_m1 NNNNNN.N
701
702 Ir_mm NNNNNN.N
703 Dr_mm NNNNNN.N
704 Dw_mm NNNNNN.N
705# ===================================================================
706FORMAT: raw_average1
707%%STD_HEADER%%
708
709The numbers represent raw counts per loop iteration.
710
711AVERAGE
712
713             p0
714       --------
715    Ir NNNNNN.N
716    Dr NNNNNN.N
717    Dw NNNNNN.N
718  COND NNNNNN.N
719   IND NNNNNN.N
720
721COND_m NNNNNN.N
722 IND_m NNNNNN.N
723
724 Ir_m1 NNNNNN.N
725 Dr_m1 NNNNNN.N
726 Dw_m1 NNNNNN.N
727
728 Ir_mm NNNNNN.N
729 Dr_mm NNNNNN.N
730 Dw_mm NNNNNN.N
731# ===================================================================
732FORMAT: fields1
733%%STD_HEADER%%
734
735The numbers represent raw counts per loop iteration.
736
737call::sub::empty
738function call with no args or body
739
740             p0
741       --------
742    Ir NNNNNN.N
743    Dr NNNNNN.N
744# ===================================================================
745FORMAT: raw2
746%%STD_HEADER%%
747
748The numbers represent raw counts per loop iteration.
749
750call::sub::empty
751function call with no args or body
752
753             p0       p1
754       -------- --------
755    Ir NNNNNN.N NNNNNN.N
756    Dr NNNNNN.N NNNNNN.N
757    Dw NNNNNN.N NNNNNN.N
758  COND NNNNNN.N NNNNNN.N
759   IND NNNNNN.N NNNNNN.N
760
761COND_m NNNNNN.N NNNNNN.N
762 IND_m NNNNNN.N NNNNNN.N
763
764 Ir_m1 NNNNNN.N NNNNNN.N
765 Dr_m1 NNNNNN.N NNNNNN.N
766 Dw_m1 NNNNNN.N NNNNNN.N
767
768 Ir_mm NNNNNN.N NNNNNN.N
769 Dr_mm NNNNNN.N NNNNNN.N
770 Dw_mm NNNNNN.N NNNNNN.N
771# ===================================================================
772FORMAT: compact
773%%STD_HEADER%%
774
775The numbers represent relative counts per loop iteration, compared to
776p0 at 100.0%.
777Higher is better: for example, using half as many instructions gives 200%,
778while using twice as many gives 50%.
779
780Results for p1
781
782     Ir     Dr     Dw   COND    IND COND_m  IND_m  Ir_m1  Dr_m1  Dw_m1  Ir_mm  Dr_mm  Dw_mm
783 ------ ------ ------ ------ ------ ------ ------ ------ ------ ------ ------ ------ ------
784 NNN.NN NNN.NN NNN.NN NNN.NN NNN.NN NNN.NN NNN.NN NNN.NN NNN.NN NNN.NN NNN.NN NNN.NN NNN.NN  call::sub::empty   function call with no args or body
785# ===================================================================
786FORMAT: compact_fields
787%%STD_HEADER%%
788
789The numbers represent relative counts per loop iteration, compared to
790p0 at 100.0%.
791Higher is better: for example, using half as many instructions gives 200%,
792while using twice as many gives 50%.
793
794Results for p1
795
796     Ir     Dr
797 ------ ------
798 NNN.NN NNN.NN  call::sub::empty   function call with no args or body
799# ===================================================================
800FORMAT: 1field
801%%STD_HEADER%%
802
803The numbers represent relative counts per loop iteration, compared to
804p0 at 100.0%.
805Higher is better: for example, using half as many instructions gives 200%,
806while using twice as many gives 50%.
807
808Results for field Ir
809
810                     p0     p1
811                 ------ ------
812call::sub::empty NNN.NN NNN.NN
813# ===================================================================
814FORMAT: average
815%%STD_HEADER%%
816
817The numbers represent relative counts per loop iteration, compared to
818p0 at 100.0%.
819Higher is better: for example, using half as many instructions gives 200%,
820while using twice as many gives 50%.
821
822AVERAGE
823
824           p0     p1
825       ------ ------
826    Ir 100.00 NNN.NN
827    Dr 100.00 NNN.NN
828    Dw 100.00 NNN.NN
829  COND 100.00 NNN.NN
830   IND 100.00 NNN.NN
831
832COND_m 100.00 NNN.NN
833 IND_m 100.00 NNN.NN
834
835 Ir_m1 100.00 NNN.NN
836 Dr_m1 100.00 NNN.NN
837 Dw_m1 100.00 NNN.NN
838
839 Ir_mm 100.00 NNN.NN
840 Dr_mm 100.00 NNN.NN
841 Dw_mm 100.00 NNN.NN
842# ===================================================================
843FORMAT: raw_compact
844%%STD_HEADER%%
845
846The numbers represent raw counts per loop iteration.
847
848Results for p0
849
850      Ir      Dr      Dw    COND     IND  COND_m   IND_m   Ir_m1   Dr_m1   Dw_m1   Ir_mm   Dr_mm   Dw_mm
851  ------  ------  ------  ------  ------  ------  ------  ------  ------  ------  ------  ------  ------
852 NNNNN.N NNNNN.N NNNNN.N NNNNN.N NNNNN.N NNNNN.N NNNNN.N NNNNN.N NNNNN.N NNNNN.N NNNNN.N NNNNN.N NNNNN.N  call::sub::empty   function call with no args or body
853# ===================================================================
854