From 2c8ffe9e741d24df5954969d5bffc6a469a8b52b Mon Sep 17 00:00:00 2001 From: Ben Walker Date: Mon, 11 Mar 2019 15:26:53 -0700 Subject: [PATCH] bdev/nvme: Add configuration parameter to slow down polling For NVMe devices, in conjunction with the new batching options, it can be advantageous to artificially delay between polling for completions. Add an option to slow this rate down. Change-Id: I0fc92709ff45ead0beb388dda60694bf1ed8b258 Signed-off-by: Ben Walker Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/447716 Tested-by: SPDK CI Jenkins Reviewed-by: Jim Harris Reviewed-by: Changpeng Liu --- doc/jsonrpc.md | 3 ++- etc/spdk/iscsi.conf.in | 3 +++ etc/spdk/nvmf.conf.in | 3 +++ etc/spdk/vhost.conf.in | 3 +++ lib/bdev/nvme/bdev_nvme.c | 10 +++++++++- lib/bdev/nvme/bdev_nvme.h | 1 + lib/bdev/nvme/bdev_nvme_rpc.c | 1 + scripts/rpc.py | 5 ++++- scripts/rpc/bdev.py | 9 +++++++-- 9 files changed, 33 insertions(+), 5 deletions(-) diff --git a/doc/jsonrpc.md b/doc/jsonrpc.md index 358562e86..1e62a9f6d 100644 --- a/doc/jsonrpc.md +++ b/doc/jsonrpc.md @@ -903,7 +903,8 @@ Name | Optional | Type | Description action_on_timeout | Optional | string | Action to take on command time out: none, reset or abort timeout_us | Optional | number | Timeout for each command, in microseconds. If 0, don't track timeouts retry_count | Optional | number | The number of attempts per I/O before an I/O fails -nvme_adminq_poll_period_us | Optional | number | How often the admin queue is polled for asynchronous events in microsecond +nvme_adminq_poll_period_us | Optional | number | How often the admin queue is polled for asynchronous events in microseconds +nvme_ioq_poll_period_us | Optional | number | How often I/O queues are polled for completions, in microseconds. Default: 0 (as fast as possible). ### Example diff --git a/etc/spdk/iscsi.conf.in b/etc/spdk/iscsi.conf.in index 2f725dc13..1a5dc9a80 100644 --- a/etc/spdk/iscsi.conf.in +++ b/etc/spdk/iscsi.conf.in @@ -118,6 +118,9 @@ # Set how often the admin queue is polled for asynchronous events. # Units in microseconds. AdminPollRate 100000 + # Set how often I/O queues are polled from completions. + # Units in microseconds. + IOPollRate 0 # Disable handling of hotplug (runtime insert and remove) events, # users can set to Yes if want to enable it. diff --git a/etc/spdk/nvmf.conf.in b/etc/spdk/nvmf.conf.in index 66ca5a0cd..3be1005d3 100644 --- a/etc/spdk/nvmf.conf.in +++ b/etc/spdk/nvmf.conf.in @@ -109,6 +109,9 @@ # Set how often the admin queue is polled for asynchronous events. # Units in microseconds. AdminPollRate 100000 + # Set how often I/O queues are polled from completions. + # Units in microseconds. + IOPollRate 0 # Disable handling of hotplug (runtime insert and remove) events, # users can set to Yes if want to enable it. diff --git a/etc/spdk/vhost.conf.in b/etc/spdk/vhost.conf.in index 1605749d5..1a414cf11 100644 --- a/etc/spdk/vhost.conf.in +++ b/etc/spdk/vhost.conf.in @@ -99,6 +99,9 @@ # Set how often the admin queue is polled for asynchronous events. # Units in microseconds. AdminPollRate 100000 + # Set how often I/O queues are polled from completions. + # Units in microseconds. + IOPollRate 0 # The Split virtual block device slices block devices into multiple smaller bdevs. [Split] diff --git a/lib/bdev/nvme/bdev_nvme.c b/lib/bdev/nvme/bdev_nvme.c index f2787d425..5b98a1e72 100644 --- a/lib/bdev/nvme/bdev_nvme.c +++ b/lib/bdev/nvme/bdev_nvme.c @@ -98,6 +98,7 @@ static struct spdk_bdev_nvme_opts g_opts = { .timeout_us = 0, .retry_count = SPDK_NVME_DEFAULT_RETRY_COUNT, .nvme_adminq_poll_period_us = 1000000ULL, + .nvme_ioq_poll_period_us = 0, }; #define NVME_HOTPLUG_POLL_PERIOD_MAX 10000000ULL @@ -532,7 +533,7 @@ bdev_nvme_create_cb(void *io_device, void *ctx_buf) return -1; } - ch->poller = spdk_poller_register(bdev_nvme_poll, ch, 0); + ch->poller = spdk_poller_register(bdev_nvme_poll, ch, g_opts.nvme_ioq_poll_period_us); return 0; } @@ -1308,6 +1309,11 @@ bdev_nvme_library_init(void) g_opts.nvme_adminq_poll_period_us = intval; } + intval = spdk_conf_section_get_intval(sp, "IOPollRate"); + if (intval > 0) { + g_opts.nvme_ioq_poll_period_us = intval; + } + if (spdk_process_is_primary()) { hotplug_enabled = spdk_conf_section_get_boolval(sp, "HotplugEnable", false); } @@ -1732,6 +1738,7 @@ bdev_nvme_get_spdk_running_config(FILE *fp) "# Set how often the admin queue is polled for asynchronous events.\n" "# Units in microseconds.\n"); fprintf(fp, "AdminPollRate %"PRIu64"\n", g_opts.nvme_adminq_poll_period_us); + fprintf(fp, "IOPollRate %" PRIu64"\n", g_opts.nvme_ioq_poll_period_us); fprintf(fp, "\n" "# Disable handling of hotplug (runtime insert and remove) events,\n" "# users can set to Yes if want to enable it.\n" @@ -1773,6 +1780,7 @@ bdev_nvme_config_json(struct spdk_json_write_ctx *w) spdk_json_write_named_uint64(w, "timeout_us", g_opts.timeout_us); spdk_json_write_named_uint32(w, "retry_count", g_opts.retry_count); spdk_json_write_named_uint64(w, "nvme_adminq_poll_period_us", g_opts.nvme_adminq_poll_period_us); + spdk_json_write_named_uint64(w, "nvme_ioq_poll_period_us", g_opts.nvme_ioq_poll_period_us); spdk_json_write_object_end(w); spdk_json_write_object_end(w); diff --git a/lib/bdev/nvme/bdev_nvme.h b/lib/bdev/nvme/bdev_nvme.h index f48c696b0..3afd0e0bd 100644 --- a/lib/bdev/nvme/bdev_nvme.h +++ b/lib/bdev/nvme/bdev_nvme.h @@ -53,6 +53,7 @@ struct spdk_bdev_nvme_opts { uint64_t timeout_us; uint32_t retry_count; uint64_t nvme_adminq_poll_period_us; + uint64_t nvme_ioq_poll_period_us; }; struct nvme_ctrlr { diff --git a/lib/bdev/nvme/bdev_nvme_rpc.c b/lib/bdev/nvme/bdev_nvme_rpc.c index a9154d4e5..9f5ccbf33 100644 --- a/lib/bdev/nvme/bdev_nvme_rpc.c +++ b/lib/bdev/nvme/bdev_nvme_rpc.c @@ -73,6 +73,7 @@ static const struct spdk_json_object_decoder rpc_bdev_nvme_options_decoders[] = {"timeout_us", offsetof(struct spdk_bdev_nvme_opts, timeout_us), spdk_json_decode_uint64, true}, {"retry_count", offsetof(struct spdk_bdev_nvme_opts, retry_count), spdk_json_decode_uint32, true}, {"nvme_adminq_poll_period_us", offsetof(struct spdk_bdev_nvme_opts, nvme_adminq_poll_period_us), spdk_json_decode_uint64, true}, + {"nvme_ioq_poll_period_us", offsetof(struct spdk_bdev_nvme_opts, nvme_ioq_poll_period_us), spdk_json_decode_uint64, true}, }; static void diff --git a/scripts/rpc.py b/scripts/rpc.py index 7f2698f80..5ee4ef97a 100755 --- a/scripts/rpc.py +++ b/scripts/rpc.py @@ -224,7 +224,8 @@ if __name__ == "__main__": action_on_timeout=args.action_on_timeout, timeout_us=args.timeout_us, retry_count=args.retry_count, - nvme_adminq_poll_period_us=args.nvme_adminq_poll_period_us) + nvme_adminq_poll_period_us=args.nvme_adminq_poll_period_us, + nvme_ioq_poll_period_us=args.nvme_ioq_poll_period_us) p = subparsers.add_parser('set_bdev_nvme_options', help='Set options for the bdev nvme type. This is startup command.') @@ -236,6 +237,8 @@ if __name__ == "__main__": help='the number of attempts per I/O when an I/O fails', type=int) p.add_argument('-p', '--nvme-adminq-poll-period-us', help='How often the admin queue is polled for asynchronous events', type=int) + p.add_argument('-i', '--nvme-ioq-poll-period-us', + help='How often to poll I/O queues for completions', type=int) p.set_defaults(func=set_bdev_nvme_options) @call_cmd diff --git a/scripts/rpc/bdev.py b/scripts/rpc/bdev.py index ada9448ea..b1278c897 100755 --- a/scripts/rpc/bdev.py +++ b/scripts/rpc/bdev.py @@ -147,14 +147,16 @@ def delete_aio_bdev(client, name): return client.call('delete_aio_bdev', params) -def set_bdev_nvme_options(client, action_on_timeout=None, timeout_us=None, retry_count=None, nvme_adminq_poll_period_us=None): +def set_bdev_nvme_options(client, action_on_timeout=None, timeout_us=None, retry_count=None, + nvme_adminq_poll_period_us=None, nvme_ioq_poll_period_us=None): """Set options for the bdev nvme. This is startup command. Args: action_on_timeout: action to take on command time out. Valid values are: none, reset, abort (optional) timeout_us: Timeout for each command, in microseconds. If 0, don't track timeouts (optional) retry_count: The number of attempts per I/O when an I/O fails (optional) - nvme_adminq_poll_period_us: how often the admin queue is polled for asynchronous events in microsecon (optional) + nvme_adminq_poll_period_us: How often the admin queue is polled for asynchronous events in microseconds (optional) + nvme_ioq_poll_period_us: How often to poll I/O queues for completions in microseconds (optional) """ params = {} @@ -170,6 +172,9 @@ def set_bdev_nvme_options(client, action_on_timeout=None, timeout_us=None, retry if nvme_adminq_poll_period_us: params['nvme_adminq_poll_period_us'] = nvme_adminq_poll_period_us + if nvme_ioq_poll_period_us: + params['nvme_ioq_poll_period_us'] = nvme_ioq_poll_period_us + return client.call('set_bdev_nvme_options', params)