Blame SOURCES/0052-tests-qemu-Add-boot-benchmark.patch

e76f14
From 8a9557041411dbb6739fb81c7ea992ef4109aa22 Mon Sep 17 00:00:00 2001
e76f14
From: "Richard W.M. Jones" <rjones@redhat.com>
e76f14
Date: Fri, 1 Apr 2016 19:19:51 +0100
e76f14
Subject: [PATCH] tests/qemu: Add boot-benchmark.
e76f14
e76f14
Add a new test program called 'boot-benchmark'.  This is similar to
e76f14
'boot-analysis' but it simply boots and shuts down the appliance
e76f14
several times in a row and measures how long it takes, calculating
e76f14
mean and standard deviation.
e76f14
e76f14
(cherry picked from commit 96ce2f9afedc6a7ecb2f7781958c3940255f453b)
e76f14
---
e76f14
 .gitignore                       |   1 +
e76f14
 docs/guestfs-performance.pod     |  15 ++-
e76f14
 tests/qemu/Makefile.am           |  30 ++++-
e76f14
 tests/qemu/boot-analysis-utils.c |  47 ++++++++
e76f14
 tests/qemu/boot-analysis-utils.h |  30 +++++
e76f14
 tests/qemu/boot-analysis.c       |  21 +---
e76f14
 tests/qemu/boot-benchmark.c      | 230 +++++++++++++++++++++++++++++++++++++++
e76f14
 7 files changed, 346 insertions(+), 28 deletions(-)
e76f14
 create mode 100644 tests/qemu/boot-analysis-utils.c
e76f14
 create mode 100644 tests/qemu/boot-analysis-utils.h
e76f14
 create mode 100644 tests/qemu/boot-benchmark.c
e76f14
e76f14
diff --git a/.gitignore b/.gitignore
e76f14
index 9c45df7..46a6e65 100644
e76f14
--- a/.gitignore
e76f14
+++ b/.gitignore
e76f14
@@ -510,6 +510,7 @@ Makefile.in
e76f14
 /tests/parallel/test-parallel
e76f14
 /tests/protocol/test-error-messages
e76f14
 /tests/qemu/boot-analysis
e76f14
+/tests/qemu/boot-benchmark
e76f14
 /tests/qemu/qemu-boot
e76f14
 /tests/qemu/qemu-speed-test
e76f14
 /tests/regressions/rhbz501893
e76f14
diff --git a/docs/guestfs-performance.pod b/docs/guestfs-performance.pod
e76f14
index 4ba6faf..cf30fdc 100644
e76f14
--- a/docs/guestfs-performance.pod
e76f14
+++ b/docs/guestfs-performance.pod
e76f14
@@ -29,11 +29,20 @@ appliance:
e76f14
 Run this command several times in a row and discard the first few
e76f14
 runs, so that you are measuring a typical "hot cache" case.
e76f14
 
e76f14
+I<Side note for developers:> If you are compiling libguestfs from
e76f14
+source, there is a program called F<tests/qemu/boot-benchmark> which
e76f14
+does the same thing, but performs multiple runs and prints the mean
e76f14
+and standard deviation.  To run it, do:
e76f14
+
e76f14
+ make
e76f14
+ make -C tests/qemu boot-benchmark
e76f14
+ ./run ./tests/qemu/boot-benchmark
e76f14
+
e76f14
 =head3 Explanation
e76f14
 
