return head;
}
-static void bdrv_stats_iter(QObject *data, void *opaque)
-{
- QDict *qdict;
- Monitor *mon = opaque;
-
- qdict = qobject_to_qdict(data);
- monitor_printf(mon, "%s:", qdict_get_str(qdict, "device"));
-
- 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));
+/* Consider exposing this as a full fledged QMP command */
+static BlockStats *qmp_query_blockstat(const BlockDriverState *bs, Error **errp)
+{
+ BlockStats *s;
+
+ s = g_malloc0(sizeof(*s));
+
+ 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)
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);
##
{ '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:
#