Patchwork [v5,7/7] Use qemu_put_buffer_async for guest memory pages

login
register
mail settings
Submitter Paolo Bonzini
Date April 5, 2013, 3:23 p.m.
Message ID <515EEC8C.8010203@redhat.com>
Download mbox | patch
Permalink /patch/234174/
State New
Headers show

Comments

Paolo Bonzini - April 5, 2013, 3:23 p.m.
Il 05/04/2013 15:44, Kevin Wolf ha scritto:
> This seems to have killed savevm performance. I noticed that
> qemu-iotests case 007 took forever on my test box (882 seconds instead
> of something like 10 seconds). It can be reproduced by this script:
> 
> export MALLOC_PERTURB_=11
> qemu-img create -f qcow2 -o compat=1.1 test.qcow2 1M
> time qemu-system-x86_64 -nographic -hda $TEST_IMG -serial none -monitor stdio <<EOF
> savevm test
> quit
> EOF
> 
> This used to take about 0.6s for me, after this patch it's around 10s.

The solution could be to make bdrv_load_vmstate take an iov/iovcnt pair.

Alternatively, you can try the attached patch.  I haven't yet tested it
though, and won't be able to do so today.

Paolo
Kevin Wolf - April 5, 2013, 3:39 p.m.
Am 05.04.2013 um 17:23 hat Paolo Bonzini geschrieben:
> Il 05/04/2013 15:44, Kevin Wolf ha scritto:
> > This seems to have killed savevm performance. I noticed that
> > qemu-iotests case 007 took forever on my test box (882 seconds instead
> > of something like 10 seconds). It can be reproduced by this script:
> > 
> > export MALLOC_PERTURB_=11
> > qemu-img create -f qcow2 -o compat=1.1 test.qcow2 1M
> > time qemu-system-x86_64 -nographic -hda $TEST_IMG -serial none -monitor stdio <<EOF
> > savevm test
> > quit
> > EOF
> > 
> > This used to take about 0.6s for me, after this patch it's around 10s.
> 
> The solution could be to make bdrv_load_vmstate take an iov/iovcnt pair.

Ah, so you're saying that instead of linearising the buffer it breaks up
the requests in tiny pieces?

Implementing vectored bdrv_load/save_vmstate should be easy in theory.

> Alternatively, you can try the attached patch.  I haven't yet tested it
> though, and won't be able to do so today.

Attempted to write to buffer while read buffer is not empty

Program received signal SIGABRT, Aborted.

Kevin

Patch

diff --git a/savevm.c b/savevm.c
index b1d8988..af99d64 100644
--- a/savevm.c
+++ b/savevm.c
@@ -525,27 +525,24 @@  static void qemu_file_set_error(QEMUFile *f, int ret)
 static void qemu_fflush(QEMUFile *f)
 {
     ssize_t ret = 0;
-    int i = 0;
 
     if (!f->ops->writev_buffer && !f->ops->put_buffer) {
         return;
     }
 
-    if (f->is_write && f->iovcnt > 0) {
+    if (f->is_write) {
         if (f->ops->writev_buffer) {
-            ret = f->ops->writev_buffer(f->opaque, f->iov, f->iovcnt);
-            if (ret >= 0) {
-                f->pos += ret;
+            if (f->iovcnt > 0) {
+                ret = f->ops->writev_buffer(f->opaque, f->iov, f->iovcnt);
             }
         } else {
-            for (i = 0; i < f->iovcnt && ret >= 0; i++) {
-                ret = f->ops->put_buffer(f->opaque, f->iov[i].iov_base, f->pos,
-                                         f->iov[i].iov_len);
-                if (ret >= 0) {
-                    f->pos += ret;
-                }
+            if (f->buf_index > 0) {
+                ret = f->ops->put_buffer(f->opaque, f->buf, f->pos, f->buf_index);
             }
         }
+        if (ret >= 0) {
+            f->pos += ret;
+        }
         f->buf_index = 0;
         f->iovcnt = 0;
     }
@@ -631,6 +628,11 @@  static void add_to_iovec(QEMUFile *f, const uint8_t *buf, int size)
         f->iov[f->iovcnt].iov_base = (uint8_t *)buf;
         f->iov[f->iovcnt++].iov_len = size;
     }
+
+    f->is_write = 1;
+    if (f->buf_index >= IO_BUF_SIZE || f->iovcnt >= MAX_IOV_SIZE) {
+        qemu_fflush(f);
+    }
 }
 
 void qemu_put_buffer_async(QEMUFile *f, const uint8_t *buf, int size)
@@ -645,13 +647,11 @@  void qemu_put_buffer_async(QEMUFile *f, const uint8_t *buf, int size)
         abort();
     }
 
-    add_to_iovec(f, buf, size);
-
-    f->is_write = 1;
-    f->bytes_xfer += size;
-
-    if (f->buf_index >= IO_BUF_SIZE || f->iovcnt >= MAX_IOV_SIZE) {
-        qemu_fflush(f);
+    if (f->ops->writev_buffer) {
+        f->bytes_xfer += size;
+        add_to_iovec(f, buf, size);
+    } else {
+        qemu_put_buffer(f, buf, size);
     }
 }
 
@@ -674,9 +674,17 @@  void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size)
         if (l > size)
             l = size;
         memcpy(f->buf + f->buf_index, buf, l);
-        f->is_write = 1;
-        f->buf_index += l;
-        qemu_put_buffer_async(f, f->buf + (f->buf_index - l), l);
+        f->bytes_xfer += size;
+        if (f->ops->writev_buffer) {
+            add_to_iovec(f, f->buf + f->buf_index, l);
+            f->buf_index += l;
+        } else {
+            f->is_write = 1;
+            f->buf_index += l;
+            if (f->buf_index == IO_BUF_SIZE) {
+                qemu_fflush(f);
+            }
+        }
         if (qemu_file_get_error(f)) {
             break;
         }
@@ -697,14 +705,16 @@  void qemu_put_byte(QEMUFile *f, int v)
         abort();
     }
 
-    f->buf[f->buf_index++] = v;
-    f->is_write = 1;
+    f->buf[f->buf_index] = v;
     f->bytes_xfer++;
-
-    add_to_iovec(f, f->buf + (f->buf_index - 1), 1);
-
-    if (f->buf_index >= IO_BUF_SIZE || f->iovcnt >= MAX_IOV_SIZE) {
-        qemu_fflush(f);
+    if (f->ops->writev_buffer) {
+        add_to_iovec(f, f->buf + f->buf_index, 1);
+        f->buf_index++;
+    } else {
+        f->buf_index++;
+        if (f->buf_index == IO_BUF_SIZE) {
+            qemu_fflush(f);
+        }
     }
 }