All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC] use event channel to improve suspend speed
@ 2007-05-09  0:01 Brendan Cully
  2007-05-10 22:13 ` Brendan Cully
  0 siblings, 1 reply; 8+ messages in thread
From: Brendan Cully @ 2007-05-09  0:01 UTC (permalink / raw)
  To: Xen Developers

[-- Attachment #1: Type: text/plain, Size: 1503 bytes --]

Hi,

I've been doing a little work on improving the latency of guest domain
suspends. I've added a couple of printfs into xc_domain_save around
the last round, and hooked up a harness to loop over the last round
code every couple of seconds. Here are some numbers for a run of 100
last rounds (from just before the suspend callback to just before it
would exit), on a 3.2 Ghz P4 with 1 GB of RAM, 128 MB of which goes to
a guest. This approximates the best-case downtime for live migration,
I think.

current code:
avg: 133.57 ms, min: 82.53, max: 559.86, median: 135.63

with the attached patch:
avg: 36.05 ms, min: 33.99, max: 52.14, median: 35.51

The patch creates an event channel in the guest that fires the suspend
code. xc_save can use this to suspend the domain instead of calling
back to xend, which then writes a xenstore entry, which then causes a
watch to fire in the guest. It seems the xenstore interaction is
fairly slow and very jittery.

This isn't intended for 3.1, but I thought I'd put it out just in case
anyone else finds it interesting. I'd appreciate comments about the
approach.

There's also a fair amount of latency involved in xend receiving the
notification that the domain has suspended and passing that back on to
xc_save. A quick hack to let xc_save simply loop on xc_domain_getinfo
until the domain suspends indicates that it should be fairly easy to
cut the suspend latency in half again, to about 15ms. I'll see about
finding a clean equivalent of this...

Comments?

[-- Attachment #2: suspend-via-evtchn.patch --]
[-- Type: text/x-patch, Size: 6342 bytes --]

# HG changeset patch
# User Brendan Cully <brendan@cs.ubc.ca>
# Date 1178666168 25200
# Node ID 9b400773f70d590c4a3ccfd6184e58bcc89cbf2f
# Parent  8f19dcd7132965ecd7f96dccaa25cf8aa94a0af3
Set up an event channel to signal guest suspend.
Have xc_save use it directly instead of waiting for xend to signal the
guest via xenstore.  This cuts the overhead for the last round in half
in my tests.

Signed-off-by: Brendan Cully <brendan@cs.ubc.ca>

diff -r 8f19dcd71329 -r 9b400773f70d linux-2.6-xen-sparse/drivers/xen/core/machine_reboot.c
--- a/linux-2.6-xen-sparse/drivers/xen/core/machine_reboot.c	Mon May 07 15:43:52 2007 -0700
+++ b/linux-2.6-xen-sparse/drivers/xen/core/machine_reboot.c	Tue May 08 16:16:08 2007 -0700
@@ -27,6 +27,8 @@ void (*pm_power_off)(void);
 void (*pm_power_off)(void);
 EXPORT_SYMBOL(pm_power_off);
 
+int setup_suspend_evtchn(void);
+
 void machine_emergency_restart(void)
 {
 	/* We really want to get pending console data out before we die. */
@@ -227,6 +229,7 @@ int __xen_suspend(int fast_suspend)
 	if (!suspend_cancelled) {
 		xencons_resume();
 		xenbus_resume();
+		setup_suspend_evtchn();
 	} else {
 		xenbus_suspend_cancel();
 	}
diff -r 8f19dcd71329 -r 9b400773f70d linux-2.6-xen-sparse/drivers/xen/core/reboot.c
--- a/linux-2.6-xen-sparse/drivers/xen/core/reboot.c	Mon May 07 15:43:52 2007 -0700
+++ b/linux-2.6-xen-sparse/drivers/xen/core/reboot.c	Tue May 08 16:16:08 2007 -0700
@@ -7,6 +7,7 @@
 #include <linux/sysrq.h>
 #include <asm/hypervisor.h>
 #include <xen/xenbus.h>
+#include <xen/evtchn.h>
 #include <linux/kthread.h>
 
 #ifdef HAVE_XEN_PLATFORM_COMPAT_H
@@ -199,6 +200,36 @@ static struct xenbus_watch sysrq_watch =
 	.callback = sysrq_handler
 };
 
+static irqreturn_t suspend_int(int irq, void* dev_id, struct pt_regs *ptregs)
+{
+  shutting_down = SHUTDOWN_SUSPEND;
+  schedule_work(&shutdown_work);
+
+  return IRQ_HANDLED;
+}
+
+int setup_suspend_evtchn(void)
+{
+  static int irq = -1;
+  int port;
+  char portstr[5]; /* 1024 max? */
+
+  if (irq > 0)
+    unbind_from_irqhandler(irq, NULL);
+
+  /* TODO: get other end dynamically */
+  irq = bind_listening_port_to_irqhandler(0, suspend_int, 0, "suspend", NULL);
+  if (irq <= 0) {
+    return -1;
+  }
+  port = irq_to_evtchn_port(irq);
+  printk(KERN_ERR "suspend: event channel %d\n", port);
+  sprintf(portstr, "%d", port);
+  xenbus_write(XBT_NIL, "device/suspend", "event-channel", portstr);
+
+  return 0;
+}
+
 static int setup_shutdown_watcher(void)
 {
 	int err;
@@ -217,6 +248,13 @@ static int setup_shutdown_watcher(void)
 	if (err) {
 		printk(KERN_ERR "Failed to set sysrq watcher\n");
 		return err;
+	}
+
+	/* suspend event channel */
+	err = setup_suspend_evtchn();
+	if (err) {
+	  printk(KERN_ERR "Failed to register suspend event channel\n");
+	  return err;
 	}
 
 	return 0;
diff -r 8f19dcd71329 -r 9b400773f70d tools/python/xen/xend/XendCheckpoint.py
--- a/tools/python/xen/xend/XendCheckpoint.py	Mon May 07 15:43:52 2007 -0700
+++ b/tools/python/xen/xend/XendCheckpoint.py	Tue May 08 16:16:08 2007 -0700
@@ -92,6 +92,7 @@ def save(fd, dominfo, network, live, dst
             if line == "suspend":
                 log.debug("Suspending %d ...", dominfo.getDomid())
                 dominfo.shutdown('suspend')
+            if line in ('suspend', 'suspended'):
                 dominfo.waitForShutdown()
                 dominfo.migrateDevices(network, dst, DEV_MIGRATE_STEP2,
                                        domain_name)
diff -r 8f19dcd71329 -r 9b400773f70d tools/xcutils/xc_save.c
--- a/tools/xcutils/xc_save.c	Mon May 07 15:43:52 2007 -0700
+++ b/tools/xcutils/xc_save.c	Tue May 08 16:16:08 2007 -0700
@@ -23,8 +23,13 @@
 #include <xenctrl.h>
 #include <xenguest.h>
 
+#include <errno.h>
+
 /* defined in xc_linux_save. Yes, this is cheezy. */
 extern int do_last_round;
+
+static int xce = -1;
+static int suspend_evtchn = -1;
 
 /**
  * Issue a suspend request through stdout, and receive the acknowledgement
@@ -32,9 +37,24 @@ extern int do_last_round;
  */
 static int suspend(int domid)
 {
+    static char* suspend = "suspend\n";
+    static char* suspended = "suspended\n";
+
     char ans[30];
-
-    printf("suspend\n");
+    char* msg;
+    int rc;
+
+    msg = suspend;
+
+    if (suspend_evtchn > 0) {
+      rc = xc_evtchn_notify(xce, suspend_evtchn);
+      if (rc < 0)
+	fprintf(stderr, "failed to notify suspend event channel: %d\n", rc);
+      else
+	msg = suspended;
+    }
+
+    printf(msg);
     fflush(stdout);
 
     return (fgets(ans, sizeof(ans), stdin) != NULL &&
@@ -183,6 +203,59 @@ static void sigusr1(int sig)
   do_last_round = 1;
 }
 
+static int setup_suspend_evtchn(unsigned int domid)
+{
+  struct xs_handle* xs;
+  char path[128];
+  char *portstr;
+  unsigned int plen;
+  int port;
+  int rc = -1;
+
+  xce = xc_evtchn_open();
+  if (xce < 0) {
+    fprintf(stderr, "failed to open event channel handle\n");
+    return -1;
+  }
+
+  xs = xs_daemon_open_readonly();
+  if (!xs) {
+    fprintf(stderr, "failed to open xenstore handle\n");
+    goto xce_err;
+  }
+
+  sprintf(path, "/local/domain/%d/device/suspend/event-channel", domid);
+
+  portstr = xs_read(xs, XBT_NULL, path, &plen);
+  if (!portstr || !plen) {
+    fprintf(stderr, "failed to read suspend event channel\n");
+    goto xs_err;
+  }
+  port = atoi(portstr);
+  free(portstr);
+
+  fprintf(stderr, "binding to suspend evtchn %u:%d\n", domid, port);
+
+  suspend_evtchn = xc_evtchn_bind_interdomain(xce, domid, port);
+  if (suspend_evtchn < 0) {
+    fprintf(stderr, "failed to bind suspend event channel: %d (%s)\n",
+	    suspend_evtchn, strerror(errno));
+    goto xs_err;
+  }
+
+  rc = 0;
+
+  xs_err:
+  xs_daemon_close(xs);
+  xce_err:
+  if (xce >= 0 && rc < 0) {
+    xc_evtchn_close(xce);
+    xce = -1;
+  }
+
+  return rc;
+}
+
 int
 main(int argc, char **argv)
 {
@@ -207,12 +280,17 @@ main(int argc, char **argv)
     sa.sa_flags = SA_RESTART;
     sigaction(SIGUSR1, &sa, NULL);
 
+    setup_suspend_evtchn(domid);
+
     ret = xc_domain_save(xc_fd, io_fd, domid, maxit, max_f, flags, 
                          &suspend,
 			 flags & XCFLAGS_CONTINUAL ? checkpoint_cb : NULL,
 			 !!(flags & XCFLAGS_HVM),
                          &init_qemu_maps, &qemu_flip_buffer);
 
+    if (xce >= 0)
+      xc_evtchn_close(xce);
+
     xc_interface_close(xc_fd);
 
     return ret;

[-- Attachment #3: Type: text/plain, Size: 138 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2007-05-25 23:41 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-05-09  0:01 [RFC] use event channel to improve suspend speed Brendan Cully
2007-05-10 22:13 ` Brendan Cully
2007-05-10 23:00   ` Daniel P. Berrange
2007-05-11  0:06     ` Brendan Cully
2007-05-11  6:55     ` Keir Fraser
2007-05-25  0:06       ` Brendan Cully
2007-05-25  6:46         ` Keir Fraser
2007-05-25 23:41           ` Brendan Cully

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.