From: Alberto Garcia <be...@igalia.com> This patch adds two new fields to BlockDeviceTimedStats that track the average number of pending read and write requests for a block device.
The values are calculated for the period of time defined for that interval. Signed-off-by: Alberto Garcia <be...@igalia.com> Message-id: fd31fef53e2714f2f30d59ed58ca2f67ec9ab926.1446044837.git.be...@igalia.com Signed-off-by: Stefan Hajnoczi <stefa...@redhat.com> --- block/accounting.c | 12 ++++++++++++ block/qapi.c | 5 +++++ include/block/accounting.h | 2 ++ include/qemu/timed-average.h | 1 + qapi/block-core.json | 9 ++++++++- qmp-commands.hx | 6 ++++++ util/timed-average.c | 31 ++++++++++++++++++++++++++----- 7 files changed, 60 insertions(+), 6 deletions(-) diff --git a/block/accounting.c b/block/accounting.c index 61de8ce..a941931 100644 --- a/block/accounting.c +++ b/block/accounting.c @@ -143,3 +143,15 @@ int64_t block_acct_idle_time_ns(BlockAcctStats *stats) { return qemu_clock_get_ns(clock_type) - stats->last_access_time_ns; } + +double block_acct_queue_depth(BlockAcctTimedStats *stats, + enum BlockAcctType type) +{ + uint64_t sum, elapsed; + + assert(type < BLOCK_MAX_IOTYPE); + + sum = timed_average_sum(&stats->latency[type], &elapsed); + + return (double) sum / elapsed; +} diff --git a/block/qapi.c b/block/qapi.c index 4baf6e1..99d5303 100644 --- a/block/qapi.c +++ b/block/qapi.c @@ -402,6 +402,11 @@ static BlockStats *bdrv_query_stats(const BlockDriverState *bs, dev_stats->min_flush_latency_ns = timed_average_min(fl); dev_stats->max_flush_latency_ns = timed_average_max(fl); dev_stats->avg_flush_latency_ns = timed_average_avg(fl); + + dev_stats->avg_rd_queue_depth = + block_acct_queue_depth(ts, BLOCK_ACCT_READ); + dev_stats->avg_wr_queue_depth = + block_acct_queue_depth(ts, BLOCK_ACCT_WRITE); } } diff --git a/include/block/accounting.h b/include/block/accounting.h index 1dd582a..482926b 100644 --- a/include/block/accounting.h +++ b/include/block/accounting.h @@ -78,5 +78,7 @@ void block_acct_invalid(BlockAcctStats *stats, enum BlockAcctType type); void block_acct_merge_done(BlockAcctStats *stats, enum BlockAcctType type, int num_requests); int64_t block_acct_idle_time_ns(BlockAcctStats *stats); +double block_acct_queue_depth(BlockAcctTimedStats *stats, + enum BlockAcctType type); #endif diff --git a/include/qemu/timed-average.h b/include/qemu/timed-average.h index f1cdddc..364bf88 100644 --- a/include/qemu/timed-average.h +++ b/include/qemu/timed-average.h @@ -59,5 +59,6 @@ void timed_average_account(TimedAverage *ta, uint64_t value); uint64_t timed_average_min(TimedAverage *ta); uint64_t timed_average_avg(TimedAverage *ta); uint64_t timed_average_max(TimedAverage *ta); +uint64_t timed_average_sum(TimedAverage *ta, uint64_t *elapsed); #endif diff --git a/qapi/block-core.json b/qapi/block-core.json index e2cfac6..0742794 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -450,6 +450,12 @@ # @avg_flush_latency_ns: Average latency of flush operations in the # defined interval, in nanoseconds. # +# @avg_rd_queue_depth: Average number of pending read operations +# in the defined interval. +# +# @avg_wr_queue_depth: Average number of pending write operations +# in the defined interval. +# # Since: 2.5 ## @@ -458,7 +464,8 @@ 'max_rd_latency_ns': 'int', 'avg_rd_latency_ns': 'int', 'min_wr_latency_ns': 'int', 'max_wr_latency_ns': 'int', 'avg_wr_latency_ns': 'int', 'min_flush_latency_ns': 'int', - 'max_flush_latency_ns': 'int', 'avg_flush_latency_ns': 'int' } } + 'max_flush_latency_ns': 'int', 'avg_flush_latency_ns': 'int', + 'avg_rd_queue_depth': 'number', 'avg_wr_queue_depth': 'number' } } ## # @BlockDeviceStats: diff --git a/qmp-commands.hx b/qmp-commands.hx index e9b3a76..185148c 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -2578,6 +2578,12 @@ Each json-object contain the following: - "avg_flush_latency_ns": average latency of flush operations in the defined interval, in nanoseconds (json-int) + - "avg_rd_queue_depth": average number of pending read + operations in the defined interval + (json-number) + - "avg_wr_queue_depth": average number of pending write + operations in the defined interval + (json-number). - "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 diff --git a/util/timed-average.c b/util/timed-average.c index 98a1170..a2dfb48 100644 --- a/util/timed-average.c +++ b/util/timed-average.c @@ -120,8 +120,10 @@ void timed_average_init(TimedAverage *ta, QEMUClockType clock_type, * expiration time if that's the case. * * @ta: the TimedAverage structure + * @elapsed: if non-NULL, the elapsed time (in ns) within the current + * window will be stored here */ -static void check_expirations(TimedAverage *ta) +static void check_expirations(TimedAverage *ta, uint64_t *elapsed) { int64_t now = qemu_clock_get_ns(ta->clock_type); int i; @@ -143,6 +145,12 @@ static void check_expirations(TimedAverage *ta) } else { ta->current = 1; } + + /* Calculate the elapsed time within the current window */ + if (elapsed) { + int64_t remaining = ta->windows[ta->current].expiration - now; + *elapsed = ta->period - remaining; + } } /* Account a value @@ -153,7 +161,7 @@ static void check_expirations(TimedAverage *ta) void timed_average_account(TimedAverage *ta, uint64_t value) { int i; - check_expirations(ta); + check_expirations(ta, NULL); /* Do the accounting in both windows at the same time */ for (i = 0; i < 2; i++) { @@ -180,7 +188,7 @@ void timed_average_account(TimedAverage *ta, uint64_t value) uint64_t timed_average_min(TimedAverage *ta) { TimedAverageWindow *w; - check_expirations(ta); + check_expirations(ta, NULL); w = current_window(ta); return w->min < UINT64_MAX ? w->min : 0; } @@ -193,7 +201,7 @@ uint64_t timed_average_min(TimedAverage *ta) uint64_t timed_average_avg(TimedAverage *ta) { TimedAverageWindow *w; - check_expirations(ta); + check_expirations(ta, NULL); w = current_window(ta); return w->count > 0 ? w->sum / w->count : 0; } @@ -205,6 +213,19 @@ uint64_t timed_average_avg(TimedAverage *ta) */ uint64_t timed_average_max(TimedAverage *ta) { - check_expirations(ta); + check_expirations(ta, NULL); return current_window(ta)->max; } + +/* Get the sum of all accounted values + * @ta: the TimedAverage structure + * @elapsed: if non-NULL, the elapsed time (in ns) will be stored here + * @ret: the sum of all accounted values + */ +uint64_t timed_average_sum(TimedAverage *ta, uint64_t *elapsed) +{ + TimedAverageWindow *w; + check_expirations(ta, elapsed); + w = current_window(ta); + return w->sum; +} -- 2.5.0