[libvirt] [PATCH 5/8] latency: Update monitor functions for new latency fields

Osier Yang jyang at redhat.com
Wed Aug 31 08:26:10 UTC 2011


The mainly changes are:

1) Update qemuMonitorGetBlockStatsInfo and it's children (Text/JSON)
   functions to return the value of new latency fields.
2) Add new function qemuMonitorGetBlockStatsParamsNumber, which is
   to count how many parameters the underlying QEMU supports.
3) Update virDomainBlockStats in src/qemu/qemu_driver.c to be
   compatible with the changes by 1).
---
 src/qemu/qemu_driver.c       |    4 ++
 src/qemu/qemu_monitor.c      |   35 ++++++++++++
 src/qemu/qemu_monitor.h      |    6 ++
 src/qemu/qemu_monitor_json.c |  124 +++++++++++++++++++++++++++++++++++++++++-
 src/qemu/qemu_monitor_json.h |    6 ++
 src/qemu/qemu_monitor_text.c |  121 +++++++++++++++++++++++++++++++++++++----
 src/qemu/qemu_monitor_text.h |    6 ++
 7 files changed, 291 insertions(+), 11 deletions(-)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index f21122d..03fadae 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -6823,8 +6823,12 @@ qemudDomainBlockStats (virDomainPtr dom,
                                        disk->info.alias,
                                        &stats->rd_req,
                                        &stats->rd_bytes,
+                                       NULL,
                                        &stats->wr_req,
                                        &stats->wr_bytes,
+                                       NULL,
+                                       NULL,
+                                       NULL,
                                        &stats->errs);
     qemuDomainObjExitMonitor(driver, vm);
 
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index db6107c..92631ae 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -1201,8 +1201,12 @@ int qemuMonitorGetBlockStatsInfo(qemuMonitorPtr mon,
                                  const char *devname,
                                  long long *rd_req,
                                  long long *rd_bytes,
+                                 long long *rd_total_times,
                                  long long *wr_req,
                                  long long *wr_bytes,
+                                 long long *wr_total_times,
+                                 long long *flush_req,
+                                 long long *flush_total_times,
                                  long long *errs)
 {
     int ret;
@@ -1217,16 +1221,47 @@ int qemuMonitorGetBlockStatsInfo(qemuMonitorPtr mon,
     if (mon->json)
         ret = qemuMonitorJSONGetBlockStatsInfo(mon, devname,
                                                rd_req, rd_bytes,
+                                               rd_total_times,
                                                wr_req, wr_bytes,
+                                               wr_total_times,
+                                               flush_req,
+                                               flush_total_times,
                                                errs);
     else
         ret = qemuMonitorTextGetBlockStatsInfo(mon, devname,
                                                rd_req, rd_bytes,
+                                               rd_total_times,
                                                wr_req, wr_bytes,
+                                               wr_total_times,
+                                               flush_req,
+                                               flush_total_times,
                                                errs);
     return ret;
 }
 
+/* Return 0 and update @nparams with the number of block stats
+ * QEMU supports if success. Return -1 if failure.
+ */
+int qemuMonitorGetBlockStatsParamsNumber(qemuMonitorPtr mon,
+                                         int *nparams)
+{
+    int ret;
+    VIR_DEBUG("mon=%p nparams=%p", mon, nparams);
+
+    if (!mon) {
+        qemuReportError(VIR_ERR_INVALID_ARG, "%s",
+                        _("monitor must not be NULL"));
+        return -1;
+    }
+
+    if (mon->json)
+        ret = qemuMonitorJSONGetBlockStatsParamsNumber(mon, nparams);
+    else
+        ret = qemuMonitorTextGetBlockStatsParamsNumber(mon, nparams);
+
+    return ret;
+}
+
 int qemuMonitorGetBlockExtent(qemuMonitorPtr mon,
                               const char *devname,
                               unsigned long long *extent)
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index f241c9e..1b9d98d 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -212,9 +212,15 @@ int qemuMonitorGetBlockStatsInfo(qemuMonitorPtr mon,
                                  const char *devname,
                                  long long *rd_req,
                                  long long *rd_bytes,
+                                 long long *rd_total_times,
                                  long long *wr_req,
                                  long long *wr_bytes,
+                                 long long *wr_total_times,
+                                 long long *flush_req,
+                                 long long *flush_total_times,
                                  long long *errs);
+int qemuMonitorGetBlockStatsParamsNumber(qemuMonitorPtr mon,
+                                         int *nparams);
 
 int qemuMonitorGetBlockExtent(qemuMonitorPtr mon,
                               const char *devname,
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 715b26e..77a2545 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -1318,8 +1318,12 @@ int qemuMonitorJSONGetBlockStatsInfo(qemuMonitorPtr mon,
                                      const char *devname,
                                      long long *rd_req,
                                      long long *rd_bytes,
+                                     long long *rd_total_times,
                                      long long *wr_req,
                                      long long *wr_bytes,
+                                     long long *wr_total_times,
+                                     long long *flush_req,
+                                     long long *flush_total_times,
                                      long long *errs)
 {
     int ret;
@@ -1330,7 +1334,17 @@ int qemuMonitorJSONGetBlockStatsInfo(qemuMonitorPtr mon,
     virJSONValuePtr reply = NULL;
     virJSONValuePtr devices;
 
-    *rd_req = *rd_bytes = *wr_req = *wr_bytes = *errs = 0;
+    *rd_req = *rd_bytes = -1;
+    *wr_req = *wr_bytes = *errs = -1;
+
+    if (rd_total_times)
+        *rd_total_times = -1;
+    if (wr_total_times)
+        *wr_total_times = -1;
+    if (flush_req)
+        *flush_req = -1;
+    if (flush_total_times)
+        *flush_total_times = -1;
 
     if (!cmd)
         return -1;
@@ -1396,6 +1410,15 @@ int qemuMonitorJSONGetBlockStatsInfo(qemuMonitorPtr mon,
                             "rd_operations");
             goto cleanup;
         }
+        if (rd_total_times &&
+            virJSONValueObjectHasKey(stats, "rd_total_times_ns") &&
+            (virJSONValueObjectGetNumberLong(stats, "rd_total_times_ns",
+                                             rd_total_times) < 0)) {
+            qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                            _("cannot read %s statistic"),
+                            "rd_total_times_ns");
+            goto cleanup;
+        }
         if (virJSONValueObjectGetNumberLong(stats, "wr_bytes", wr_bytes) < 0) {
             qemuReportError(VIR_ERR_INTERNAL_ERROR,
                             _("cannot read %s statistic"),
@@ -1408,6 +1431,33 @@ int qemuMonitorJSONGetBlockStatsInfo(qemuMonitorPtr mon,
                             "wr_operations");
             goto cleanup;
         }
+        if (wr_total_times &&
+            virJSONValueObjectHasKey(stats, "wr_total_times_ns") &&
+            (virJSONValueObjectGetNumberLong(stats, "wr_total_times_ns",
+                                             wr_total_times) < 0)) {
+            qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                            _("cannot read %s statistic"),
+                            "wr_total_times_ns");
+            goto cleanup;
+        }
+        if (flush_req &&
+            virJSONValueObjectHasKey(stats, "flush_operations") &&
+            (virJSONValueObjectGetNumberLong(stats, "flush_operations",
+                                            flush_req) < 0)) {
+            qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                            _("cannot read %s statistic"),
+                            "flush_operations");
+            goto cleanup;
+        }
+        if (flush_total_times &&
+            virJSONValueObjectHasKey(stats, "flush_total_times_ns") &&
+            (virJSONValueObjectGetNumberLong(stats, "flush_total_times_ns",
+                                            flush_total_times) < 0)) {
+            qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                            _("cannot read %s statistic"),
+                            "flush_total_times_ns");
+            goto cleanup;
+        }
     }
 
     if (!found) {
@@ -1424,6 +1474,78 @@ cleanup:
 }
 
 
