Subject: Faster Migration
To: None <port-xen@NetBSD.org>
From: Jed Davis <jdev@panix.com>
List: port-xen
Date: 09/15/2005 20:52:07
--=-=-=

Jed Davis <jdev@panix.com> writes:

> What I've been slowly leading up to: with this and the other three
> changes I've posted about today, I can successfully (and consistently)
> save and restore a Linux domU with a NetBSD dom0.

Live migration also works -- and non-live, for that matter.  (I have
had a domain fail to suspend once, while running a process on the domU
that repeatedly wrote to 2MB of memory, but I haven't been able to
reproduce it, and it's likely not our problem anyway.)

But it's a bit slow, because xfrd reads from the network socket using
fread() on an _IONBF'ed stream; under NetBSD, this results in a
sequence of one-character reads.  This behavior, as far as I can tell,
goes back all the way to V7 Unix; i.e., it's older than me.

So I've modified libxutil, which has its own IO indirection layer, to
switch to read(2) in the "unbuffered" case; the patch is attached.


--=-=-=
Content-Type: text/x-patch
Content-Disposition: attachment; filename=migrate-speed.patch
Content-Description: Have libxutil use read(2) instead of fread(3) for \"unbuffered\" I/O.

--- libxutil/file_stream.c.orig	2005-09-13 17:02:16.000000000 -0400
+++ libxutil/file_stream.c	2005-09-13 17:31:39.000000000 -0400
@@ -21,11 +21,13 @@
  */
 #ifndef __KERNEL__
 #include <stdio.h>
+#include <unistd.h>
 #include <stdlib.h>
 #include "allocate.h"
 #include "file_stream.h"
 
 static int file_read(IOStream *s, void *buf, size_t n);
+static int file_read_nbuf(IOStream *s, void* buf, size_t n);
 static int file_write(IOStream *s, const void *buf, size_t n);
 static int file_error(IOStream *s);
 static int file_close(IOStream *s);
@@ -42,6 +44,16 @@
     flush: file_flush,
 };
 
+/** Methods used by a FILE* IOStream that's unbuffered. */
+static const IOMethods file_methods_nbuf = {
+    read:  file_read_nbuf,
+    write: file_write,
+    error: file_error,
+    close: file_close,
+    free:  file_free,
+    flush: file_flush,
+};
+
 /** IOStream for stdin. */
 static IOStream _iostdin = {
     methods: &file_methods,
@@ -102,6 +114,7 @@
  * @return 0 on success, non-zero otherwise
  */
 int file_stream_setvbuf(IOStream *io, char *buf, int mode, size_t size){
+    io->methods = (mode == _IONBF) ? &file_methods_nbuf : &file_methods;
     return setvbuf(get_file(io), buf, mode, size);
 }
 
@@ -126,6 +139,15 @@
 static int file_read(IOStream *s, void *buf, size_t n){
     return fread(buf, 1, n, get_file(s));
 }
+static int file_read_nbuf(IOStream *s, void *buf, size_t n){
+    int fd = fileno(get_file(s)), rv, nr=0;
+    while(n > nr) {
+        rv = read(fd, buf+nr, n-nr);
+	if (rv <= 0) break;
+	nr += rv;
+    }
+    return nr;
+}
 
 /** Fush the underlying stream using fflush().
  *

--=-=-=

-- 
(let ((C call-with-current-continuation)) (apply (lambda (x y) (x y)) (map
((lambda (r) ((C C) (lambda (s) (r (lambda l (apply (s s) l))))))  (lambda
(f) (lambda (l) (if (null? l) C (lambda (k) (display (car l)) ((f (cdr l))
(C k)))))))    '((#\J #\d #\D #\v #\s) (#\e #\space #\a #\i #\newline)))))

--=-=-=--