block: Allow configuring whether to account failed and invalid ops
This patch adds two options, "stats-account-invalid" and "stats-account-failed", that can be used to decide whether invalid and failed I/O operations must be used when collecting statistics for latency and last access time. Signed-off-by: Alberto Garcia <berto@igalia.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Message-id: ebc7e5966511a342cad428a392c5f5ad56b15213.1446044837.git.berto@igalia.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
parent
7ee12dafe9
commit
362e9299b3
@ -28,6 +28,13 @@
|
|||||||
|
|
||||||
static QEMUClockType clock_type = QEMU_CLOCK_REALTIME;
|
static QEMUClockType clock_type = QEMU_CLOCK_REALTIME;
|
||||||
|
|
||||||
|
void block_acct_init(BlockAcctStats *stats, bool account_invalid,
|
||||||
|
bool account_failed)
|
||||||
|
{
|
||||||
|
stats->account_invalid = account_invalid;
|
||||||
|
stats->account_failed = account_failed;
|
||||||
|
}
|
||||||
|
|
||||||
void block_acct_start(BlockAcctStats *stats, BlockAcctCookie *cookie,
|
void block_acct_start(BlockAcctStats *stats, BlockAcctCookie *cookie,
|
||||||
int64_t bytes, enum BlockAcctType type)
|
int64_t bytes, enum BlockAcctType type)
|
||||||
{
|
{
|
||||||
@ -53,13 +60,17 @@ void block_acct_done(BlockAcctStats *stats, BlockAcctCookie *cookie)
|
|||||||
|
|
||||||
void block_acct_failed(BlockAcctStats *stats, BlockAcctCookie *cookie)
|
void block_acct_failed(BlockAcctStats *stats, BlockAcctCookie *cookie)
|
||||||
{
|
{
|
||||||
int64_t time_ns = qemu_clock_get_ns(clock_type);
|
|
||||||
|
|
||||||
assert(cookie->type < BLOCK_MAX_IOTYPE);
|
assert(cookie->type < BLOCK_MAX_IOTYPE);
|
||||||
|
|
||||||
stats->failed_ops[cookie->type]++;
|
stats->failed_ops[cookie->type]++;
|
||||||
stats->total_time_ns[cookie->type] += time_ns - cookie->start_time_ns;
|
|
||||||
stats->last_access_time_ns = time_ns;
|
if (stats->account_failed) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void block_acct_invalid(BlockAcctStats *stats, enum BlockAcctType type)
|
void block_acct_invalid(BlockAcctStats *stats, enum BlockAcctType type)
|
||||||
@ -72,7 +83,10 @@ void block_acct_invalid(BlockAcctStats *stats, enum BlockAcctType type)
|
|||||||
* therefore there's no actual I/O involved. */
|
* therefore there's no actual I/O involved. */
|
||||||
|
|
||||||
stats->invalid_ops[type]++;
|
stats->invalid_ops[type]++;
|
||||||
stats->last_access_time_ns = qemu_clock_get_ns(clock_type);
|
|
||||||
|
if (stats->account_invalid) {
|
||||||
|
stats->last_access_time_ns = qemu_clock_get_ns(clock_type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void block_acct_merge_done(BlockAcctStats *stats, enum BlockAcctType type,
|
void block_acct_merge_done(BlockAcctStats *stats, enum BlockAcctType type,
|
||||||
|
@ -372,6 +372,9 @@ static BlockStats *bdrv_query_stats(const BlockDriverState *bs,
|
|||||||
if (s->stats->has_idle_time_ns) {
|
if (s->stats->has_idle_time_ns) {
|
||||||
s->stats->idle_time_ns = block_acct_idle_time_ns(stats);
|
s->stats->idle_time_ns = block_acct_idle_time_ns(stats);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s->stats->account_invalid = stats->account_invalid;
|
||||||
|
s->stats->account_failed = stats->account_failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
s->stats->wr_highest_offset = bs->wr_highest_offset;
|
s->stats->wr_highest_offset = bs->wr_highest_offset;
|
||||||
|
16
blockdev.c
16
blockdev.c
@ -441,6 +441,7 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
|
|||||||
const char *buf;
|
const char *buf;
|
||||||
int bdrv_flags = 0;
|
int bdrv_flags = 0;
|
||||||
int on_read_error, on_write_error;
|
int on_read_error, on_write_error;
|
||||||
|
bool account_invalid, account_failed;
|
||||||
BlockBackend *blk;
|
BlockBackend *blk;
|
||||||
BlockDriverState *bs;
|
BlockDriverState *bs;
|
||||||
ThrottleConfig cfg;
|
ThrottleConfig cfg;
|
||||||
@ -477,6 +478,9 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
|
|||||||
/* extract parameters */
|
/* extract parameters */
|
||||||
snapshot = qemu_opt_get_bool(opts, "snapshot", 0);
|
snapshot = qemu_opt_get_bool(opts, "snapshot", 0);
|
||||||
|
|
||||||
|
account_invalid = qemu_opt_get_bool(opts, "stats-account-invalid", true);
|
||||||
|
account_failed = qemu_opt_get_bool(opts, "stats-account-failed", true);
|
||||||
|
|
||||||
extract_common_blockdev_options(opts, &bdrv_flags, &throttling_group, &cfg,
|
extract_common_blockdev_options(opts, &bdrv_flags, &throttling_group, &cfg,
|
||||||
&detect_zeroes, &error);
|
&detect_zeroes, &error);
|
||||||
if (error) {
|
if (error) {
|
||||||
@ -573,6 +577,8 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
|
|||||||
if (bdrv_key_required(bs)) {
|
if (bdrv_key_required(bs)) {
|
||||||
autostart = 0;
|
autostart = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
block_acct_init(blk_get_stats(blk), account_invalid, account_failed);
|
||||||
}
|
}
|
||||||
|
|
||||||
blk_set_on_error(blk, on_read_error, on_write_error);
|
blk_set_on_error(blk, on_read_error, on_write_error);
|
||||||
@ -3900,6 +3906,16 @@ QemuOptsList qemu_common_drive_opts = {
|
|||||||
.name = "detect-zeroes",
|
.name = "detect-zeroes",
|
||||||
.type = QEMU_OPT_STRING,
|
.type = QEMU_OPT_STRING,
|
||||||
.help = "try to optimize zero writes (off, on, unmap)",
|
.help = "try to optimize zero writes (off, on, unmap)",
|
||||||
|
},{
|
||||||
|
.name = "stats-account-invalid",
|
||||||
|
.type = QEMU_OPT_BOOL,
|
||||||
|
.help = "whether to account for invalid I/O operations "
|
||||||
|
"in the statistics",
|
||||||
|
},{
|
||||||
|
.name = "stats-account-failed",
|
||||||
|
.type = QEMU_OPT_BOOL,
|
||||||
|
.help = "whether to account for failed I/O operations "
|
||||||
|
"in the statistics",
|
||||||
},
|
},
|
||||||
{ /* end of list */ }
|
{ /* end of list */ }
|
||||||
},
|
},
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#define BLOCK_ACCOUNTING_H
|
#define BLOCK_ACCOUNTING_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include "qemu/typedefs.h"
|
#include "qemu/typedefs.h"
|
||||||
|
|
||||||
@ -43,6 +44,8 @@ typedef struct BlockAcctStats {
|
|||||||
uint64_t total_time_ns[BLOCK_MAX_IOTYPE];
|
uint64_t total_time_ns[BLOCK_MAX_IOTYPE];
|
||||||
uint64_t merged[BLOCK_MAX_IOTYPE];
|
uint64_t merged[BLOCK_MAX_IOTYPE];
|
||||||
int64_t last_access_time_ns;
|
int64_t last_access_time_ns;
|
||||||
|
bool account_invalid;
|
||||||
|
bool account_failed;
|
||||||
} BlockAcctStats;
|
} BlockAcctStats;
|
||||||
|
|
||||||
typedef struct BlockAcctCookie {
|
typedef struct BlockAcctCookie {
|
||||||
@ -51,6 +54,8 @@ typedef struct BlockAcctCookie {
|
|||||||
enum BlockAcctType type;
|
enum BlockAcctType type;
|
||||||
} BlockAcctCookie;
|
} BlockAcctCookie;
|
||||||
|
|
||||||
|
void block_acct_init(BlockAcctStats *stats, bool account_invalid,
|
||||||
|
bool account_failed);
|
||||||
void block_acct_start(BlockAcctStats *stats, BlockAcctCookie *cookie,
|
void block_acct_start(BlockAcctStats *stats, BlockAcctCookie *cookie,
|
||||||
int64_t bytes, enum BlockAcctType type);
|
int64_t bytes, enum BlockAcctType type);
|
||||||
void block_acct_done(BlockAcctStats *stats, BlockAcctCookie *cookie);
|
void block_acct_done(BlockAcctStats *stats, BlockAcctCookie *cookie);
|
||||||
|
@ -470,6 +470,12 @@
|
|||||||
# @invalid_flush_operations: The number of invalid flush operations
|
# @invalid_flush_operations: The number of invalid flush operations
|
||||||
# performed by the device (Since 2.5)
|
# performed by the device (Since 2.5)
|
||||||
#
|
#
|
||||||
|
# @account_invalid: Whether invalid operations are included in the
|
||||||
|
# last access statistics (Since 2.5)
|
||||||
|
#
|
||||||
|
# @account_failed: Whether failed operations are included in the
|
||||||
|
# latency and last access statistics (Since 2.5)
|
||||||
|
#
|
||||||
# Since: 0.14.0
|
# Since: 0.14.0
|
||||||
##
|
##
|
||||||
{ 'struct': 'BlockDeviceStats',
|
{ 'struct': 'BlockDeviceStats',
|
||||||
@ -480,7 +486,8 @@
|
|||||||
'rd_merged': 'int', 'wr_merged': 'int', '*idle_time_ns': 'int',
|
'rd_merged': 'int', 'wr_merged': 'int', '*idle_time_ns': 'int',
|
||||||
'failed_rd_operations': 'int', 'failed_wr_operations': 'int',
|
'failed_rd_operations': 'int', 'failed_wr_operations': 'int',
|
||||||
'failed_flush_operations': 'int', 'invalid_rd_operations': 'int',
|
'failed_flush_operations': 'int', 'invalid_rd_operations': 'int',
|
||||||
'invalid_wr_operations': 'int', 'invalid_flush_operations': 'int' } }
|
'invalid_wr_operations': 'int', 'invalid_flush_operations': 'int',
|
||||||
|
'account_invalid': 'bool', 'account_failed': 'bool' } }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @BlockStats:
|
# @BlockStats:
|
||||||
@ -1461,6 +1468,12 @@
|
|||||||
# (default: enospc)
|
# (default: enospc)
|
||||||
# @read-only: #optional whether the block device should be read-only
|
# @read-only: #optional whether the block device should be read-only
|
||||||
# (default: false)
|
# (default: false)
|
||||||
|
# @stats-account-invalid: #optional whether to include invalid
|
||||||
|
# operations when computing last access statistics
|
||||||
|
# (default: true) (Since 2.5)
|
||||||
|
# @stats-account-failed: #optional whether to include failed
|
||||||
|
# operations when computing latency and last
|
||||||
|
# access statistics (default: true) (Since 2.5)
|
||||||
# @detect-zeroes: #optional detect and optimize zero writes (Since 2.1)
|
# @detect-zeroes: #optional detect and optimize zero writes (Since 2.1)
|
||||||
# (default: off)
|
# (default: off)
|
||||||
#
|
#
|
||||||
@ -1476,6 +1489,8 @@
|
|||||||
'*rerror': 'BlockdevOnError',
|
'*rerror': 'BlockdevOnError',
|
||||||
'*werror': 'BlockdevOnError',
|
'*werror': 'BlockdevOnError',
|
||||||
'*read-only': 'bool',
|
'*read-only': 'bool',
|
||||||
|
'*stats-account-invalid': 'bool',
|
||||||
|
'*stats-account-failed': 'bool',
|
||||||
'*detect-zeroes': 'BlockdevDetectZeroesOptions' } }
|
'*detect-zeroes': 'BlockdevDetectZeroesOptions' } }
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -2599,6 +2599,11 @@ Each json-object contain the following:
|
|||||||
(json-int)
|
(json-int)
|
||||||
- "invalid_flush_operations": number of invalid flush operations
|
- "invalid_flush_operations": number of invalid flush operations
|
||||||
(json-int)
|
(json-int)
|
||||||
|
- "account_invalid": whether invalid operations are included in
|
||||||
|
the last access statistics (json-bool)
|
||||||
|
- "account_failed": whether failed operations are included in the
|
||||||
|
latency and last access statistics
|
||||||
|
(json-bool)
|
||||||
- "parent": Contains recursively the statistics of the underlying
|
- "parent": Contains recursively the statistics of the underlying
|
||||||
protocol (e.g. the host file for a qcow2 image). If there is
|
protocol (e.g. the host file for a qcow2 image). If there is
|
||||||
no underlying protocol, this field is omitted
|
no underlying protocol, this field is omitted
|
||||||
@ -2624,7 +2629,9 @@ Example:
|
|||||||
"flush_operations":61,
|
"flush_operations":61,
|
||||||
"rd_merged":0,
|
"rd_merged":0,
|
||||||
"wr_merged":0,
|
"wr_merged":0,
|
||||||
"idle_time_ns":2953431879
|
"idle_time_ns":2953431879,
|
||||||
|
"account_invalid":true,
|
||||||
|
"account_failed":false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"stats":{
|
"stats":{
|
||||||
@ -2639,7 +2646,9 @@ Example:
|
|||||||
"flush_total_times_ns":49653,
|
"flush_total_times_ns":49653,
|
||||||
"rd_merged":0,
|
"rd_merged":0,
|
||||||
"wr_merged":0,
|
"wr_merged":0,
|
||||||
"idle_time_ns":2953431879
|
"idle_time_ns":2953431879,
|
||||||
|
"account_invalid":true,
|
||||||
|
"account_failed":false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -2655,7 +2664,9 @@ Example:
|
|||||||
"rd_total_times_ns":0
|
"rd_total_times_ns":0
|
||||||
"flush_total_times_ns":0,
|
"flush_total_times_ns":0,
|
||||||
"rd_merged":0,
|
"rd_merged":0,
|
||||||
"wr_merged":0
|
"wr_merged":0,
|
||||||
|
"account_invalid":false,
|
||||||
|
"account_failed":false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -2671,7 +2682,9 @@ Example:
|
|||||||
"rd_total_times_ns":0
|
"rd_total_times_ns":0
|
||||||
"flush_total_times_ns":0,
|
"flush_total_times_ns":0,
|
||||||
"rd_merged":0,
|
"rd_merged":0,
|
||||||
"wr_merged":0
|
"wr_merged":0,
|
||||||
|
"account_invalid":false,
|
||||||
|
"account_failed":false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -2687,7 +2700,9 @@ Example:
|
|||||||
"rd_total_times_ns":0
|
"rd_total_times_ns":0
|
||||||
"flush_total_times_ns":0,
|
"flush_total_times_ns":0,
|
||||||
"rd_merged":0,
|
"rd_merged":0,
|
||||||
"wr_merged":0
|
"wr_merged":0,
|
||||||
|
"account_invalid":false,
|
||||||
|
"account_failed":false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
Loading…
Reference in New Issue
Block a user