On Mon, Sep 05, 2011 at 04:38:32PM +0800, Osier Yang wrote:
> 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 7028d72..c5809d2 100644
> --- a/src/qemu/qemu_driver.c
> +++ b/src/qemu/qemu_driver.c
> @@ -7224,8 +7224,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 4ceb536..0cc4702 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 854ee7f..9bbb8b0 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);

  ACK,

Daniel

-- 
Daniel Veillard      | libxml Gnome XML XSLT toolkit  http://xmlsoft.org/
dan...@veillard.com  | Rpmfind RPM search engine http://rpmfind.net/
http://veillard.com/ | virtualization library  http://libvirt.org/

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

Reply via email to