diff --git a/block/accounting.c b/block/accounting.c index 6f4c0f12eb6ff46d3427fa58015509313c900745..d427fa8fb83ffca1f0fd42cfd34a11dd8280b39c 100644 --- a/block/accounting.c +++ b/block/accounting.c @@ -40,12 +40,15 @@ void block_acct_start(BlockAcctStats *stats, BlockAcctCookie *cookie, void block_acct_done(BlockAcctStats *stats, BlockAcctCookie *cookie) { + int64_t time_ns = qemu_clock_get_ns(clock_type); + int64_t latency_ns = time_ns - cookie->start_time_ns; + assert(cookie->type < BLOCK_MAX_IOTYPE); stats->nr_bytes[cookie->type] += cookie->bytes; stats->nr_ops[cookie->type]++; - stats->total_time_ns[cookie->type] += - qemu_clock_get_ns(clock_type) - cookie->start_time_ns; + stats->total_time_ns[cookie->type] += latency_ns; + stats->last_access_time_ns = time_ns; } @@ -55,3 +58,8 @@ void block_acct_merge_done(BlockAcctStats *stats, enum BlockAcctType type, assert(type < BLOCK_MAX_IOTYPE); stats->merged[type] += num_requests; } + +int64_t block_acct_idle_time_ns(BlockAcctStats *stats) +{ + return qemu_clock_get_ns(clock_type) - stats->last_access_time_ns; +} diff --git a/block/qapi.c b/block/qapi.c index 89d42741773de4c1099dcbfad3445ef42422e7f0..97996567614458cbbf1f444e90e99386a6b11e28 100644 --- a/block/qapi.c +++ b/block/qapi.c @@ -357,6 +357,11 @@ static BlockStats *bdrv_query_stats(const BlockDriverState *bs, s->stats->wr_total_time_ns = stats->total_time_ns[BLOCK_ACCT_WRITE]; s->stats->rd_total_time_ns = stats->total_time_ns[BLOCK_ACCT_READ]; s->stats->flush_total_time_ns = stats->total_time_ns[BLOCK_ACCT_FLUSH]; + + s->stats->has_idle_time_ns = stats->last_access_time_ns > 0; + if (s->stats->has_idle_time_ns) { + s->stats->idle_time_ns = block_acct_idle_time_ns(stats); + } } s->stats->wr_highest_offset = bs->wr_highest_offset; diff --git a/hmp.c b/hmp.c index d3812831ced63402db06822d0ed2f8af3287a6c6..21406059c761d14b3aef4203e534013df9f907b3 100644 --- a/hmp.c +++ b/hmp.c @@ -522,6 +522,7 @@ void hmp_info_blockstats(Monitor *mon, const QDict *qdict) " flush_total_time_ns=%" PRId64 " rd_merged=%" PRId64 " wr_merged=%" PRId64 + " idle_time_ns=%" PRId64 "\n", stats->value->stats->rd_bytes, stats->value->stats->wr_bytes, @@ -532,7 +533,8 @@ void hmp_info_blockstats(Monitor *mon, const QDict *qdict) stats->value->stats->rd_total_time_ns, stats->value->stats->flush_total_time_ns, stats->value->stats->rd_merged, - stats->value->stats->wr_merged); + stats->value->stats->wr_merged, + stats->value->stats->idle_time_ns); } qapi_free_BlockStatsList(stats_list); diff --git a/include/block/accounting.h b/include/block/accounting.h index 66637cdfedda5baa392a5fd07aca5a2dc20d768c..4b2b999bd0bdd65a02be5a2760194be30e4889f7 100644 --- a/include/block/accounting.h +++ b/include/block/accounting.h @@ -40,6 +40,7 @@ typedef struct BlockAcctStats { uint64_t nr_ops[BLOCK_MAX_IOTYPE]; uint64_t total_time_ns[BLOCK_MAX_IOTYPE]; uint64_t merged[BLOCK_MAX_IOTYPE]; + int64_t last_access_time_ns; } BlockAcctStats; typedef struct BlockAcctCookie { @@ -53,5 +54,6 @@ void block_acct_start(BlockAcctStats *stats, BlockAcctCookie *cookie, void block_acct_done(BlockAcctStats *stats, BlockAcctCookie *cookie); void block_acct_merge_done(BlockAcctStats *stats, enum BlockAcctType type, int num_requests); +int64_t block_acct_idle_time_ns(BlockAcctStats *stats); #endif diff --git a/qapi/block-core.json b/qapi/block-core.json index 470e86c6df51bdceae107fcca6892f765e006b59..597281821b8f620c02b5f08f66eb07377a5740ae 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -448,6 +448,10 @@ # @wr_merged: Number of write requests that have been merged into another # request (Since 2.3). # +# @idle_time_ns: #optional Time since the last I/O operation, in +# nanoseconds. If the field is absent it means that +# there haven't been any operations yet (Since 2.5). +# # Since: 0.14.0 ## { 'struct': 'BlockDeviceStats', @@ -455,7 +459,7 @@ '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', - 'rd_merged': 'int', 'wr_merged': 'int' } } + 'rd_merged': 'int', 'wr_merged': 'int', '*idle_time_ns': 'int' } } ## # @BlockStats: diff --git a/qmp-commands.hx b/qmp-commands.hx index ede18bf701c5f6b909a03277b657036a731a8950..5c4c16fe9b9d7d4410755437d75042d62fcec2b5 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -2583,6 +2583,10 @@ Each json-object contain the following: another request (json-int) - "wr_merged": number of write requests that have been merged into another request (json-int) + - "idle_time_ns": time since the last I/O operation, in + nanoseconds. If the field is absent it means + that there haven't been any operations yet + (json-int, optional) - "parent": Contains recursively the statistics of the underlying protocol (e.g. the host file for a qcow2 image). If there is no underlying protocol, this field is omitted @@ -2607,7 +2611,8 @@ Example: "flush_total_times_ns":49653 "flush_operations":61, "rd_merged":0, - "wr_merged":0 + "wr_merged":0, + "idle_time_ns":2953431879 } }, "stats":{ @@ -2621,7 +2626,8 @@ Example: "rd_total_times_ns":3465673657 "flush_total_times_ns":49653, "rd_merged":0, - "wr_merged":0 + "wr_merged":0, + "idle_time_ns":2953431879 } }, {