Skip to content

Commit

Permalink
block/null: Latency simulation by adding new option "latency-ns"
Browse files Browse the repository at this point in the history
Aio context switch should just work because the requests will be
drained, so the scheduled timer(s) on the old context will be freed.

Signed-off-by: Fam Zheng <famz@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Message-id: 1427852740-24315-2-git-send-email-famz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
  • Loading branch information
Fam Zheng authored and kevmw committed Apr 28, 2015
1 parent 9eddd6a commit e5e51dd
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 7 deletions.
58 changes: 52 additions & 6 deletions block/null.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@

#include "block/block_int.h"

#define NULL_OPT_LATENCY "latency-ns"

typedef struct {
int64_t length;
int64_t latency_ns;
} BDRVNullState;

static QemuOptsList runtime_opts = {
Expand All @@ -30,6 +33,12 @@ static QemuOptsList runtime_opts = {
.type = QEMU_OPT_SIZE,
.help = "size of the null block",
},
{
.name = NULL_OPT_LATENCY,
.type = QEMU_OPT_NUMBER,
.help = "nanoseconds (approximated) to wait "
"before completing request",
},
{ /* end of list */ }
},
};
Expand All @@ -39,13 +48,20 @@ static int null_file_open(BlockDriverState *bs, QDict *options, int flags,
{
QemuOpts *opts;
BDRVNullState *s = bs->opaque;
int ret = 0;

opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
qemu_opts_absorb_qdict(opts, options, &error_abort);
s->length =
qemu_opt_get_size(opts, BLOCK_OPT_SIZE, 1 << 30);
s->latency_ns =
qemu_opt_get_number(opts, NULL_OPT_LATENCY, 0);
if (s->latency_ns < 0) {
error_setg(errp, "latency-ns is invalid");
ret = -EINVAL;
}
qemu_opts_del(opts);
return 0;
return ret;
}

static void null_close(BlockDriverState *bs)
Expand All @@ -58,28 +74,40 @@ static int64_t null_getlength(BlockDriverState *bs)
return s->length;
}

static coroutine_fn int null_co_common(BlockDriverState *bs)
{
BDRVNullState *s = bs->opaque;

if (s->latency_ns) {
co_aio_sleep_ns(bdrv_get_aio_context(bs), QEMU_CLOCK_REALTIME,
s->latency_ns);
}
return 0;
}

static coroutine_fn int null_co_readv(BlockDriverState *bs,
int64_t sector_num, int nb_sectors,
QEMUIOVector *qiov)
{
return 0;
return null_co_common(bs);
}

static coroutine_fn int null_co_writev(BlockDriverState *bs,
int64_t sector_num, int nb_sectors,
QEMUIOVector *qiov)
{
return 0;
return null_co_common(bs);
}

static coroutine_fn int null_co_flush(BlockDriverState *bs)
{
return 0;
return null_co_common(bs);
}

typedef struct {
BlockAIOCB common;
QEMUBH *bh;
QEMUTimer timer;
} NullAIOCB;

static const AIOCBInfo null_aiocb_info = {
Expand All @@ -94,15 +122,33 @@ static void null_bh_cb(void *opaque)
qemu_aio_unref(acb);
}

static void null_timer_cb(void *opaque)
{
NullAIOCB *acb = opaque;
acb->common.cb(acb->common.opaque, 0);
timer_deinit(&acb->timer);
qemu_aio_unref(acb);
}

static inline BlockAIOCB *null_aio_common(BlockDriverState *bs,
BlockCompletionFunc *cb,
void *opaque)
{
NullAIOCB *acb;
BDRVNullState *s = bs->opaque;

acb = qemu_aio_get(&null_aiocb_info, bs, cb, opaque);
acb->bh = aio_bh_new(bdrv_get_aio_context(bs), null_bh_cb, acb);
qemu_bh_schedule(acb->bh);
/* Only emulate latency after vcpu is running. */
if (s->latency_ns) {
aio_timer_init(bdrv_get_aio_context(bs), &acb->timer,
QEMU_CLOCK_REALTIME, SCALE_NS,
null_timer_cb, acb);
timer_mod_ns(&acb->timer,
qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + s->latency_ns);
} else {
acb->bh = aio_bh_new(bdrv_get_aio_context(bs), null_bh_cb, acb);
qemu_bh_schedule(acb->bh);
}
return &acb->common;
}

Expand Down
5 changes: 4 additions & 1 deletion qapi/block-core.json
Original file line number Diff line number Diff line change
Expand Up @@ -1310,11 +1310,14 @@
# Driver specific block device options for the null backend.
#
# @size: #optional size of the device in bytes.
# @latency-ns: #optional emulated latency (in nanoseconds) in processing
# requests. Default to zero which completes requests immediately.
# (Since 2.4)
#
# Since: 2.2
##
{ 'type': 'BlockdevOptionsNull',
'data': { '*size': 'int' } }
'data': { '*size': 'int', '*latency-ns': 'uint64' } }

##
# @BlockdevOptionsVVFAT
Expand Down

0 comments on commit e5e51dd

Please sign in to comment.