+int qemuMonitorJSONGetBlockStatsParamsNumber(qemuMonitorPtr mon,
+                                             int *nparams)
+{
+    int ret, i, num = 0;
+    virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("query-blockstats",
+                                                     NULL);
+    virJSONValuePtr reply = NULL;
+    virJSONValuePtr devices = NULL;
+    virJSONValuePtr dev = NULL;
+    virJSONValuePtr stats = NULL;
+
+    if (!cmd)
+        return -1;
+
+    ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+    if (ret == 0)
+        ret = qemuMonitorJSONCheckError(cmd, reply);
+    if (ret < 0)
+        goto cleanup;
+    ret = -1;
+
+    devices = virJSONValueObjectGet(reply, "return");
+    if (!devices || devices->type != VIR_JSON_TYPE_ARRAY) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                        _("blockstats reply was missing device list"));
+        goto cleanup;
+    }
+
+    dev = virJSONValueArrayGet(devices, 0);
+
+    if (!dev || dev->type != VIR_JSON_TYPE_OBJECT) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                        _("blockstats device entry was not in expected format"));
+        goto cleanup;
+    }
+
+    if ((stats = virJSONValueObjectGet(dev, "stats")) == NULL ||
+        stats->type != VIR_JSON_TYPE_OBJECT) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                        _("blockstats stats entry was not in expected format"));
+        goto cleanup;
+    }
+
+    for (i = 0 ; i < stats->data.object.npairs; i++) {
+        const char *key = stats->data.object.pairs[i].key;
+
+        if (STREQ(key, "rd_bytes") ||
+            STREQ(key, "rd_operations") ||
+            STREQ(key, "rd_total_times_ns") ||
+            STREQ(key, "wr_bytes") ||
+            STREQ(key, "wr_operations") ||
+            STREQ(key, "wr_total_times_ns") ||
+            STREQ(key, "flush_operations") ||
+            STREQ(key, "flush_total_times_ns")) {
+            num++;
+        } else {
+            /* wr_highest_offset is parsed by qemuMonitorJSONGetBlockExtent. */
+            if (STRNEQ(key, "wr_highest_offset"))
+                VIR_DEBUG("Missed block stat: %s", key);
+        }
+    }
+
+    *nparams = num;
+    ret = 0;
+
+cleanup:
+    virJSONValueFree(cmd);
+    virJSONValueFree(reply);
+    return ret;
+}
+
 int qemuMonitorJSONGetBlockExtent(qemuMonitorPtr mon,
                                   const char *devname,
                                   unsigned long long *extent)
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index 9512793..ec9fecb 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -64,9 +64,15 @@ int qemuMonitorJSONGetBlockStatsInfo(qemuMonitorPtr mon,
                                      const char *devname,
                                      long long *rd_req,
                                      long long *rd_bytes,
+                                     long long *rd_total_times,
                                      long long *wr_req,
                                      long long *wr_bytes,
+                                     long long *wr_total_times,
+                                     long long *flush_req,
+                                     long long *flush_total_times,
                                      long long *errs);
