Commit 819046239451bd6efeb13cabee566ced9d03140f

Authored by Jay Berkenbilt
1 parent b880273c

Formalize performance testing

README-maintainer
... ... @@ -160,13 +160,16 @@ RELEASE PREPARATION
160 160 * Increment shared library version information as needed (`LT_*` in
161 161 `configure.ac`). Remember to rerun ./autogen.sh.
162 162  
163   -* Test for binary compatibility:
  163 +* Test for performance binary compatibility:
164 164 * Check out the last release
165 165 * ./configure --enable-werror && make -j$(nproc)
166 166 * Check out the current version
  167 + * ./performance_check | tee -a /tmp/perf
167 168 * ./configure --enable-werror && make -j$(nproc) build_libqpdf
168 169 * Checkout the last release
169 170 * make -k check NO_REBUILD=1
  171 + * make -j$(nproc)
  172 + * ./performance_check | tee -a /tmp/perf
170 173  
171 174 * Update release notes in manual. Look at diffs and ChangeLog. Update
172 175 release date in `manual/qpdf-manual.xml`. Remember to ensure that
... ...
performance_check 0 → 100755
  1 +#!/usr/bin/env perl
  2 +require 5.008;
  3 +use warnings;
  4 +use strict;
  5 +use File::Basename;
  6 +use Time::HiRes qw(gettimeofday tv_interval);
  7 +use File::Path qw(make_path);
  8 +
  9 +my $whoami = basename($0);
  10 +$| = 1;
  11 +
  12 +# [ name, [ args ] ]
  13 +my @tests = (
  14 + ['no arguments', []],
  15 + ['split pages', ['--split-pages', '--remove-unreferenced-resources=no']],
  16 + ['shared resource check', ['--split-pages', '--remove-unreferenced-resources=auto']],
  17 + ['linearize', ['--linearize']],
  18 + );
  19 +
  20 +# If arg is not found in help output, look here. If not here, skip test.
  21 +# { new => old } -- if new is not found, replace with old; if old is
  22 +# if old is empty, remove argument
  23 +my %arg_compat = (
  24 + '--remove-unreferenced-resources=no' => '--preserve-unreferenced-resources',
  25 + '--remove-unreferenced-resources=yes' => '',
  26 + '--remove-unreferenced-resources=auto' => undef,
  27 + );
  28 +
  29 +my $executable = undef;
  30 +my $test_dir = undef;
  31 +my $test_file = undef;
  32 +my $workdir = undef;
  33 +my $maxtime = undef;
  34 +
  35 +my $default_executable = 'qpdf/build/qpdf';
  36 +my $default_test_dir = '../performance-test-files';
  37 +my $default_test_file = undef;
  38 +my $default_workdir = 'qpdf/build/perf';
  39 +my $default_maxtime = 20;
  40 +
  41 +sub usage
  42 +{
  43 + die "
  44 +Usage: $whoami [ args ]
  45 + --dir dir test on all files in dir (default: $default_test_dir)
  46 + --file file test only on the named file
  47 + --executable qpdf use the specified qpdf (default: $default_executable)
  48 + --workdir where to write output pdfs (default: $default_workdir)
  49 + --maxtime maximum time for a test; 0 means unlimited (default: $default_maxtime)
  50 +";
  51 +}
  52 +
  53 +while (@ARGV)
  54 +{
  55 + my $arg = shift(@ARGV);
  56 + if ('--dir' eq $arg)
  57 + {
  58 + usage() unless @ARGV;
  59 + $test_dir = shift(@ARGV);
  60 + $test_file = undef;
  61 + }
  62 + elsif ('--file' eq $arg)
  63 + {
  64 + usage() unless @ARGV;
  65 + $test_file = shift(@ARGV);
  66 + $test_dir = undef;
  67 + }
  68 + elsif ('--executable' eq $arg)
  69 + {
  70 + usage() unless @ARGV;
  71 + $executable = shift(@ARGV);
  72 + }
  73 + elsif ('--workdir' eq $arg)
  74 + {
  75 + usage() unless @ARGV;
  76 + $workdir = shift(@ARGV);
  77 + }
  78 + elsif ('--maxtime' eq $arg)
  79 + {
  80 + usage() unless @ARGV;
  81 + $maxtime = shift(@ARGV);
  82 + }
  83 + else
  84 + {
  85 + usage();
  86 + }
  87 +}
  88 +
  89 +if ((! defined $test_dir) && (! defined $test_file))
  90 +{
  91 + $test_dir = $default_test_dir;
  92 +}
  93 +if (! defined $executable)
  94 +{
  95 + $executable = $default_executable;
  96 +}
  97 +if (! defined $workdir)
  98 +{
  99 + $workdir = $default_workdir;
  100 +}
  101 +if (! defined $maxtime)
  102 +{
  103 + $maxtime = $default_maxtime;
  104 +}
  105 +
  106 +my @test_files = ();
  107 +if (defined $test_file)
  108 +{
  109 + push(@test_files, $test_file);
  110 +}
  111 +else
  112 +{
  113 + opendir(D, $test_dir) or
  114 + die "$whoami: can't open directory $test_dir: $!\n";
  115 + my @entries = readdir(D);
  116 + closedir(D);
  117 + for (sort @entries)
  118 + {
  119 + push(@test_files, "$test_dir/$_") unless (('.' eq $_) || ('..' eq $_));
  120 + }
  121 +}
  122 +
  123 +run_tests();
  124 +
  125 +sub filter_args
  126 +{
  127 + my $args = shift;
  128 + my $help = `$executable --help`;
  129 + my $new_args = [];
  130 + foreach my $arg (@$args)
  131 + {
  132 + my $to_check = $arg;
  133 + $to_check =~ s/=.*$//;
  134 + if (index($help, $to_check) == -1)
  135 + {
  136 + my $new_arg = $arg_compat{$arg};
  137 + if (! defined $new_arg)
  138 + {
  139 + return undef;
  140 + }
  141 + if ($new_arg ne '')
  142 + {
  143 + print " replacing $arg with $new_arg\n";
  144 + push(@$new_args, $new_arg);
  145 + }
  146 + }
  147 + else
  148 + {
  149 + push(@$new_args, $arg);
  150 + }
  151 + }
  152 + $new_args;
  153 +}
  154 +
  155 +sub run_tests
  156 +{
  157 + my $args = shift;
  158 +
  159 + chomp(my $commit = `git describe @`);
  160 + print "commit: $commit\n";
  161 + make_path($workdir);
  162 + foreach my $test (@tests)
  163 + {
  164 + my ($name, $args) = @$test;
  165 + print " test: $name\n";
  166 + $args = filter_args($args);
  167 + if (! defined $args)
  168 + {
  169 + print " skipping (unknown arguments)\n";
  170 + next;
  171 + }
  172 + foreach my $file (@test_files)
  173 + {
  174 + my $time = run_test($file, $args);
  175 + if (defined $time)
  176 + {
  177 + print " $time " . basename($file) ."\n";
  178 + }
  179 + else
  180 + {
  181 + print " $file skipped\n";
  182 + }
  183 + }
  184 + }
  185 +}
  186 +
  187 +sub run_test
  188 +{
  189 + my ($file, $args) = @_;
  190 +
  191 + my $iterations = 20;
  192 + my @cmd = ($executable, @$args, $file, "$workdir/out.pdf");
  193 + # Run once and discard to update caches
  194 + system("sync");
  195 + system(@cmd);
  196 + my $i = 0;
  197 + my $total = 0;
  198 + while ($i < $iterations)
  199 + {
  200 + my $start = [gettimeofday];
  201 + my $r = system(@cmd);
  202 + if ($r == 2)
  203 + {
  204 + # interrupt
  205 + exit(2);
  206 + }
  207 + my $end = [gettimeofday];
  208 + if ($r != 0)
  209 + {
  210 + print " command failed; ignoring results\n";
  211 + return undef;
  212 + }
  213 + my $elapsed = tv_interval($start, $end);
  214 + $total += $elapsed;
  215 + ++$i;
  216 + if (($maxtime > 0) && ($total >= $maxtime) && ($i >= 3))
  217 + {
  218 + # This is taking too long, so take what we have
  219 + last;
  220 + }
  221 + }
  222 + return sprintf("%0.4f", $total / $i);
  223 +}
... ...