This patch add the block group for bulk stats.
The following typed parameter used for each block stats:
block.count - number of block devices in this domain
block.0.name - name of the block device
block.0.rd_bytes - number of read bytes
block.0.rd_operations - number of read requests
block.0.rd_total_time - total time spend on cache reads in nano-seconds
block.0.wr_bytes - number of write bytes
block.0.wr_operations - number of write requests
block.0.wr_total_time - total time spend on cache write in nano-seconds
block.0.flush_operations - total flush requests
block.0.flush_total_time - total time spend on cache flushing in nano-seconds
Signed-off-by: Li Wei <lw(a)cn.fujitsu.com>
---
include/libvirt/libvirt.h.in | 1 +
src/libvirt.c | 13 ++++
src/qemu/qemu_driver.c | 31 ++++++++
src/qemu/qemu_monitor.c | 23 ++++++
src/qemu/qemu_monitor.h | 5 ++
src/qemu/qemu_monitor_json.c | 170 +++++++++++++++++++++++++++++++++++++++++++
src/qemu/qemu_monitor_json.h | 5 ++
7 files changed, 248 insertions(+)
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index 9358314..36c4fec 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -2511,6 +2511,7 @@ struct _virDomainStatsRecord {
typedef enum {
VIR_DOMAIN_STATS_STATE = (1 << 0), /* return domain state */
+ VIR_DOMAIN_STATS_BLOCK = (1 << 1), /* return block stats */
} virDomainStatsTypes;
typedef enum {
diff --git a/src/libvirt.c b/src/libvirt.c
index 5d8f01c..ca0d071 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -21632,6 +21632,19 @@ virConnectGetAllDomainStats(virConnectPtr conn,
* "state.reason" - reason for entering given state, returned as int from
* virDomain*Reason enum corresponding to given state.
*
+ * VIR_DOMAIN_STATS_BLOCK: Return block device stats. The typed parameter keys
+ * are in this format:
+ * "block.count" - number of block devices in this domain
+ * "block.0.name" - name of the block device
+ * "block.0.rd_bytes" - number of read bytes
+ * "block.0.rd_operations" - number of read requests
+ * "block.0.rd_total_time" - total time spend on cache reads in nano-seconds
+ * "block.0.wr_bytes" - number of write bytes
+ * "block.0.wr_operations" - number of write requests
+ * "block.0.wr_total_time" - total time spend on cache write in nano-seconds
+ * "block.0.flush_operations" - total flush requests
+ * "block.0.flush_total_time" - total time spend on cache flushing in
nano-seconds
+ *
* Using 0 for @stats returns all stats groups supported by the given
* hypervisor.
*
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 239a300..ef4d3be 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -17221,6 +17221,36 @@ qemuDomainGetStatsState(virDomainObjPtr dom,
}
+static int
+qemuDomainGetStatsBlock(virDomainObjPtr dom,
+ virDomainStatsRecordPtr record,
+ int *maxparams,
+ unsigned int flags)
+{
+ int ret;
+ qemuDomainObjPrivatePtr priv = dom->privateData;
+
+ /* only valid for active domain, ignore inactive ones silently */
+ if (!virDomainObjIsActive(dom))
+ return 0;
+
+ if (qemuDomainObjBeginJob(qemu_driver, dom, QEMU_JOB_QUERY) < 0)
+ return -1;
+
+ qemuDomainObjEnterMonitor(qemu_driver, dom);
+ ret = qemuMonitorDomainGetStatsBlock(priv->mon,
+ record,
+ maxparams,
+ flags);
+ qemuDomainObjExitMonitor(qemu_driver, dom);
+
+ if (qemuDomainObjEndJob(qemu_driver, dom) < 0)
+ return -1;
+
+ return ret;
+}
+
+
typedef int
(*qemuDomainGetStatsFunc)(virDomainObjPtr dom,
virDomainStatsRecordPtr record,
@@ -17234,6 +17264,7 @@ struct qemuDomainGetStatsWorker {
static struct qemuDomainGetStatsWorker qemuDomainGetStatsWorkers[] = {
{ qemuDomainGetStatsState, VIR_DOMAIN_STATS_STATE},
+ { qemuDomainGetStatsBlock, VIR_DOMAIN_STATS_BLOCK},
{ NULL, 0 }
};
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 5b2952a..83d1dc3 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -4071,3 +4071,26 @@ qemuMonitorRTCResetReinjection(qemuMonitorPtr mon)
return qemuMonitorJSONRTCResetReinjection(mon);
}
+
+int
+qemuMonitorDomainGetStatsBlock(qemuMonitorPtr mon,
+ virDomainStatsRecordPtr record,
+ int *maxparams,
+ unsigned int flags)
+{
+ VIR_DEBUG("mon=%p", mon);
+
+ if (!mon) {
+ virReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("monitor must not be NULL"));
+ return -1;
+ }
+
+ if (!mon->json) {
+ virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+ _("JSON monitor is required"));
+ return -1;
+ }
+
+ return qemuMonitorJSONDomainGetStatsBlock(mon, record, maxparams, flags);
+}
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 4fd6f01..6f77ecc 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -792,6 +792,11 @@ int qemuMonitorGetGuestCPU(qemuMonitorPtr mon,
int qemuMonitorRTCResetReinjection(qemuMonitorPtr mon);
+int
+qemuMonitorDomainGetStatsBlock(qemuMonitorPtr mon,
+ virDomainStatsRecordPtr record,
+ int *maxparams,
+ unsigned int flags);
/**
* When running two dd process and using <> redirection, we need a
* shell that will not truncate files. These two strings serve that
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 62e7d5d..282635a 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -5872,3 +5872,173 @@ qemuMonitorJSONRTCResetReinjection(qemuMonitorPtr mon)
virJSONValueFree(reply);
return ret;
}
+
+int
+qemuMonitorJSONDomainGetStatsBlock(qemuMonitorPtr mon,
+ virDomainStatsRecordPtr record,
+ int *maxparams,
+ unsigned int privflags ATTRIBUTE_UNUSED)
+{
+ int ret, i, nblocks = 0;
+ virJSONValuePtr cmd, devices;
+ virJSONValuePtr reply = NULL;
+ char field[VIR_TYPED_PARAM_FIELD_LENGTH];
+
+ if (!(cmd = qemuMonitorJSONMakeCommand("query-blockstats", NULL)))
+ 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) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("blockstats reply was missing device list"));
+ goto cleanup;
+ }
+
+ if (virTypedParamsAddInt(&record->params,
+ &record->nparams,
+ maxparams,
+ "block.count",
+ virJSONValueArraySize(devices)) < 0)
+ goto cleanup;
+
+ for (i = 0; i < virJSONValueArraySize(devices); i++) {
+ virJSONValuePtr dev = virJSONValueArrayGet(devices, i);
+ virJSONValuePtr stats;
+ long long int llvalue;
+ const char *block_name;
+
+ if (!dev || dev->type != VIR_JSON_TYPE_OBJECT) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("blockstats device entry was not in expected
format"));
+ goto cleanup;
+ }
+
+ if ((block_name = virJSONValueObjectGetString(dev, "device")) == NULL)
{
+ virReportError(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) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("blockstats device entry was not in expected
format"));
+ goto cleanup;
+ }
+
+ snprintf(field, VIR_TYPED_PARAM_FIELD_LENGTH, "block.%d.name",
nblocks);
+ if (virTypedParamsAddString(&record->params,
+ &record->nparams,
+ maxparams,
+ field,
+ block_name) < 0)
+ goto cleanup;
+
+ if (virJSONValueObjectGetNumberLong(stats, "rd_bytes", &llvalue)
< 0)
+ goto cleanup;
+
+ snprintf(field, VIR_TYPED_PARAM_FIELD_LENGTH, "block.%d.rd_bytes",
nblocks);
+ if (virTypedParamsAddLLong(&record->params,
+ &record->nparams,
+ maxparams,
+ field,
+ llvalue) < 0)
+ goto cleanup;
+
+ if (virJSONValueObjectGetNumberLong(stats, "rd_operations",
&llvalue) < 0)
+ goto cleanup;
+
+ snprintf(field, VIR_TYPED_PARAM_FIELD_LENGTH, "block.%d.rd_operations",
nblocks);
+ if (virTypedParamsAddLLong(&record->params,
+ &record->nparams,
+ maxparams,
+ field,
+ llvalue) < 0)
+ goto cleanup;
+
+ if (virJSONValueObjectGetNumberLong(stats, "rd_total_time_ns",
&llvalue) < 0)
+ goto cleanup;
+
+ snprintf(field, VIR_TYPED_PARAM_FIELD_LENGTH, "block.%d.rd_total_time",
nblocks);
+ if (virTypedParamsAddLLong(&record->params,
+ &record->nparams,
+ maxparams,
+ field,
+ llvalue) < 0)
+ goto cleanup;
+
+ if (virJSONValueObjectGetNumberLong(stats, "wr_bytes", &llvalue)
< 0)
+ goto cleanup;
+
+ snprintf(field, VIR_TYPED_PARAM_FIELD_LENGTH, "block.%d.wr_bytes",
nblocks);
+ if (virTypedParamsAddLLong(&record->params,
+ &record->nparams,
+ maxparams,
+ field,
+ llvalue) < 0)
+ goto cleanup;
+
+ if (virJSONValueObjectGetNumberLong(stats, "wr_operations",
&llvalue) < 0)
+ goto cleanup;
+
+ snprintf(field, VIR_TYPED_PARAM_FIELD_LENGTH, "block.%d.wr_operations",
nblocks);
+ if (virTypedParamsAddLLong(&record->params,
+ &record->nparams,
+ maxparams,
+ field,
+ llvalue) < 0)
+ goto cleanup;
+
+ if (virJSONValueObjectGetNumberLong(stats, "wr_total_time_ns",
&llvalue) < 0)
+ goto cleanup;
+
+ snprintf(field, VIR_TYPED_PARAM_FIELD_LENGTH, "block.%d.wr_total_time",
nblocks);
+ if (virTypedParamsAddLLong(&record->params,
+ &record->nparams,
+ maxparams,
+ field,
+ llvalue) < 0)
+ goto cleanup;
+
+ if (virJSONValueObjectGetNumberLong(stats, "flush_operations",
&llvalue) < 0)
+ goto cleanup;
+
+ snprintf(field, VIR_TYPED_PARAM_FIELD_LENGTH,
"block.%d.flush_operations", nblocks);
+ if (virTypedParamsAddLLong(&record->params,
+ &record->nparams,
+ maxparams,
+ field,
+ llvalue) < 0)
+ goto cleanup;
+
+ if (virJSONValueObjectGetNumberLong(stats, "flush_total_time_ns",
&llvalue) < 0)
+ goto cleanup;
+
+ snprintf(field, VIR_TYPED_PARAM_FIELD_LENGTH,
"block.%d.flush_total_time", nblocks);
+ if (virTypedParamsAddLLong(&record->params,
+ &record->nparams,
+ maxparams,
+ field,
+ llvalue) < 0)
+ goto cleanup;
+
+ nblocks++;
+ }
+
+ ret = 0;
+
+ cleanup:
+ virJSONValueFree(cmd);
+ virJSONValueFree(reply);
+
+ return ret;
+}
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index d8c9308..a763c82 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -439,4 +439,9 @@ int qemuMonitorJSONGetGuestCPU(qemuMonitorPtr mon,
virCPUDataPtr *data);
int qemuMonitorJSONRTCResetReinjection(qemuMonitorPtr mon);
+
+int qemuMonitorJSONDomainGetStatsBlock(qemuMonitorPtr mon,
+ virDomainStatsRecordPtr record,
+ int *maxparams,
+ unsigned int flags);
#endif /* QEMU_MONITOR_JSON_H */
--
1.9.3