From f11f57e405a99732ed0f3294904c2dd258d77629 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Thu, 22 Sep 2011 15:56:36 -0300 Subject: [PATCH] qapi: Convert query-blockstats Signed-off-by: Anthony Liguori Signed-off-by: Luiz Capitulino --- block.c | 105 +++++++++++++++-------------------------------- hmp.c | 34 +++++++++++++++ hmp.h | 1 + monitor.c | 11 +---- qapi-schema.json | 67 ++++++++++++++++++++++++++++++ qmp-commands.hx | 6 +++ 6 files changed, 143 insertions(+), 81 deletions(-) diff --git a/block.c b/block.c index e648513fdd..551aa80af9 100644 --- a/block.c +++ b/block.c @@ -1874,93 +1874,56 @@ BlockInfoList *qmp_query_block(Error **errp) return head; } -static void bdrv_stats_iter(QObject *data, void *opaque) +/* Consider exposing this as a full fledged QMP command */ +static BlockStats *qmp_query_blockstat(const BlockDriverState *bs, Error **errp) { - QDict *qdict; - Monitor *mon = opaque; + BlockStats *s; - qdict = qobject_to_qdict(data); - monitor_printf(mon, "%s:", qdict_get_str(qdict, "device")); + s = g_malloc0(sizeof(*s)); - qdict = qobject_to_qdict(qdict_get(qdict, "stats")); - monitor_printf(mon, " rd_bytes=%" PRId64 - " wr_bytes=%" PRId64 - " rd_operations=%" PRId64 - " wr_operations=%" PRId64 - " flush_operations=%" PRId64 - " wr_total_time_ns=%" PRId64 - " rd_total_time_ns=%" PRId64 - " flush_total_time_ns=%" PRId64 - "\n", - qdict_get_int(qdict, "rd_bytes"), - qdict_get_int(qdict, "wr_bytes"), - qdict_get_int(qdict, "rd_operations"), - qdict_get_int(qdict, "wr_operations"), - qdict_get_int(qdict, "flush_operations"), - qdict_get_int(qdict, "wr_total_time_ns"), - qdict_get_int(qdict, "rd_total_time_ns"), - qdict_get_int(qdict, "flush_total_time_ns")); -} - -void bdrv_stats_print(Monitor *mon, const QObject *data) -{ - qlist_iter(qobject_to_qlist(data), bdrv_stats_iter, mon); -} - -static QObject* bdrv_info_stats_bs(BlockDriverState *bs) -{ - QObject *res; - QDict *dict; - - res = qobject_from_jsonf("{ 'stats': {" - "'rd_bytes': %" PRId64 "," - "'wr_bytes': %" PRId64 "," - "'rd_operations': %" PRId64 "," - "'wr_operations': %" PRId64 "," - "'wr_highest_offset': %" PRId64 "," - "'flush_operations': %" PRId64 "," - "'wr_total_time_ns': %" PRId64 "," - "'rd_total_time_ns': %" PRId64 "," - "'flush_total_time_ns': %" PRId64 - "} }", - bs->nr_bytes[BDRV_ACCT_READ], - bs->nr_bytes[BDRV_ACCT_WRITE], - bs->nr_ops[BDRV_ACCT_READ], - bs->nr_ops[BDRV_ACCT_WRITE], - bs->wr_highest_sector * - (uint64_t)BDRV_SECTOR_SIZE, - bs->nr_ops[BDRV_ACCT_FLUSH], - bs->total_time_ns[BDRV_ACCT_WRITE], - bs->total_time_ns[BDRV_ACCT_READ], - bs->total_time_ns[BDRV_ACCT_FLUSH]); - dict = qobject_to_qdict(res); - - if (*bs->device_name) { - qdict_put(dict, "device", qstring_from_str(bs->device_name)); + if (bs->device_name[0]) { + s->has_device = true; + s->device = g_strdup(bs->device_name); } + s->stats = g_malloc0(sizeof(*s->stats)); + s->stats->rd_bytes = bs->nr_bytes[BDRV_ACCT_READ]; + s->stats->wr_bytes = bs->nr_bytes[BDRV_ACCT_WRITE]; + s->stats->rd_operations = bs->nr_ops[BDRV_ACCT_READ]; + s->stats->wr_operations = bs->nr_ops[BDRV_ACCT_WRITE]; + s->stats->wr_highest_offset = bs->wr_highest_sector * BDRV_SECTOR_SIZE; + s->stats->flush_operations = bs->nr_ops[BDRV_ACCT_FLUSH]; + s->stats->wr_total_time_ns = bs->total_time_ns[BDRV_ACCT_WRITE]; + s->stats->rd_total_time_ns = bs->total_time_ns[BDRV_ACCT_READ]; + s->stats->flush_total_time_ns = bs->total_time_ns[BDRV_ACCT_FLUSH]; + if (bs->file) { - QObject *parent = bdrv_info_stats_bs(bs->file); - qdict_put_obj(dict, "parent", parent); + s->has_parent = true; + s->parent = qmp_query_blockstat(bs->file, NULL); } - return res; + return s; } -void bdrv_info_stats(Monitor *mon, QObject **ret_data) +BlockStatsList *qmp_query_blockstats(Error **errp) { - QObject *obj; - QList *devices; + BlockStatsList *head = NULL, *cur_item = NULL; BlockDriverState *bs; - devices = qlist_new(); - QTAILQ_FOREACH(bs, &bdrv_states, list) { - obj = bdrv_info_stats_bs(bs); - qlist_append_obj(devices, obj); + BlockStatsList *info = g_malloc0(sizeof(*info)); + info->value = qmp_query_blockstat(bs, NULL); + + /* XXX: waiting for the qapi to support GSList */ + if (!cur_item) { + head = cur_item = info; + } else { + cur_item->next = info; + cur_item = info; + } } - *ret_data = QOBJECT(devices); + return head; } const char *bdrv_get_encrypted_filename(BlockDriverState *bs) diff --git a/hmp.c b/hmp.c index 5912250d04..eab2ddfce9 100644 --- a/hmp.c +++ b/hmp.c @@ -226,6 +226,40 @@ void hmp_info_block(Monitor *mon) qapi_free_BlockInfoList(block_list); } +void hmp_info_blockstats(Monitor *mon) +{ + BlockStatsList *stats_list, *stats; + + stats_list = qmp_query_blockstats(NULL); + + for (stats = stats_list; stats; stats = stats->next) { + if (!stats->value->has_device) { + continue; + } + + monitor_printf(mon, "%s:", stats->value->device); + monitor_printf(mon, " rd_bytes=%" PRId64 + " wr_bytes=%" PRId64 + " rd_operations=%" PRId64 + " wr_operations=%" PRId64 + " flush_operations=%" PRId64 + " wr_total_time_ns=%" PRId64 + " rd_total_time_ns=%" PRId64 + " flush_total_time_ns=%" PRId64 + "\n", + stats->value->stats->rd_bytes, + stats->value->stats->wr_bytes, + stats->value->stats->rd_operations, + stats->value->stats->wr_operations, + stats->value->stats->flush_operations, + stats->value->stats->wr_total_time_ns, + stats->value->stats->rd_total_time_ns, + stats->value->stats->flush_total_time_ns); + } + + qapi_free_BlockStatsList(stats_list); +} + void hmp_quit(Monitor *mon, const QDict *qdict) { monitor_suspend(mon); diff --git a/hmp.h b/hmp.h index f5ec417156..f8c50d438b 100644 --- a/hmp.h +++ b/hmp.h @@ -27,6 +27,7 @@ void hmp_info_mice(Monitor *mon); void hmp_info_migrate(Monitor *mon); void hmp_info_cpus(Monitor *mon); void hmp_info_block(Monitor *mon); +void hmp_info_blockstats(Monitor *mon); void hmp_quit(Monitor *mon, const QDict *qdict); void hmp_stop(Monitor *mon, const QDict *qdict); void hmp_system_reset(Monitor *mon, const QDict *qdict); diff --git a/monitor.c b/monitor.c index 3e76f4c0b7..70e54602a9 100644 --- a/monitor.c +++ b/monitor.c @@ -2681,8 +2681,7 @@ static const mon_cmd_t info_cmds[] = { .args_type = "", .params = "", .help = "show block device statistics", - .user_print = bdrv_stats_print, - .mhandler.info_new = bdrv_info_stats, + .mhandler.info = hmp_info_blockstats, }, { .name = "registers", @@ -2959,14 +2958,6 @@ static const mon_cmd_t qmp_cmds[] = { }; static const mon_cmd_t qmp_query_cmds[] = { - { - .name = "blockstats", - .args_type = "", - .params = "", - .help = "show block device statistics", - .user_print = bdrv_stats_print, - .mhandler.info_new = bdrv_info_stats, - }, { .name = "pci", .args_type = "", diff --git a/qapi-schema.json b/qapi-schema.json index 5e3570e53d..45494d8af8 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -436,6 +436,73 @@ ## { 'command': 'query-block', 'returns': ['BlockInfo'] } +## +# @BlockDeviceStats: +# +# Statistics of a virtual block device or a block backing device. +# +# @rd_bytes: The number of bytes read by the device. +# +# @wr_bytes: The number of bytes written by the device. +# +# @rd_operations: The number of read operations performed by the device. +# +# @wr_operations: The number of write operations performed by the device. +# +# @flush_operations: The number of cache flush operations performed by the +# device (since 0.15.0) +# +# @flush_total_time_ns: Total time spend on cache flushes in nano-seconds +# (since 0.15.0). +# +# @wr_total_time_ns: Total time spend on writes in nano-seconds (since 0.15.0). +# +# @rd_total_time_ns: Total_time_spend on reads in nano-seconds (since 0.15.0). +# +# @wr_highest_offset: The offset after the greatest byte written to the +# device. The intended use of this information is for +# growable sparse files (like qcow2) that are used on top +# of a physical device. +# +# Since: 0.14.0 +## +{ 'type': 'BlockDeviceStats', + 'data': {'rd_bytes': 'int', 'wr_bytes': 'int', 'rd_operations': 'int', + 'wr_operations': 'int', 'flush_operations': 'int', + 'flush_total_time_ns': 'int', 'wr_total_time_ns': 'int', + 'rd_total_time_ns': 'int', 'wr_highest_offset': 'int' } } + +## +# @BlockStats: +# +# Statistics of a virtual block device or a block backing device. +# +# @device: #optional If the stats are for a virtual block device, the name +# corresponding to the virtual block device. +# +# @stats: A @BlockDeviceStats for the device. +# +# @parent: #optional This may point to the backing block device if this is a +# a virtual block device. If it's a backing block, this will point +# to the backing file is one is present. +# +# Since: 0.14.0 +## +{ 'type': 'BlockStats', + 'data': {'*device': 'str', 'stats': 'BlockDeviceStats', + '*parent': 'BlockStats'} } + +## +# @query-blockstats: +# +# Query the @BlockStats for all virtual block devices. +# +# Returns: A list of @BlockStats for each virtual block devices. +# +# Since: 0.14.0 +## +{ 'command': 'query-blockstats', 'returns': ['BlockStats'] } + ## # @quit: # diff --git a/qmp-commands.hx b/qmp-commands.hx index 0cf0be7e0d..a250a7ada7 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -1311,6 +1311,12 @@ Example: EQMP + { + .name = "query-blockstats", + .args_type = "", + .mhandler.cmd_new = qmp_marshal_input_query_blockstats, + }, + SQMP query-cpus ----------