Blame SOURCES/0062-tests-Add-boot-benchmark-range-script.patch

e76f14
From 7b8c5efa52161bcd99006e7986c6cb67f6475023 Mon Sep 17 00:00:00 2001
e76f14
From: "Richard W.M. Jones" <rjones@redhat.com>
e76f14
Date: Fri, 22 Apr 2016 16:32:24 +0100
e76f14
Subject: [PATCH] tests: Add boot-benchmark-range script.
e76f14
e76f14
Add a script we can use to benchmark performance across a range of
e76f14
commits in another project.
e76f14
e76f14
(cherry picked from commit 8299d7087a6457828a57ecace54c01b73912a9c7)
e76f14
---
e76f14
 docs/guestfs-performance.pod       |  14 +++
e76f14
 tests/qemu/boot-benchmark-range.pl | 240 +++++++++++++++++++++++++++++++++++++
e76f14
 2 files changed, 254 insertions(+)
e76f14
 create mode 100755 tests/qemu/boot-benchmark-range.pl
e76f14
e76f14
diff --git a/docs/guestfs-performance.pod b/docs/guestfs-performance.pod
e76f14
index cf30fdc..d9c76ac 100644
e76f14
--- a/docs/guestfs-performance.pod
e76f14
+++ b/docs/guestfs-performance.pod
e76f14
@@ -589,6 +589,20 @@ breakpoints, etc.  Note that when you are past the BIOS and into the
e76f14
 Linux kernel, you'll want to change the architecture back to 32 or 64
e76f14
 bit.
e76f14
 
e76f14
+=head1 PERFORMANCE REGRESSIONS IN OTHER PROGRAMS
e76f14
+
e76f14
+Sometimes performance regressions happen in other programs (eg. qemu,
e76f14
+the kernel) that cause problems for libguestfs.
e76f14
+
e76f14
+In the libguestfs source, F<tests/qemu/boot-benchmark-range.pl> is a
e76f14
+script which can be used to benchmark libguestfs across a range of git
e76f14
+commits in another project to find out if any commit is causing a
e76f14
+slowdown (or speedup).
e76f14
+
e76f14
+To find out how to use this script, consult the manual:
e76f14
+
e76f14
+ ./tests/qemu/boot-benchmark-range.pl --man
e76f14
+
e76f14
 =head1 SEE ALSO
e76f14
 
e76f14
 L<supermin(1)>,
