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@xxxxxxxxxxxxxx> --- 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list