[Libguestfs] [PATCH libnbd v2 4/6] examples: copy-libev.c: Optimize zero extents

Nir Soffer nirsof at gmail.com
Thu Apr 22 20:56:24 UTC 2021


If the destination supports zero, try to zero entire extent in one
request. This speeds up copying of large sparse images. Same logic is
used by nbdcopy.

Here is an example benchmark, copying empty 1 TiB qcow2 image:

$ qemu-img create -f qcow2 src.qcow2 1t
$ qemu-img create -f qcow2 dst.qcow2 1t
$ qemu-nbd --persistent --socket=/tmp/src.sock --format=qcow2 --read-only src.qcow2
$ qemu-nbd --persistent --socket=/tmp/dst.sock --format=qcow2 dst.qcow2
$ export SRC=nbd+unix:///?socket=/tmp/src.sock
$ export DST=nbd+unix:///?socket=/tmp/dst.sock

$ hyperfine -w3 \
    "./copy-libev $SRC $DST" \
    "qemu-img convert -n -W $SRC $DST" \
    "../copy/nbdcopy --request-size=1048576 --requests=16 --connections=1 $SRC $DST"

Benchmark #1: ./copy-libev nbd+unix:///?socket=/tmp/src.sock nbd+unix:///?socket=/tmp/dst.sock
  Time (mean ± σ):     940.9 ms ±  36.3 ms    [User: 80.8 ms, System: 120.0 ms]
  Range (min … max):   892.8 ms … 1005.3 ms    10 runs

Benchmark #2: qemu-img convert -n -W nbd+unix:///?socket=/tmp/src.sock nbd+unix:///?socket=/tmp/dst.sock
  Time (mean ± σ):      2.848 s ±  0.087 s    [User: 241.7 ms, System: 253.9 ms]
  Range (min … max):    2.740 s …  3.035 s    10 runs

Benchmark #3: ../copy/nbdcopy --request-size=1048576 --requests=16 --connections=1 nbd+unix:///?socket=/tmp/src.sock nbd+unix:///?socket=/tmp/dst.sock
  Time (mean ± σ):      1.082 s ±  0.041 s    [User: 77.6 ms, System: 100.9 ms]
  Range (min … max):    1.043 s …  1.148 s    10 runs

Summary
  './copy-libev nbd+unix:///?socket=/tmp/src.sock nbd+unix:///?socket=/tmp/dst.sock' ran
    1.15 ± 0.06 times faster than '../copy/nbdcopy --request-size=1048576 --requests=16 --connections=1 nbd+unix:///?socket=/tmp/src.sock nbd+unix:///?socket=/tmp/dst.sock'
    3.03 ± 0.15 times faster than 'qemu-img convert -n -W nbd+unix:///?socket=/tmp/src.sock nbd+unix:///?socket=/tmp/dst.sock'

Signed-off-by: Nir Soffer <nsoffer at redhat.com>
---
 examples/copy-libev.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/examples/copy-libev.c b/examples/copy-libev.c
index 197d959..d9c8560 100644
--- a/examples/copy-libev.c
+++ b/examples/copy-libev.c
@@ -248,7 +248,7 @@ start_extents (struct request *r)
 static void
 next_extent (struct request *r)
 {
-    uint32_t limit = MIN (REQUEST_SIZE, size - offset);
+    uint32_t limit;
     uint32_t length = 0;
     bool is_zero;
 
@@ -256,6 +256,12 @@ next_extent (struct request *r)
 
     is_zero = extents[extents_pos + 1] & LIBNBD_STATE_ZERO;
 
+    /* Zero can be much faster, so try to zero entire extent. */
+    if (is_zero && dst.can_zero)
+        limit = MIN (EXTENTS_SIZE, size - offset);
+    else
+        limit = MIN (REQUEST_SIZE, size - offset);
+
     while (length < limit) {
         DEBUG ("e%d: offset=%ld len=%ld zero=%d",
                extents_pos / 2, offset, extents[extents_pos], is_zero);
-- 
2.26.3




More information about the Libguestfs mailing list