[libvirt] [PATCH v7 6/7] qemu: add cache for DomainMemoryStats

Derbyshev Dmitriy dderbyshev at virtuozzo.com
Wed Jul 13 10:42:17 UTC 2016


From: Igor Redko <redkoi at virtuozzo.com>

Communication with qemu monitor is time-consuming and there is
additional overhead for converting qemu_binary->json->libvirt_binary.

This patch tries to avoid unnecessary qmp queries.
Knowing period of balloon statistics update cycle and timestamps of last update
provided by qemu, it is possible to make cache of last response and reuse it
for next requests.

Signed-off-by: Igor Redko <redkoi at virtuozzo.com>
Signed-off-by: Derbyshev Dmitry <dderbyshev at virtuozzo.com>
---
 src/qemu/qemu_domain.h |   6 +++
 src/qemu/qemu_driver.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 105 insertions(+), 1 deletion(-)

diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
index 114db98..90cddfd 100644
--- a/src/qemu/qemu_domain.h
+++ b/src/qemu/qemu_domain.h
@@ -213,6 +213,12 @@ struct _qemuDomainObjPrivate {
 
     qemuDomainUnpluggingDevice unplug;
 
+    unsigned long long cacheExpires;
+    unsigned int cacheNrStats;
+    virDomainMemoryStatStruct cacheStats[VIR_DOMAIN_MEMORY_STAT_NR];
+
+    virCond unplugFinished; /* signals that unpluggingDevice was unplugged */
+    const char *unpluggingDevice; /* alias of the device that is being unplugged */
     char **qemuDevices; /* NULL-terminated list of devices aliases known to QEMU */
 
     bool hookRun;  /* true if there was a hook run over this domain */
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 70f3faa..616b87d 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -10962,6 +10962,96 @@ qemuDomainGetInterfaceParameters(virDomainPtr dom,
 /* This functions assumes that job QEMU_JOB_QUERY is started by a caller */
 
 static int
+qemuDomainCacheMemoryStats(virDomainObjPtr vm,
+                           virDomainMemoryStatPtr stats,
+                           unsigned int nr_stats,
+                           unsigned int flags)
+{
+    unsigned long long now;
+    unsigned long long expires;
+    unsigned long long timestamp;
+    size_t i;
+    virDomainDefPtr def;
+    qemuDomainObjPrivatePtr priv;
+    int ret = -1;
+
+    if (nr_stats <= 0 || nr_stats > VIR_DOMAIN_MEMORY_STAT_NR)
+        goto cleanup;
+
+    if (virDomainObjGetDefs(vm, flags, &def, NULL) < 0)
+        goto cleanup;
+
+    if (def->memballoon->period <= 0)
+        goto cleanup;
+
+    if (virTimeMillisNow(&now) < 0)
+        goto cleanup;
+
+    priv = vm->privateData;
+    timestamp = now;
+
+    for (i = 0; i < nr_stats; i++){
+        if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_LAST_UPDATE){
+            /* QEMU timestamps are in secs */
+            timestamp = stats[i].val * 1000;
+            break;
+        }
+    }
+    /* period also in secs */
+    expires = (timestamp > now) ? now : timestamp + def->memballoon->period * 1000;
+
+    if (expires < now || expires <= priv->cacheExpires)
+        goto cleanup;
+
+    priv->cacheExpires = expires;
+    memcpy(priv->cacheStats, stats, nr_stats * sizeof(*stats));
+    priv->cacheNrStats = nr_stats;
+    ret = nr_stats;
+
+ cleanup:
+    return ret;
+}
+
+static int
+qemuDomainCachedMemoryStats(virDomainObjPtr vm,
+                            virDomainMemoryStatPtr stats,
+                            unsigned int nr_stats,
+                            unsigned int flags)
+{
+    unsigned long long now;
+    virDomainDefPtr def;
+    qemuDomainObjPrivatePtr priv;
+    int ret = -1;
+
+    if (virTimeMillisNow(&now) < 0)
+        goto cleanup;
+
+    priv = vm->privateData;
+
+    if (nr_stats <= 0 || nr_stats > priv->cacheNrStats)
+        goto cleanup;
+
+    if (now > priv->cacheExpires){
+        goto cleanup;
+    }
+
+    if (virDomainObjGetDefs(vm, flags, &def, NULL) < 0)
+        goto cleanup;
+
+    /* If period was changed or system time driffted we drop caches */
+    if (now + def->memballoon->period * 1000 < priv->cacheExpires){
+        priv->cacheNrStats = 0;
+        goto cleanup;
+    }
+
+    memcpy(stats, priv->cacheStats, nr_stats * sizeof(*stats));
+    return nr_stats;
+
+ cleanup:
+    return ret;
+}
+
+static int
 qemuDomainMemoryStatsInternal(virQEMUDriverPtr driver,
                               virDomainObjPtr vm,
                               virDomainMemoryStatPtr stats,
@@ -10977,6 +11067,11 @@ qemuDomainMemoryStatsInternal(virQEMUDriverPtr driver,
         return -1;
     }
 
+    ret = qemuDomainCachedMemoryStats(vm, stats, nr_stats, 0);
+
+    if (ret > 0)
+        goto cleanup;
+
     if (vm->def->memballoon &&
         vm->def->memballoon->model == VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO) {
         qemuDomainObjEnterMonitor(driver, vm);
@@ -10985,7 +11080,7 @@ qemuDomainMemoryStatsInternal(virQEMUDriverPtr driver,
             ret = -1;
 
         if (ret < 0 || ret >= nr_stats)
-            return ret;
+            goto cache;
     } else {
         ret = 0;
     }
@@ -10999,6 +11094,9 @@ qemuDomainMemoryStatsInternal(virQEMUDriverPtr driver,
         ret++;
     }
 
+ cache:
+    qemuDomainCacheMemoryStats(vm, stats, ret, 0);
+ cleanup:
     return ret;
 }
 
-- 
1.9.5.msysgit.0




More information about the libvir-list mailing list