+int qemuMonitorJSONGetBlockStatsParamsNumber(qemuMonitorPtr mon,
+                                             int *nparams);
 int qemuMonitorJSONGetBlockExtent(qemuMonitorPtr mon,
                                   const char *devname,
                                   unsigned long long *extent);
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c
index 4bd761d..fab5e19 100644
--- a/src/qemu/qemu_monitor_text.c
+++ b/src/qemu/qemu_monitor_text.c
@@ -708,8 +708,12 @@ int qemuMonitorTextGetBlockStatsInfo(qemuMonitorPtr mon,
                                      const char *devname,
                                      long long *rd_req,
                                      long long *rd_bytes,
+                                     long long *rd_total_times,
                                      long long *wr_req,
                                      long long *wr_bytes,
+                                     long long *wr_total_times,
+                                     long long *flush_req,
+                                     long long *flush_total_times,
                                      long long *errs)
 {
     char *info = NULL;
@@ -736,11 +740,17 @@ int qemuMonitorTextGetBlockStatsInfo(qemuMonitorPtr mon,
         goto cleanup;
     }
 
-    *rd_req = -1;
-    *rd_bytes = -1;
-    *wr_req = -1;
-    *wr_bytes = -1;
-    *errs = -1;
+    *rd_req = *rd_bytes = -1;
+    *wr_req = *wr_bytes = *errs = -1;
+
+    if (rd_total_times)
+        *rd_total_times = -1;
+    if (wr_total_times)
+        *wr_total_times = -1;
+    if (flush_req)
+        *flush_req = -1;
+    if (flush_total_times)
+        *flush_total_times = -1;
 
     /* The output format for both qemu & KVM is:
      *   blockdevice: rd_bytes=% wr_bytes=% rd_operations=% wr_operations=%
@@ -768,23 +778,44 @@ int qemuMonitorTextGetBlockStatsInfo(qemuMonitorPtr mon,
 
             while (*p) {
                 if (STRPREFIX (p, "rd_bytes=")) {
-                    p += 9;
+                    p += strlen("rd_bytes=");
                     if (virStrToLong_ll (p, &dummy, 10, rd_bytes) == -1)
                         VIR_DEBUG ("error reading rd_bytes: %s", p);
                 } else if (STRPREFIX (p, "wr_bytes=")) {
-                    p += 9;
+                    p += strlen("wr_bytes=");
                     if (virStrToLong_ll (p, &dummy, 10, wr_bytes) == -1)
                         VIR_DEBUG ("error reading wr_bytes: %s", p);
                 } else if (STRPREFIX (p, "rd_operations=")) {
-                    p += 14;
+                    p += strlen("rd_operations=");
                     if (virStrToLong_ll (p, &dummy, 10, rd_req) == -1)
                         VIR_DEBUG ("error reading rd_req: %s", p);
                 } else if (STRPREFIX (p, "wr_operations=")) {
-                    p += 14;
+                    p += strlen("wr_operations=");
                     if (virStrToLong_ll (p, &dummy, 10, wr_req) == -1)
                         VIR_DEBUG ("error reading wr_req: %s", p);
-                } else
+                } else if (rd_total_times &&
+                           STRPREFIX (p, "rd_total_times_ns=")) {
+                    p += strlen("rd_total_times_ns=");
+                    if (virStrToLong_ll (p, &dummy, 10, rd_total_times) == -1)
+                        VIR_DEBUG ("error reading rd_total_times: %s", p);
+                } else if (wr_total_times &&
+                           STRPREFIX (p, "wr_total_times_ns=")) {
+                    p += strlen("wr_total_times_ns=");
+                    if (virStrToLong_ll (p, &dummy, 10, wr_total_times) == -1)
+                        VIR_DEBUG ("error reading wr_total_times: %s", p);
+                } else if (flush_req &&
+                           STRPREFIX (p, "flush_operations=")) {
+                    p += strlen("flush_operations=");
+                    if (virStrToLong_ll (p, &dummy, 10, flush_req) == -1)
+                        VIR_DEBUG ("error reading flush_req: %s", p);
+                } else if (flush_total_times &&
+                           STRPREFIX (p, "flush_total_times_ns=")) {
+                    p += strlen("flush_total_times_ns=");
+                    if (virStrToLong_ll (p, &dummy, 10, flush_total_times) == -1)
+                        VIR_DEBUG ("error reading flush_total_times: %s", p);
+                } else {
                     VIR_DEBUG ("unknown block stat near %s", p);
+                }
 
                 /* Skip to next label. */
                 p = strchr (p, ' ');
@@ -810,6 +841,76 @@ int qemuMonitorTextGetBlockStatsInfo(qemuMonitorPtr mon,
     return ret;
 }
 
+int qemuMonitorTextGetBlockStatsParamsNumber(qemuMonitorPtr mon,
+                                             int *nparams)
+{
+    char *info = NULL;
+    int ret = -1;
+    int num = 0;
+    const char *p, *eol;
+
+    if (qemuMonitorHMPCommand (mon, "info blockstats", &info) < 0) {
+        qemuReportError(VIR_ERR_OPERATION_FAILED,
+                        "%s", _("'info blockstats' command failed"));
+        goto cleanup;
+    }
+
+    /* If the command isn't supported then qemu prints the supported
+     * info commands, so the output starts "info ".  Since this is
+     * unlikely to be the name of a block device, we can use this
+     * to detect if qemu supports the command.
+     */
+    if (strstr(info, "\ninfo ")) {
+        qemuReportError(VIR_ERR_OPERATION_INVALID,
+                        "%s",
+                        _("'info blockstats' not supported by this qemu"));
+        goto cleanup;
+    }
+
+    /* The output format for both qemu & KVM is:
+     *   blockdevice: rd_bytes=% wr_bytes=% rd_operations=% wr_operations=%
+     *   (repeated for each block device)
+     * where '%' is a 64 bit number.
+     */
+    p = info;
+
+    eol = strchr (p, '\n');
+    if (!eol)
+        eol = p + strlen (p);
+
+    /* Skip the device name and following ":", and spaces (e.g.
+     * "floppy0: ")
+     */
+    p = strchr(p, ' ');
+    p++;
+
+    while (*p) {
+            if (STRPREFIX (p, "rd_bytes=") ||
+                STRPREFIX (p, "wr_bytes=") ||
+                STRPREFIX (p, "rd_operations=") ||
+                STRPREFIX (p, "wr_operations=") ||
+                STRPREFIX (p, "rd_total_times_ns=") ||
+                STRPREFIX (p, "wr_total_times_ns=") ||
+                STRPREFIX (p, "flush_operations=") ||
+                STRPREFIX (p, "flush_total_times_ns=")) {
+                num++;
+            } else {
+                VIR_DEBUG ("unknown block stat near %s", p);
+            }
+
+            /* Skip to next label. */
+            p = strchr (p, ' ');
+            if (!p || p >= eol) break;
+            p++;
+    }
+
+    *nparams = num;
+    ret = 0;
+
+ cleanup:
+    VIR_FREE(info);
+    return ret;
+}
 
 int qemuMonitorTextGetBlockExtent(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
                                   const char *devname ATTRIBUTE_UNUSED,
diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h
index b250738..de6fbcc 100644
--- a/src/qemu/qemu_monitor_text.h
+++ b/src/qemu/qemu_monitor_text.h
@@ -61,9 +61,15 @@ int qemuMonitorTextGetBlockStatsInfo(qemuMonitorPtr mon,
                                      const char *devname,
                                      long long *rd_req,
                                      long long *rd_bytes,
+                                     long long *rd_total_times,
                                      long long *wr_req,
                                      long long *wr_bytes,
+                                     long long *wr_total_times,
+                                     long long *flush_req,
+                                     long long *flush_total_times,
                                      long long *errs);
+int qemuMonitorTextGetBlockStatsParamsNumber(qemuMonitorPtr mon,
+                                             int *nparams);
 int qemuMonitorTextGetBlockExtent(qemuMonitorPtr mon,
                                   const char *devname,
                                   unsigned long long *extent);
-- 
1.7.6




More information about the libvir-list mailing list