diff mbox

[v2] qcow2: Add cache-size=max option to optimize caches for performance

Message ID 1475605184-29375-1-git-send-email-eswierk@skyportsystems.com
State New
Headers show

Commit Message

Ed Swierk Oct. 4, 2016, 6:19 p.m. UTC
The optimal size of the qcow2 L2 cache depends on the working set size
and the cluster size of the virtual disk. If the cache is too small,
L2 tables are re-read from disk on every IO operation in the worst
case. The host's buffer cache can paper over this inefficiency, but
with cache=none or cache=directsync, L2 cache thrashing dramatically
reduces IO operations per second (e.g. from 50k/sec to 5k/sec for a
qcow2 stored on a modern SSD).

The default L2 cache size of 1 MB is optimal for an 8 GB working set
in a virtual disk with a 64 KB cluster size. The user can control the
cache size manually via the l2-cache-size and cache-size options, but
still has to compute the correct size based on working set and cluster
sizes.

This change adds a cache-size=max option that tells qemu to optimize
for qcow2 performance, making the L2 and refcount caches as large as
necessary to cover the entire virtual disk.

Signed-off-by: Ed Swierk <eswierk@skyportsystems.com>
---
 block/qcow2.c        | 16 +++++++++++++---
 docs/qcow2-cache.txt | 10 ++++++++--
 2 files changed, 21 insertions(+), 5 deletions(-)

Comments

no-reply@patchew.org Oct. 4, 2016, 9:50 p.m. UTC | #1
Hi,

Your series failed automatic build test. Please find the testing commands and
their output below. If you have docker installed, you can probably reproduce it
locally.

Type: series
Message-id: 1475605184-29375-1-git-send-email-eswierk@skyportsystems.com
Subject: [Qemu-devel] [PATCH v2] qcow2: Add cache-size=max option to optimize caches for performance

=== TEST SCRIPT BEGIN ===
#!/bin/bash
set -e
git submodule update --init dtc
# Let docker tests dump environment info
export SHOW_ENV=1
make J=8 docker-test-quick@centos6
make J=8 docker-test-mingw@fedora
=== TEST SCRIPT END ===

Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384
Switched to a new branch 'test'
859cc86 qcow2: Add cache-size=max option to optimize caches for performance

=== OUTPUT BEGIN ===
Submodule 'dtc' (git://git.qemu-project.org/dtc.git) registered for path 'dtc'
Cloning into 'dtc'...
Submodule path 'dtc': checked out '65cc4d2748a2c2e6f27f1cf39e07a5dbabd80ebf'
  BUILD centos6
=== OUTPUT END ===

Abort: command timeout (>3600 seconds)


---
Email generated automatically by Patchew [http://patchew.org/].
Please send your feedback to patchew-devel@freelists.org
diff mbox

Patch

diff --git a/block/qcow2.c b/block/qcow2.c
index 91ef4df..6f3a6ed 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -442,7 +442,7 @@  static QemuOptsList qcow2_runtime_opts = {
         },
         {
             .name = QCOW2_OPT_CACHE_SIZE,
-            .type = QEMU_OPT_SIZE,
+            .type = QEMU_OPT_STRING,
             .help = "Maximum combined metadata (L2 tables and refcount blocks) "
                     "cache size",
         },
@@ -525,18 +525,28 @@  static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts,
 {
     BDRVQcow2State *s = bs->opaque;
     uint64_t combined_cache_size;
-    bool l2_cache_size_set, refcount_cache_size_set, combined_cache_size_set;
+    bool l2_cache_size_set, refcount_cache_size_set;
+    const char *combined_cache_size_set;
 
     combined_cache_size_set = qemu_opt_get(opts, QCOW2_OPT_CACHE_SIZE);
     l2_cache_size_set = qemu_opt_get(opts, QCOW2_OPT_L2_CACHE_SIZE);
     refcount_cache_size_set = qemu_opt_get(opts, QCOW2_OPT_REFCOUNT_CACHE_SIZE);
 
-    combined_cache_size = qemu_opt_get_size(opts, QCOW2_OPT_CACHE_SIZE, 0);
     *l2_cache_size = qemu_opt_get_size(opts, QCOW2_OPT_L2_CACHE_SIZE, 0);
     *refcount_cache_size = qemu_opt_get_size(opts,
                                              QCOW2_OPT_REFCOUNT_CACHE_SIZE, 0);
 
     if (combined_cache_size_set) {
+        if (strcasecmp(combined_cache_size_set, "max"))
+            parse_option_size(QCOW2_OPT_CACHE_SIZE, combined_cache_size_set,
+                              &combined_cache_size, &error_abort);
+        else
+            combined_cache_size =
+                (bs->total_sectors * BDRV_SECTOR_SIZE * 8
+                 + s->cluster_size - 1) / s->cluster_size
+                * (DEFAULT_L2_REFCOUNT_SIZE_RATIO + 1)
+                / DEFAULT_L2_REFCOUNT_SIZE_RATIO;
+
         if (l2_cache_size_set && refcount_cache_size_set) {
             error_setg(errp, QCOW2_OPT_CACHE_SIZE ", " QCOW2_OPT_L2_CACHE_SIZE
                        " and " QCOW2_OPT_REFCOUNT_CACHE_SIZE " may not be set "
diff --git a/docs/qcow2-cache.txt b/docs/qcow2-cache.txt
index 5bb0607..c7ea9f3 100644
--- a/docs/qcow2-cache.txt
+++ b/docs/qcow2-cache.txt
@@ -114,9 +114,10 @@  There are three options available, and all of them take bytes:
 
 "l2-cache-size":         maximum size of the L2 table cache
 "refcount-cache-size":   maximum size of the refcount block cache
-"cache-size":            maximum size of both caches combined
+"cache-size":            maximum size of both caches combined, or
+                         "max" to cover entire disk
 
-There are two things that need to be taken into account:
+There are several things that need to be taken into account:
 
  - Both caches must have a size that is a multiple of the cluster
    size.
@@ -125,11 +126,16 @@  There are two things that need to be taken into account:
    adjust the others so that the L2 cache is 4 times bigger than the
    refcount cache.
 
+ - If you set cache-size to the special value "max", QEMU will
+   automatically size both caches to cover the entire virtual disk.
+
 This means that these options are equivalent:
 
    -drive file=hd.qcow2,l2-cache-size=2097152
    -drive file=hd.qcow2,refcount-cache-size=524288
    -drive file=hd.qcow2,cache-size=2621440
+   -drive file=hd.qcow2,cache-size=max [assuming hd.qcow2 is 16 GB
+                                        with 64 KB clusters]
 
 The reason for this 1/4 ratio is to ensure that both caches cover the
 same amount of disk space. Note however that this is only valid with