From ca3962bf4aeffd518339bd669e314d56661916cd Mon Sep 17 00:00:00 2001 From: Darek Stojaczyk Date: Mon, 17 Dec 2018 03:45:35 +0100 Subject: [PATCH] vhost: introduce per-session coalescing settings Keep all coalescing variables inside the session struct. Interrupt coalescing is still configured with the device- pecific APIs, but those will now transparently propagate the change to all active connections. This is the last piece that held struct spdk_vhost_dev tied with the session's lcore. Now that device settings aren't actively polled by any sessions, they only need to be synchronized with the global vhost lock. This will potentially let us get rid of the vhost external events API, allowing user to lock the mutex directly, set coalescing params directly, and transparently let the internal spdk_vhost_dev_foreach_session() do the tricky synchronization. Change-Id: Ifba96d241c736d33376861fa894c738e7d9b5b40 Signed-off-by: Darek Stojaczyk Reviewed-on: https://review.gerrithub.io/c/437777 Reviewed-by: Pawel Wodkowski Reviewed-by: Jim Harris Reviewed-by: Shuhei Matsumoto Tested-by: SPDK CI Jenkins Chandler-Test-Pool: SPDK Automated Test System --- lib/vhost/vhost.c | 39 ++++++++++++++++++++++++++------------ lib/vhost/vhost_internal.h | 18 +++++++++++------- 2 files changed, 38 insertions(+), 19 deletions(-) diff --git a/lib/vhost/vhost.c b/lib/vhost/vhost.c index e5b1d85188..e801f6dca3 100644 --- a/lib/vhost/vhost.c +++ b/lib/vhost/vhost.c @@ -268,19 +268,18 @@ spdk_vhost_vq_used_signal(struct spdk_vhost_session *vsession, static void check_session_io_stats(struct spdk_vhost_session *vsession, uint64_t now) { - struct spdk_vhost_dev *vdev = vsession->vdev; struct spdk_vhost_virtqueue *virtqueue; - uint32_t irq_delay_base = vdev->coalescing_delay_time_base; - uint32_t io_threshold = vdev->coalescing_io_rate_threshold; + uint32_t irq_delay_base = vsession->coalescing_delay_time_base; + uint32_t io_threshold = vsession->coalescing_io_rate_threshold; int32_t irq_delay; uint32_t req_cnt; uint16_t q_idx; - if (now < vdev->next_stats_check_time) { + if (now < vsession->next_stats_check_time) { return; } - vdev->next_stats_check_time = now + vdev->stats_check_interval; + vsession->next_stats_check_time = now + vsession->stats_check_interval; for (q_idx = 0; q_idx < vsession->max_queues; q_idx++) { virtqueue = &vsession->virtqueue[q_idx]; @@ -300,12 +299,11 @@ check_session_io_stats(struct spdk_vhost_session *vsession, uint64_t now) void spdk_vhost_session_used_signal(struct spdk_vhost_session *vsession) { - struct spdk_vhost_dev *vdev = vsession->vdev; struct spdk_vhost_virtqueue *virtqueue; uint64_t now; uint16_t q_idx; - if (vdev->coalescing_delay_time_base == 0) { + if (vsession->coalescing_delay_time_base == 0) { for (q_idx = 0; q_idx < vsession->max_queues; q_idx++) { virtqueue = &vsession->virtqueue[q_idx]; @@ -340,19 +338,33 @@ spdk_vhost_session_used_signal(struct spdk_vhost_session *vsession) } } +static int +spdk_vhost_session_set_coalescing(struct spdk_vhost_dev *vdev, + struct spdk_vhost_session *vsession, void *ctx) +{ + if (vdev == NULL || vsession == NULL) { + /* nothing to do */ + return 0; + } + + vsession->coalescing_delay_time_base = vdev->coalescing_delay_time_base; + vsession->coalescing_io_rate_threshold = vdev->coalescing_io_rate_threshold; + return 0; +} + int spdk_vhost_set_coalescing(struct spdk_vhost_dev *vdev, uint32_t delay_base_us, uint32_t iops_threshold) { uint64_t delay_time_base = delay_base_us * spdk_get_ticks_hz() / 1000000ULL; - uint32_t io_rate = iops_threshold * SPDK_VHOST_DEV_STATS_CHECK_INTERVAL_MS / 1000U; + uint32_t io_rate = iops_threshold * SPDK_VHOST_STATS_CHECK_INTERVAL_MS / 1000U; if (delay_time_base >= UINT32_MAX) { SPDK_ERRLOG("Delay time of %"PRIu32" is to big\n", delay_base_us); return -EINVAL; } else if (io_rate == 0) { SPDK_ERRLOG("IOPS rate of %"PRIu32" is too low. Min is %u\n", io_rate, - 1000U / SPDK_VHOST_DEV_STATS_CHECK_INTERVAL_MS); + 1000U / SPDK_VHOST_STATS_CHECK_INTERVAL_MS); return -EINVAL; } @@ -361,6 +373,8 @@ spdk_vhost_set_coalescing(struct spdk_vhost_dev *vdev, uint32_t delay_base_us, vdev->coalescing_delay_us = delay_base_us; vdev->coalescing_iops_threshold = iops_threshold; + + spdk_vhost_dev_foreach_session(vdev, spdk_vhost_session_set_coalescing, NULL); return 0; } @@ -757,9 +771,6 @@ spdk_vhost_dev_register(struct spdk_vhost_dev *vdev, const char *name, const cha spdk_vhost_set_coalescing(vdev, SPDK_VHOST_COALESCING_DELAY_BASE_US, SPDK_VHOST_VQ_IOPS_COALESCING_THRESHOLD); - vdev->next_stats_check_time = 0; - vdev->stats_check_interval = SPDK_VHOST_DEV_STATS_CHECK_INTERVAL_MS * spdk_get_ticks_hz() / - 1000UL; TAILQ_INSERT_TAIL(&g_spdk_vhost_devices, vdev, tailq); @@ -1130,6 +1141,7 @@ start_device(int vid) } } + spdk_vhost_session_set_coalescing(vdev, vsession, NULL); vdev->lcore = spdk_vhost_allocate_reactor(vdev->cpumask); spdk_vhost_session_mem_register(vsession); rc = _spdk_vhost_event_send(vdev, vdev->backend->start_device, 3, "start device"); @@ -1282,6 +1294,9 @@ new_connection(int vid) vsession->vdev = vdev; vsession->vid = vid; + vsession->next_stats_check_time = 0; + vsession->stats_check_interval = SPDK_VHOST_STATS_CHECK_INTERVAL_MS * + spdk_get_ticks_hz() / 1000UL; vdev->session = vsession; pthread_mutex_unlock(&g_spdk_vhost_mutex); return 0; diff --git a/lib/vhost/vhost_internal.h b/lib/vhost/vhost_internal.h index 97f0e707dc..a3db7d9211 100644 --- a/lib/vhost/vhost_internal.h +++ b/lib/vhost/vhost_internal.h @@ -70,7 +70,7 @@ /* * Rate at which stats are checked for interrupt coalescing. */ -#define SPDK_VHOST_DEV_STATS_CHECK_INTERVAL_MS 10 +#define SPDK_VHOST_STATS_CHECK_INTERVAL_MS 10 /* * Default threshold at which interrupts start to be coalesced. */ @@ -147,6 +147,16 @@ struct spdk_vhost_session { uint64_t negotiated_features; + /* Local copy of device coalescing settings. */ + uint32_t coalescing_delay_time_base; + uint32_t coalescing_io_rate_threshold; + + /* Next time when stats for event coalescing will be checked. */ + uint64_t next_stats_check_time; + + /* Interval used for event coalescing checking. */ + uint64_t stats_check_interval; + struct spdk_vhost_virtqueue virtqueue[SPDK_VHOST_MAX_VQUEUES]; }; @@ -174,12 +184,6 @@ struct spdk_vhost_dev { /* Threshold when event coalescing for virtqueue will be turned on. */ uint32_t coalescing_io_rate_threshold; - /* Next time when stats for event coalescing will be checked. */ - uint64_t next_stats_check_time; - - /* Interval used for event coalescing checking. */ - uint64_t stats_check_interval; - /* Active connection to the device */ struct spdk_vhost_session *session;