[libvirt] [PATCH 5/8] latency: Update monitor functions for new latency fields
Daniel Veillard
veillard at redhat.com
Tue Sep 6 03:54:37 UTC 2011
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/
daniel at veillard.com | Rpmfind RPM search engine http://rpmfind.net/
http://veillard.com/ | virtualization library http://libvirt.org/
More information about the libvir-list
mailing list