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@xxxxxxxxxxxx | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/ -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list