File Coverage

blib/lib/Surveyor/App.pm
Criterion Covered Total %
statement 17 48 35.4
branch 0 12 0.0
condition n/a
subroutine 6 10 60.0
pod 3 3 100.0
total 26 73 35.6


line stmt bran cond sub pod time code
1 1     1   602 use v5.14;
  1         3  
2              
3             package Surveyor::App;
4 1     1   18 use strict;
  1         2  
  1         17  
5 1     1   4 use warnings;
  1         2  
  1         88  
6              
7             our $VERSION = '0.123';
8              
9             =encoding utf8
10              
11             =head1 NAME
12              
13             Surveyor::App - Run benchmarks from a package
14              
15             =head1 SYNOPSIS
16              
17             use Surveyor::App;
18              
19             =head1 DESCRIPTION
20              
21             C provides a minimal framework and convention for
22             people to distribute benchmarks. By creating a package in a special
23             way, you can easily share your benchmarks with people without having
24             to repeat a lot of code.
25              
26             First, if you want to do some setup before your benchmarks run, define
27             a C method. Do whatever you need there, such as setting
28             environment variables, changing directories, and so on. The C
29             method gets the command-line arguments you specified when you run
30             C, save for any that C used for itself.
31              
32             Next, define your benchmarks in subroutines whose names start with
33             C. Surveyor::App will find each of those, using the part of
34             the name after C as the label for that test.
35              
36             Last, if you want to do some setup before your benchmarks run, define
37             a C method. The C method gets no arguments.
38              
39             Your benchmarking package doesn't have to have any particular name and
40             it doesn't need to subclass or C this package. See
41             L for an example.
42              
43             =over 4
44              
45             =cut
46              
47             =item run( PACKAGE, ITERATIONS, @ARGS )
48              
49             Find all of the subroutines that start with C in C
50             and run each of them C times.
51              
52             Before it does that, though, call the C routine in C
53             as a class method. After benchmarking, call the C routine
54             in C as a class method.
55              
56             =cut
57              
58             sub run {
59 0     0 1   my( $package, $iterations, @args ) = @_;
60 0 0         $package->set_up( @args ) if $package->can( 'set_up' );
61              
62             # the key is a label, which is the stuff after bench_
63 1     1   6 no strict 'refs';
  1         2  
  1         252  
64             my %hash = map {
65 0           (
66 0           do { (my $s = $_) =~ s/\Abench_//; $s },
  0            
67 0           \&{"${package}::$_"}
  0            
68             )
69             } get_all_bench_( $package );
70              
71 0 0         die "Did not find any bench_ subroutines in [$package]\n"
72             unless keys %hash;
73              
74 0           require Benchmark;
75 0           my $results = Benchmark::timethese( $iterations, \%hash );
76              
77 0 0         $package->tear_down() if $package->can( 'tear_down' );
78             }
79              
80             =item test( PACKAGE, @ARGS )
81              
82             Find all of the subroutines that start with C in C
83             and run each of them once. Compare the return values of each to ensure
84             they are the same.
85              
86             Before it does that, though, call the C routine in C
87             as a class method. After benchmarking, call the C routine
88             in C as a class method.
89              
90             =cut
91              
92             sub test {
93 0     0 1   my( $package, @args ) = @_;
94 0           my @subs = get_all_bench_( $package );
95 0           my %results;
96              
97 0 0         $package->set_up( @args ) if $package->can( 'set_up' );
98 0           foreach my $sub ( get_all_bench_( $package ) ) {
99 0           my @return = $package->$sub();
100 0           $results{$sub} = \@return;
101             }
102 0 0         $package->tear_down() if $package->can( 'tear_down' );
103              
104 1     1   6 use Test::More;
  1         2  
  1         8  
105              
106             subtest pairs => sub {
107 0     0     my @subs = keys %results;
108 0           foreach my $i ( 1 .. $#subs ) {
109 0           my @sub_names = @subs[ $i - 1, $i ];
110 0           my( $first, $second ) = @results{ @sub_names };
111 0           local $" = " and ";
112 0           is_deeply( $first, $second, "@sub_names match return values" );
113             }
114 0           };
115              
116 0           done_testing();
117             }
118              
119             =item get_all_bench_( PACKAGE )
120              
121             Extract all of the subroutines starting with C in C.
122             If you don't define a package, it uses the package this subroutine
123             was compiled in (so that's probably useless).
124              
125             =cut
126              
127             sub get_all_bench_ {
128 0     0 1   my( $package ) = @_;
129 0 0         $package = defined $package ? $package : __PACKAGE__;
130              
131 1     1   386 no strict 'refs';
  1         2  
  1         83  
132             my @subs =
133             grep /\Abench_/,
134 0           keys %{"${package}::"};
  0            
135             }
136              
137              
138             =back
139              
140             =head1 TO DO
141              
142              
143             =head1 SEE ALSO
144              
145              
146             =head1 SOURCE AVAILABILITY
147              
148             This source is in a Git repository that I haven't made public
149             because I haven't bothered to set it up. If you want to clone
150             it, just ask and we'll work something out.
151              
152             https://github.com/briandfoy/surveyor-app
153              
154             =head1 AUTHOR
155              
156             brian d foy, C<< >>
157              
158             =head1 COPYRIGHT AND LICENSE
159              
160             Copyright © 2013-2022, brian d foy . All rights reserved.
161              
162             You may redistribute this under the terms of the Artistic License 2.0.
163              
164             =cut
165              
166             1;