diff options
author | Alberto Garcia <berto@igalia.com> | 2015-10-28 17:33:05 +0200 |
---|---|---|
committer | Kevin Wolf <kwolf@redhat.com> | 2015-11-12 16:22:45 +0100 |
commit | 979e9b03fc8c85d3b78a14410c64cbb16d348095 (patch) | |
tree | acadf4f7a6bf98a4ce5363ea40a5658542949640 /block | |
parent | 362e9299b34b3101aaa20f20363441c9f055fa5e (diff) |
block: Compute minimum, maximum and average I/O latencies
This patch keeps track of the minimum, maximum and average latencies
of I/O operations during a certain interval of time.
The values are exposed in the BlockDeviceTimedStats structure.
An option to define the intervals to collect these statistics will be
added in a separate patch.
Signed-off-by: Alberto Garcia <berto@igalia.com>
Message-id: c7382dc89622c64f918d09f32815827772628f8e.1446044837.git.berto@igalia.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Diffstat (limited to 'block')
-rw-r--r-- | block/accounting.c | 43 | ||||
-rw-r--r-- | block/block-backend.c | 1 | ||||
-rw-r--r-- | block/qapi.c | 28 |
3 files changed, 72 insertions, 0 deletions
diff --git a/block/accounting.c b/block/accounting.c index 923aeaf5be..61de8ce9bc 100644 --- a/block/accounting.c +++ b/block/accounting.c @@ -35,6 +35,39 @@ void block_acct_init(BlockAcctStats *stats, bool account_invalid, stats->account_failed = account_failed; } +void block_acct_cleanup(BlockAcctStats *stats) +{ + BlockAcctTimedStats *s, *next; + QSLIST_FOREACH_SAFE(s, &stats->intervals, entries, next) { + g_free(s); + } +} + +void block_acct_add_interval(BlockAcctStats *stats, unsigned interval_length) +{ + BlockAcctTimedStats *s; + unsigned i; + + s = g_new0(BlockAcctTimedStats, 1); + s->interval_length = interval_length; + QSLIST_INSERT_HEAD(&stats->intervals, s, entries); + + for (i = 0; i < BLOCK_MAX_IOTYPE; i++) { + timed_average_init(&s->latency[i], clock_type, + (uint64_t) interval_length * NANOSECONDS_PER_SECOND); + } +} + +BlockAcctTimedStats *block_acct_interval_next(BlockAcctStats *stats, + BlockAcctTimedStats *s) +{ + if (s == NULL) { + return QSLIST_FIRST(&stats->intervals); + } else { + return QSLIST_NEXT(s, entries); + } +} + void block_acct_start(BlockAcctStats *stats, BlockAcctCookie *cookie, int64_t bytes, enum BlockAcctType type) { @@ -47,6 +80,7 @@ void block_acct_start(BlockAcctStats *stats, BlockAcctCookie *cookie, void block_acct_done(BlockAcctStats *stats, BlockAcctCookie *cookie) { + BlockAcctTimedStats *s; int64_t time_ns = qemu_clock_get_ns(clock_type); int64_t latency_ns = time_ns - cookie->start_time_ns; @@ -56,6 +90,10 @@ void block_acct_done(BlockAcctStats *stats, BlockAcctCookie *cookie) stats->nr_ops[cookie->type]++; stats->total_time_ns[cookie->type] += latency_ns; stats->last_access_time_ns = time_ns; + + QSLIST_FOREACH(s, &stats->intervals, entries) { + timed_average_account(&s->latency[cookie->type], latency_ns); + } } void block_acct_failed(BlockAcctStats *stats, BlockAcctCookie *cookie) @@ -65,11 +103,16 @@ void block_acct_failed(BlockAcctStats *stats, BlockAcctCookie *cookie) stats->failed_ops[cookie->type]++; if (stats->account_failed) { + BlockAcctTimedStats *s; int64_t time_ns = qemu_clock_get_ns(clock_type); int64_t latency_ns = time_ns - cookie->start_time_ns; stats->total_time_ns[cookie->type] += latency_ns; stats->last_access_time_ns = time_ns; + + QSLIST_FOREACH(s, &stats->intervals, entries) { + timed_average_account(&s->latency[cookie->type], latency_ns); + } } } diff --git a/block/block-backend.c b/block/block-backend.c index 6f9309fef4..9889e813b6 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -176,6 +176,7 @@ static void blk_delete(BlockBackend *blk) } g_free(blk->name); drive_info_del(blk->legacy_dinfo); + block_acct_cleanup(&blk->stats); g_free(blk); } diff --git a/block/qapi.c b/block/qapi.c index 083469abcb..6169a22243 100644 --- a/block/qapi.c +++ b/block/qapi.c @@ -346,6 +346,7 @@ static BlockStats *bdrv_query_stats(const BlockDriverState *bs, s->stats = g_malloc0(sizeof(*s->stats)); if (bs->blk) { BlockAcctStats *stats = blk_get_stats(bs->blk); + BlockAcctTimedStats *ts = NULL; s->stats->rd_bytes = stats->nr_bytes[BLOCK_ACCT_READ]; s->stats->wr_bytes = stats->nr_bytes[BLOCK_ACCT_WRITE]; @@ -375,6 +376,33 @@ static BlockStats *bdrv_query_stats(const BlockDriverState *bs, s->stats->account_invalid = stats->account_invalid; s->stats->account_failed = stats->account_failed; + + while ((ts = block_acct_interval_next(stats, ts))) { + BlockDeviceTimedStatsList *timed_stats = + g_malloc0(sizeof(*timed_stats)); + BlockDeviceTimedStats *dev_stats = g_malloc0(sizeof(*dev_stats)); + timed_stats->next = s->stats->timed_stats; + timed_stats->value = dev_stats; + s->stats->timed_stats = timed_stats; + + TimedAverage *rd = &ts->latency[BLOCK_ACCT_READ]; + TimedAverage *wr = &ts->latency[BLOCK_ACCT_WRITE]; + TimedAverage *fl = &ts->latency[BLOCK_ACCT_FLUSH]; + + dev_stats->interval_length = ts->interval_length; + + dev_stats->min_rd_latency_ns = timed_average_min(rd); + dev_stats->max_rd_latency_ns = timed_average_max(rd); + dev_stats->avg_rd_latency_ns = timed_average_avg(rd); + + dev_stats->min_wr_latency_ns = timed_average_min(wr); + dev_stats->max_wr_latency_ns = timed_average_max(wr); + dev_stats->avg_wr_latency_ns = timed_average_avg(wr); + + 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); + } } s->stats->wr_highest_offset = bs->wr_highest_offset; |