|
|
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 |
--
|
|
|
aa0300 |
2.7.4
|
|
|
e76f14 |
|