e76f14
diff --git a/tests/qemu/boot-benchmark-range.pl b/tests/qemu/boot-benchmark-range.pl
e76f14
new file mode 100755
e76f14
index 0000000..0e31c4d
e76f14
--- /dev/null
e76f14
+++ b/tests/qemu/boot-benchmark-range.pl
e76f14
@@ -0,0 +1,240 @@
e76f14
+#!/usr/bin/env perl
e76f14
+# Copyright (C) 2016 Red Hat Inc.
e76f14
+#
e76f14
+# This program is free software; you can redistribute it and/or modify
e76f14
+# it under the terms of the GNU General Public License as published by
e76f14
+# the Free Software Foundation; either version 2 of the License, or
e76f14
+# (at your option) any later version.
e76f14
+#
e76f14
+# This program is distributed in the hope that it will be useful,
e76f14
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
e76f14
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
e76f14
+# GNU General Public License for more details.
e76f14
+#
e76f14
+# You should have received a copy of the GNU General Public License
e76f14
+# along with this program; if not, write to the Free Software
e76f14
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
e76f14
+
e76f14
+use warnings;
e76f14
+use strict;
e76f14
+
e76f14
+use Pod::Usage;
e76f14
+use Getopt::Long;
e76f14
+
e76f14
+=head1 NAME
e76f14
+
e76f14
+boot-benchmark-range.pl - Benchmark libguestfs across a range of commits
e76f14
+from another project
e76f14
+
e76f14
+=head1 SYNOPSIS
e76f14
+
e76f14
+ LIBGUESTFS_BACKEND=direct \
e76f14
+ LIBGUESTFS_HV=/path/to/qemu/x86_64-softmmu/qemu-system-x86_64 \
e76f14
+   ./run \
e76f14
+   tests/qemu/boot-benchmark-range.pl /path/to/qemu HEAD~50..HEAD
e76f14
+
e76f14
+=head1
e76f14
+
e76f14
+Run F<tests/qemu/boot-benchmark> across a range of commits in another
e76f14
+project.  This is useful for finding performance regressions in other
e76f14
+programs such as qemu or the Linux kernel which might be affecting
e76f14
+libguestfs.
e76f14
+
e76f14
+For example, suppose you suspect there has been a performance
e76f14
+regression in qemu, somewhere between C<HEAD~50..HEAD>.  You could run
e76f14
+the script like this:
e76f14
+
e76f14
+ LIBGUESTFS_BACKEND=direct \
e76f14
+ LIBGUESTFS_HV=/path/to/qemu/x86_64-softmmu/qemu-system-x86_64 \
e76f14
+   ./run \
e76f14
+   tests/qemu/boot-benchmark-range.pl /path/to/qemu HEAD~50..HEAD
e76f14
+
e76f14
+where F</path/to/qemu> is the path to the qemu git repository.
e76f14
+
e76f14
+The output is a list of the qemu commits, annotated by the benchmark
e76f14
+time and some other information about how the time compares to the
e76f14
+previous commit.
e76f14
+
e76f14
+You should run these tests on an unloaded machine.  In particular
e76f14
+running a desktop environment, web browser and so on can make the
e76f14
+benchmarks useless.
e76f14
+
e76f14
+=head1 OPTIONS
e76f14
+
e76f14
+=over 4
e76f14
+
e76f14
+=cut
e76f14
+
e76f14
+my $help;
e76f14
+
e76f14
+=item B<--help>
e76f14
+
e76f14
+Display brief help.
e76f14
+
e76f14
+=cut
e76f14
+
e76f14
+my $man;
e76f14
+
e76f14
+=item B<--man>
e76f14
+
e76f14
+Display full documentation (man page).
e76f14
+
e76f14
+=cut
e76f14
+
e76f14
+my $benchmark_command;
e76f14
+
e76f14
+=item B<--benchmark> C<boot-benchmark>
e76f14
+
e76f14
+Set the name of the benchmark to run.  You only need to use this if
e76f14
+the script cannot find the right path to the libguestfs
e76f14
+F<tests/qemu/boot-benchmark> program.  By default the script looks for
e76f14
+this file in the same directory as its executable.
e76f14
+
e76f14
+=cut
e76f14
+
e76f14
+my $make_command = "make";
e76f14
+
e76f14
+=item B<--make> C<make>
e76f14
+
e76f14
+Set the command used to build the other project.  The default is
e76f14
+to run C<make>.
e76f14
+
e76f14
+If the command fails, then the commit is skipped.
e76f14
+
e76f14
+=back
e76f14
+
e76f14
+=cut
e76f14
+
e76f14
+# Clean up the program name.
e76f14
+my $progname = $0;
e76f14
+$progname =~ s{.*/}{};
e76f14
+
e76f14
+# Parse options.
e76f14
+GetOptions ("help|?" => \$help,
e76f14
+            "man" => \$man,
e76f14
+            "benchmark=s" => \$benchmark_command,
e76f14
+            "make=s" => \$make_command,
e76f14
+    ) or pod2usage (2);
e76f14
+pod2usage (-exitval => 0) if $help;
e76f14
+pod2usage (-exitval => 0, -verbose => 2) if $man;
e76f14
+
e76f14
+die "$progname: missing argument: requires path to git repository and range of commits\n" unless @ARGV == 2;
e76f14
+
e76f14
+my $dir = $ARGV[0];
e76f14
+my $range = $ARGV[1];
e76f14
+
e76f14
+die "$progname: $dir is not a git repository\n"
e76f14
+    unless -d $dir && -d "$dir/.git";
e76f14
+
e76f14
+sub silently_run
e76f14
+{
e76f14
+    open my $saveout, ">&STDOUT";
e76f14
+    open my $saveerr, ">&STDERR";
e76f14
+    open STDOUT, ">/dev/null";
e76f14
+    open STDERR, ">/dev/null";
e76f14
+    my $ret = system (@_);
e76f14
+    open STDOUT, ">&", $saveout;
e76f14
+    open STDERR, ">&", $saveerr;
e76f14
+    return $ret;
e76f14
+}
e76f14
+
e76f14
+# Find the benchmark program and check it works.
e76f14
+unless (defined $benchmark_command) {
e76f14
+    $benchmark_command = $0;
e76f14
+    $benchmark_command =~ s{/[^/]+$}{};
e76f14
+    $benchmark_command .= "/boot-benchmark";
e76f14
+
e76f14
+    my $r = silently_run ("$benchmark_command", "--help");
e76f14
+    die "$progname: cannot locate boot-benchmark program, try using --benchmark\n" unless $r == 0;
e76f14
+}
e76f14
+
e76f14
+# Get the top-most commit from the remote, and restore it on exit.
e76f14
+my $top_commit = `git -C '$dir' rev-parse HEAD`;
e76f14
+chomp $top_commit;
e76f14
+
e76f14
+sub checkout
e76f14
+{
e76f14
+    my $sha = shift;
e76f14
+    my $ret = silently_run ("git", "-C", $dir, "checkout", $sha);
e76f14
+    return $ret;
e76f14
+}
e76f14
+
e76f14
+END {
e76f14
+    checkout ($top_commit);
e76f14
+}
e76f14
+
e76f14
+# Get the range of commits and log messages.
e76f14
+my @range = ();
e76f14
+open RANGE, "git -C '$dir' log --reverse --oneline $range |" or die;
e76f14
+while (<RANGE>) {
e76f14
+    if (m/^([0-9a-f]+) (.*)/) {
e76f14
+        my $sha = $1;
e76f14
+        my $msg = $2;
e76f14
+        push @range, [ $sha, $msg ];
e76f14
+    }
e76f14
+}
e76f14
+close RANGE or die;
e76f14
+
e76f14
+# Run the test.
e76f14
+my $prev_ms;
e76f14
+foreach (@range) {
e76f14
+    my ($sha, $msg) = @$_;
e76f14
+    my $r;
e76f14
+
e76f14
+    print "\n";
e76f14
+    print "$sha $msg\n";
e76f14
+
e76f14
+    # Checkout this commit in the other repo.
e76f14
+    $r = checkout ($sha);
e76f14
+    if ($r != 0) {
e76f14
+        print "git checkout failed\n";
e76f14
+        next;
e76f14
+    }
e76f14
+
e76f14
+    # Build the repo, silently.
e76f14
+    $r = silently_run ("cd $dir && $make_command");
e76f14
+    if ($r != 0) {
e76f14
+        print "build failed\n";
e76f14
+        next;
e76f14
+    }
e76f14
+
e76f14
+    # Run the benchmark program and get the timing.
e76f14
+    my ($time_ms, $time_str);
e76f14
+    open BENCHMARK, "$benchmark_command | grep '^Result:' |" or die;
e76f14
+    while (<BENCHMARK>) {
e76f14
+        die unless m/^Result: (([\d.]+)ms ±[\d.]+ms)/;
e76f14
+        $time_ms = $2;
e76f14
+        $time_str = $1;
e76f14
+    }
e76f14
+    close BENCHMARK;
e76f14
+
e76f14
+    print "\t", $time_str;
e76f14
+    if (defined $prev_ms) {
e76f14
+        if ($prev_ms > $time_ms) {
e76f14
+            my $pc = 100 * ($prev_ms-$time_ms) / $time_ms;
e76f14
+            if ($pc >= 1) {
e76f14
+                printf (" ↑ improves performance by %0.1f%%", $pc);
e76f14
+            }
e76f14
+        } elsif ($prev_ms < $time_ms) {
e76f14
+            my $pc = 100 * ($time_ms-$prev_ms) / $prev_ms;
e76f14
+            if ($pc >= 1) {
e76f14
+                printf (" ↓ degrades performance by %0.1f%%", $pc);
e76f14
+            }
e76f14
+        }
e76f14
+    }
e76f14
+    print "\n";
e76f14
+    $prev_ms = $time_ms;
e76f14
+}
e76f14
+
e76f14
+=head1 SEE ALSO
e76f14
+
e76f14
+L<git(1)>,
e76f14
+L<guestfs-performance(1)>.
e76f14
+
e76f14
+=head1 AUTHOR
e76f14
+
e76f14
+Richard W.M. Jones.
e76f14
+
e76f14
+=head1 COPYRIGHT
e76f14
+
e76f14
+Copyright (C) 2016 Red Hat Inc.
e76f14
-- 
7af31e
1.8.3.1
e76f14