e76f14
-This command starts up the libguestfs appliance on a null disk, and
e76f14
-then immediately shuts it down.  The first time you run the command,
e76f14
-it will create an appliance and cache it (usually under
e76f14
+The guestfish command above starts up the libguestfs appliance on a
e76f14
+null disk, and then immediately shuts it down.  The first time you run
e76f14
+the command, it will create an appliance and cache it (usually under
e76f14
 F).  Subsequent runs should reuse the cached
e76f14
 appliance.
e76f14
 
e76f14
diff --git a/tests/qemu/Makefile.am b/tests/qemu/Makefile.am
e76f14
index bea1c85..cc5cb6a 100644
e76f14
--- a/tests/qemu/Makefile.am
e76f14
+++ b/tests/qemu/Makefile.am
e76f14
@@ -1,5 +1,5 @@
e76f14
 # libguestfs
e76f14
-# Copyright (C) 2011 Red Hat Inc.
e76f14
+# Copyright (C) 2011-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
@@ -33,10 +33,11 @@ EXTRA_DIST = \
e76f14
 	qemu-boot.c \
e76f14
 	qemu-speed-test.c
e76f14
 
e76f14
-# qemu-boot, qemu-speed-test and boot-analysis are built but not run
e76f14
-# by default as they are mainly qemu & kernel diagnostic tools.
e76f14
+# qemu-boot, qemu-speed-test, boot-analysis and boot-benchmark are
e76f14
+# built but not run by default as they are mainly qemu & kernel
e76f14
+# diagnostic tools.
e76f14
 
e76f14
-check_PROGRAMS = qemu-boot qemu-speed-test boot-analysis
e76f14
+check_PROGRAMS = qemu-boot qemu-speed-test boot-analysis boot-benchmark
e76f14
 
e76f14
 qemu_boot_SOURCES = \
e76f14
 	../../df/estimate-max-threads.c \
e76f14
@@ -76,7 +77,9 @@ qemu_speed_test_LDADD = \
e76f14
 boot_analysis_SOURCES = \
e76f14
 	boot-analysis.c \
e76f14
 	boot-analysis.h \
e76f14
-	boot-analysis-timeline.c
e76f14
+	boot-analysis-timeline.c \
e76f14
+	boot-analysis-utils.c \
e76f14
+	boot-analysis-utils.h
e76f14
 boot_analysis_CPPFLAGS = \
e76f14
 	-I$(top_srcdir)/gnulib/lib -I$(top_builddir)/gnulib/lib \
e76f14
 	-I$(top_srcdir)/src -I$(top_builddir)/src
e76f14
@@ -93,6 +96,23 @@ boot_analysis_LDADD = \
e76f14
 	$(top_builddir)/gnulib/lib/libgnu.la \
e76f14
 	-lm
e76f14
 
e76f14
+boot_benchmark_SOURCES = \
e76f14
+	boot-benchmark.c \
e76f14
+	boot-analysis-utils.c \
e76f14
+	boot-analysis-utils.h
e76f14
+boot_benchmark_CPPFLAGS = \
e76f14
+	-I$(top_srcdir)/gnulib/lib -I$(top_builddir)/gnulib/lib \
e76f14
+	-I$(top_srcdir)/src -I$(top_builddir)/src
e76f14
+boot_benchmark_CFLAGS = \
e76f14
+	$(WARN_CFLAGS) $(WERROR_CFLAGS)
e76f14
+boot_benchmark_LDADD = \
e76f14
+	$(top_builddir)/src/libutils.la \
e76f14
+	$(top_builddir)/src/libguestfs.la \
e76f14
+	$(LIBXML2_LIBS) \
e76f14
+	$(LTLIBINTL) \
e76f14
+	$(top_builddir)/gnulib/lib/libgnu.la \
e76f14
+	-lm
e76f14
+
e76f14
 # Don't run these tests in parallel, since they are designed to check
e76f14
 # the integrity of qemu.
e76f14
 .NOTPARALLEL:
e76f14
diff --git a/tests/qemu/boot-analysis-utils.c b/tests/qemu/boot-analysis-utils.c
e76f14
new file mode 100644
e76f14
index 0000000..e885f3b
e76f14
--- /dev/null
e76f14
+++ b/tests/qemu/boot-analysis-utils.c
e76f14
@@ -0,0 +1,47 @@
e76f14
+/* libguestfs
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 along
e76f14
+ * with this program; if not, write to the Free Software Foundation, Inc.,
e76f14
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
e76f14
+ */
e76f14
+
e76f14
+#include <config.h>
e76f14
+
e76f14
+#include <stdio.h>
e76f14
+#include <stdlib.h>
e76f14
+#include <time.h>
e76f14
+#include <error.h>
e76f14
+#include <errno.h>
e76f14
+
e76f14
+#include "guestfs.h"
e76f14
+#include "guestfs-internal-frontend.h"
e76f14
+
e76f14
+#include "boot-analysis-utils.h"
e76f14
+
e76f14
+void
e76f14
+get_time (struct timespec *ts)
e76f14
+{
e76f14
+  if (clock_gettime (CLOCK_REALTIME, ts) == -1)
e76f14
+    error (EXIT_FAILURE, errno, "clock_gettime: CLOCK_REALTIME");
e76f14
+}
e76f14
+
e76f14
+int64_t
e76f14
+timespec_diff (const struct timespec *x, const struct timespec *y)
e76f14
+{
e76f14
+  int64_t nsec;
e76f14
+
e76f14
+  nsec = (y->tv_sec - x->tv_sec) * UINT64_C(1000000000);
e76f14
+  nsec += y->tv_nsec - x->tv_nsec;
e76f14
+  return nsec;
e76f14
+}
e76f14
diff --git a/tests/qemu/boot-analysis-utils.h b/tests/qemu/boot-analysis-utils.h
e76f14
new file mode 100644
e76f14
index 0000000..83fc494
e76f14
--- /dev/null
e76f14
+++ b/tests/qemu/boot-analysis-utils.h
e76f14
@@ -0,0 +1,30 @@
e76f14
+/* libguestfs
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 along
e76f14
+ * with this program; if not, write to the Free Software Foundation, Inc.,
e76f14
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
e76f14
+ */
e76f14
+
e76f14
+#ifndef GUESTFS_BOOT_ANALYSIS_UTILS_H_
e76f14
+#define GUESTFS_BOOT_ANALYSIS_UTILS_H_
e76f14
+
e76f14
+/* Get current time, returning it in *ts.  If there is a system call
e76f14
+ * failure, this exits.
e76f14
+ */
e76f14
+extern void get_time (struct timespec *ts);
e76f14
+
e76f14
+/* Computes Y - X, returning nanoseconds. */
e76f14
+extern int64_t timespec_diff (const struct timespec *x, const struct timespec *y);
e76f14
+
e76f14
+#endif /* GUESTFS_BOOT_ANALYSIS_UTILS_H_ */
e76f14
diff --git a/tests/qemu/boot-analysis.c b/tests/qemu/boot-analysis.c
e76f14
index fc2c93b..022eaab 100644
e76f14
--- a/tests/qemu/boot-analysis.c
e76f14
+++ b/tests/qemu/boot-analysis.c
e76f14
@@ -79,6 +79,7 @@
e76f14
 #include "guestfs-internal-frontend.h"
e76f14
 
e76f14
 #include "boot-analysis.h"
e76f14
+#include "boot-analysis-utils.h"
e76f14
 
e76f14
 /* Activities taking longer than this % of the total time, except
e76f14
  * those flagged as LONG_ACTIVITY, are highlighted in red.
e76f14
@@ -96,8 +97,6 @@ static int smp = 1;
e76f14
 static int verbose = 0;
e76f14
 
e76f14
 static void run_test (void);
e76f14
-static void get_time (struct timespec *ts);
e76f14
-static int64_t timespec_diff (const struct timespec *x, const struct timespec *y);
e76f14
 static struct event *add_event (struct pass_data *, uint64_t source);
e76f14
 static guestfs_h *create_handle (void);
e76f14
 static void set_up_event_handlers (guestfs_h *g, size_t pass);
e76f14
@@ -267,24 +266,6 @@ run_test (void)
e76f14
   free_final_timeline ();
e76f14
 }
e76f14
 
e76f14
-static void
e76f14
-get_time (struct timespec *ts)
e76f14
-{
e76f14
-  if (clock_gettime (CLOCK_REALTIME, ts) == -1)
e76f14
-    error (EXIT_FAILURE, errno, "clock_gettime: CLOCK_REALTIME");
e76f14
-}
e76f14
-
e76f14
-/* Computes Y - X, returning nanoseconds. */
e76f14
-static int64_t
e76f14
-timespec_diff (const struct timespec *x, const struct timespec *y)
e76f14
-{
e76f14
-  int64_t nsec;
e76f14
-
e76f14
-  nsec = (y->tv_sec - x->tv_sec) * UINT64_C(1000000000);
e76f14
-  nsec += y->tv_nsec - x->tv_nsec;
e76f14
-  return nsec;
e76f14
-}
e76f14
-
e76f14
 static struct event *
e76f14
 add_event (struct pass_data *data, uint64_t source)
e76f14
 {
e76f14
diff --git a/tests/qemu/boot-benchmark.c b/tests/qemu/boot-benchmark.c
e76f14
new file mode 100644
e76f14
index 0000000..2a6a038
e76f14
--- /dev/null
e76f14
+++ b/tests/qemu/boot-benchmark.c
e76f14
@@ -0,0 +1,230 @@
e76f14
+/* libguestfs
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 along
e76f14
+ * with this program; if not, write to the Free Software Foundation, Inc.,
e76f14
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
e76f14
+ */
e76f14
+
e76f14
+/* Benchmark the time taken to boot the libguestfs appliance. */
e76f14
+
e76f14
+#include <config.h>
e76f14
+
e76f14
+#include <stdio.h>
e76f14
+#include <stdlib.h>
e76f14
+#include <stdint.h>
e76f14
+#include <inttypes.h>
e76f14
+#include <string.h>
e76f14
+#include <getopt.h>
e76f14
+#include <limits.h>
e76f14
+#include <time.h>
e76f14
+#include <errno.h>
e76f14
+#include <error.h>
e76f14
+#include <assert.h>
e76f14
+#include <math.h>
e76f14
+
e76f14
+#include "guestfs.h"
e76f14
+#include "guestfs-internal-frontend.h"
e76f14
+
e76f14
+#include "boot-analysis-utils.h"
e76f14
+
e76f14
+#define NR_WARMUP_PASSES 3
e76f14
+#define NR_TEST_PASSES   10
e76f14
+
e76f14
+static const char *append = NULL;
e76f14
+static int memsize = 0;
e76f14
+static int smp = 1;
e76f14
+
e76f14
+static void run_test (void);
e76f14
+static guestfs_h *create_handle (void);
e76f14
+static void add_drive (guestfs_h *g);
e76f14
+
e76f14
+static void
e76f14
+usage (int exitcode)
e76f14
+{
e76f14
+  guestfs_h *g;
e76f14
+  int default_memsize = -1;
e76f14
+
e76f14
+  g = guestfs_create ();
e76f14
+  if (g) {
e76f14
+    default_memsize = guestfs_get_memsize (g);
e76f14
+    guestfs_close (g);
e76f14
+  }
e76f14
+
e76f14
+  fprintf (stderr,
e76f14
+           "boot-benchmark: Benchmark the time taken to boot the libguestfs appliance.\n"
e76f14
+           "Usage:\n"
e76f14
+           "  boot-benchmark [--options]\n"
e76f14
+           "Options:\n"
e76f14
+           "  --help         Display this usage text and exit.\n"
e76f14
+           "  --append OPTS  Append OPTS to kernel command line.\n"
e76f14
+           "  -m MB\n"
e76f14
+           "  --memsize MB   Set memory size in MB (default: %d).\n"
e76f14
+           "  --smp N        Enable N virtual CPUs (default: 1).\n",
e76f14
+           default_memsize);
e76f14
+  exit (exitcode);
e76f14
+}
e76f14
+
e76f14
+int
e76f14
+main (int argc, char *argv[])
e76f14
+{
e76f14
+  enum { HELP_OPTION = CHAR_MAX + 1 };
e76f14
+  static const char *options = "m:";
e76f14
+  static const struct option long_options[] = {
e76f14
+    { "help", 0, 0, HELP_OPTION },
e76f14
+    { "append", 1, 0, 0 },
e76f14
+    { "memsize", 1, 0, 'm' },
e76f14
+    { "smp", 1, 0, 0 },
e76f14
+    { 0, 0, 0, 0 }
e76f14
+  };
e76f14
+  int c, option_index;
e76f14
+
e76f14
+  for (;;) {
e76f14
+    c = getopt_long (argc, argv, options, long_options, &option_index);
e76f14
+    if (c == -1) break;
e76f14
+
e76f14
+    switch (c) {
e76f14
+    case 0:                     /* Options which are long only. */
e76f14
+      if (STREQ (long_options[option_index].name, "append")) {
e76f14
+        append = optarg;
e76f14
+        break;
e76f14
+      }
e76f14
+      else if (STREQ (long_options[option_index].name, "smp")) {
e76f14
+        if (sscanf (optarg, "%d", &smp) != 1) {
e76f14
+          fprintf (stderr, "%s: could not parse smp parameter: %s\n",
e76f14
+                   guestfs_int_program_name, optarg);
e76f14
+          exit (EXIT_FAILURE);
e76f14
+        }
e76f14
+        break;
e76f14
+      }
e76f14
+      fprintf (stderr, "%s: unknown long option: %s (%d)\n",
e76f14
+               guestfs_int_program_name, long_options[option_index].name, option_index);
e76f14
+      exit (EXIT_FAILURE);
e76f14
+
e76f14
+    case 'm':
e76f14
+      if (sscanf (optarg, "%d", &memsize) != 1) {
e76f14
+        fprintf (stderr, "%s: could not parse memsize parameter: %s\n",
e76f14
+                 guestfs_int_program_name, optarg);
e76f14
+        exit (EXIT_FAILURE);
e76f14
+      }
e76f14
+      break;
e76f14
+
e76f14
+    case HELP_OPTION:
e76f14
+      usage (EXIT_SUCCESS);
e76f14
+
e76f14
+    default:
e76f14
+      usage (EXIT_FAILURE);
e76f14
+    }
e76f14
+  }
e76f14
+
e76f14
+  run_test ();
e76f14
+}
e76f14
+
e76f14
+static void
e76f14
+run_test (void)
e76f14
+{
e76f14
+  guestfs_h *g;
e76f14
+  size_t i;
e76f14
+  int64_t ns[NR_TEST_PASSES];
e76f14
+  double mean;
e76f14
+  double variance;
e76f14
+  double sd;
e76f14
+
e76f14
+  printf ("Warming up the libguestfs cache ...\n");
e76f14
+  for (i = 0; i < NR_WARMUP_PASSES; ++i) {
e76f14
+    g = create_handle ();
e76f14
+    add_drive (g);
e76f14
+    if (guestfs_launch (g) == -1)
e76f14
+      exit (EXIT_FAILURE);
e76f14
+    guestfs_close (g);
e76f14
+  }
e76f14
+
e76f14
+  printf ("Running the tests ...\n");
e76f14
+  for (i = 0; i < NR_TEST_PASSES; ++i) {
e76f14
+    struct timespec start_t, end_t;
e76f14
+
e76f14
+    g = create_handle ();
e76f14
+    add_drive (g);
e76f14
+    get_time (&start_t);
e76f14
+    if (guestfs_launch (g) == -1)
e76f14
+      exit (EXIT_FAILURE);
e76f14
+    guestfs_close (g);
e76f14
+    get_time (&end_t);
e76f14
+
e76f14
+    ns[i] = timespec_diff (&start_t, &end_t);
e76f14
+  }
e76f14
+
e76f14
+  /* Calculate the mean. */
e76f14
+  mean = 0;
e76f14
+  for (i = 0; i < NR_TEST_PASSES; ++i)
e76f14
+    mean += ns[i];
e76f14
+  mean /= NR_TEST_PASSES;
e76f14
+
e76f14
+  /* Calculate the variance and standard deviation. */
e76f14
+  variance = 0;
e76f14
+  for (i = 0; i < NR_TEST_PASSES; ++i)
e76f14
+    variance = pow (ns[i] - mean, 2);
e76f14
+  variance /= NR_TEST_PASSES;
e76f14
+  sd = sqrt (variance);
e76f14
+
e76f14
+  /* Print the test parameters. */
e76f14
+  printf ("\n");
e76f14
+  printf (" passes %d\n", NR_TEST_PASSES);
e76f14
+  g = create_handle ();
e76f14
+  printf (" append %s\n", guestfs_get_append (g) ? : "");
e76f14
+  printf ("backend %s\n", guestfs_get_backend (g));
e76f14
+  printf ("     hv %s\n", guestfs_get_hv (g));
e76f14
+  printf ("memsize %d\n", guestfs_get_memsize (g));
e76f14
+  printf ("    smp %d\n", guestfs_get_smp (g));
e76f14
+  guestfs_close (g);
e76f14
+
e76f14
+  /* Print the result. */
e76f14
+  printf ("\n");
e76f14
+  printf ("Result: %.1fms ±%.1fms\n", mean / 1000000, sd / 1000000);
e76f14
+}
e76f14
+
e76f14
+/* Common function to create the handle and set various defaults. */
e76f14
+static guestfs_h *
e76f14
+create_handle (void)
e76f14
+{
e76f14
+  guestfs_h *g;
e76f14
+  CLEANUP_FREE char *full_append = NULL;
e76f14
+
e76f14
+  g = guestfs_create ();
e76f14
+  if (!g) error (EXIT_FAILURE, errno, "guestfs_create");
e76f14
+
e76f14
+  if (memsize != 0)
e76f14
+    if (guestfs_set_memsize (g, memsize) == -1)
e76f14
+      exit (EXIT_FAILURE);
e76f14
+
e76f14
+  if (smp >= 2)
e76f14
+    if (guestfs_set_smp (g, smp) == -1)
e76f14
+      exit (EXIT_FAILURE);
e76f14
+
e76f14
+  if (append != NULL)
e76f14
+    if (guestfs_set_append (g, full_append) == -1)
e76f14
+      exit (EXIT_FAILURE);
e76f14
+
e76f14
+  return g;
e76f14
+}
e76f14
+
e76f14
+/* Common function to add the /dev/null drive. */
e76f14
+static void
e76f14
+add_drive (guestfs_h *g)
e76f14
+{
e76f14
+  if (guestfs_add_drive_opts (g, "/dev/null",
e76f14
+                              GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw",
e76f14
+                              GUESTFS_ADD_DRIVE_OPTS_READONLY, 1,
e76f14
+                              -1) == -1)
e76f14
+    exit (EXIT_FAILURE);
e76f14
+}
e76f14
-- 
7af31e
1.8.3.1
e76f14