diff --git a/0004-vhost-add-vhost-interrupt-coalescing.patch b/0004-vhost-add-vhost-interrupt-coalescing.patch new file mode 100644 index 0000000000000000000000000000000000000000..d611aa0870080f54c1272f12099fd5fa6b414997 --- /dev/null +++ b/0004-vhost-add-vhost-interrupt-coalescing.patch @@ -0,0 +1,193 @@ +From 22f290e64efb5f65af5bb67b3602c0c7a9049bd7 Mon Sep 17 00:00:00 2001 +From: Chengfei Huang +Date: Wed, 21 May 2025 14:47:22 +0800 +Subject: [PATCH] vhost: add vhost interrupt coalescing + +Based on virtio event idx. use vhost -E option to enable. +This patch is designed for high throughput, not recommended if low latency is +desired. +--- + app/vhost/vhost.c | 4 +++ + include/spdk/event.h | 2 +- + include/spdk/vhost.h | 8 +++++ + lib/vhost/rte_vhost_user.c | 60 ++++++++++++++++++++++++++++++++++++++ + lib/vhost/spdk_vhost.map | 1 + + lib/vhost/vhost_internal.h | 4 +++ + 6 files changed, 78 insertions(+), 1 deletion(-) + +diff --git a/app/vhost/vhost.c b/app/vhost/vhost.c +index 992ba29a6203..ce510881ec98 100644 +--- a/app/vhost/vhost.c ++++ b/app/vhost/vhost.c +@@ -16,6 +16,7 @@ vhost_usage(void) + { + printf(" -f save pid to file under given path\n"); + printf(" -S directory where to create vhost sockets (default: pwd)\n"); ++ printf(" -E Enable Backend Interrupt Coalescing\n"); + } + + static void +@@ -43,6 +44,9 @@ vhost_parse_arg(int ch, char *arg) + case 'S': + spdk_vhost_set_socket_path(arg); + break; ++ case 'E': ++ spdk_vhost_set_backend_interrupt_coalescing(true); ++ break; + default: + return -EINVAL; + } +diff --git a/include/spdk/event.h b/include/spdk/event.h +index 6f4e7c8deaf0..6c65af1d9d1d 100644 +--- a/include/spdk/event.h ++++ b/include/spdk/event.h +@@ -277,7 +277,7 @@ int spdk_app_parse_core_mask(const char *mask, struct spdk_cpuset *cpumask); + */ + const struct spdk_cpuset *spdk_app_get_core_mask(void); + +-#define SPDK_APP_GETOPT_STRING "c:de:ghi:m:n:p:r:s:uvA:B:L:RW:" ++#define SPDK_APP_GETOPT_STRING "c:de:ghi:m:n:p:r:s:uvA:B:L:RW:E" + + enum spdk_app_parse_args_rvals { + SPDK_APP_PARSE_ARGS_HELP = 0, +diff --git a/include/spdk/vhost.h b/include/spdk/vhost.h +index 020685786487..4f111fac9b1f 100644 +--- a/include/spdk/vhost.h ++++ b/include/spdk/vhost.h +@@ -340,6 +340,14 @@ int spdk_vhost_blk_construct(const char *name, const char *cpumask, const char * + */ + int spdk_vhost_dev_remove(struct spdk_vhost_dev *vdev); + ++/** ++ * Enable spdk backend interrupt coalescing. ++ * Diff than spdk_vhost_get_coalescing, this use virtio used event idx. ++ * \param enable to enable or disable. ++ * ++ */ ++void spdk_vhost_set_backend_interrupt_coalescing(bool enable); ++ + #ifdef __cplusplus + } + #endif +diff --git a/lib/vhost/rte_vhost_user.c b/lib/vhost/rte_vhost_user.c +index 17a3e0f3651b..b5db1c50e5b2 100644 +--- a/lib/vhost/rte_vhost_user.c ++++ b/lib/vhost/rte_vhost_user.c +@@ -23,6 +23,8 @@ static char g_vhost_user_dev_dirname[PATH_MAX] = ""; + + static struct spdk_thread *g_vhost_user_init_thread; + ++static bool g_backend_interrupt_coalescing = false; ++ + /** + * DPDK calls our callbacks synchronously but the work those callbacks + * perform needs to be async. Luckily, all DPDK callbacks are called on +@@ -346,6 +348,33 @@ vhost_inflight_queue_get_desc(struct spdk_vhost_session *vsession, + return 0; + } + ++#define spdk_vhost_used_event(vr) \ ++ (*(volatile uint16_t*)&(vr)->vring.avail->ring[(vr)->vring.size]) ++ ++void spdk_vhost_set_backend_interrupt_coalescing(bool enable) { ++ SPDK_NOTICELOG("Set SPDK backend interrupt coalescing mode.\n"); ++ g_backend_interrupt_coalescing = enable; ++} ++ ++bool spdk_vhost_get_backend_interrupt_coalescing(void) { ++ return g_backend_interrupt_coalescing; ++} ++ ++#define spdk_vhost_used_event(vr) \ ++ (*(volatile uint16_t*)&(vr)->vring.avail->ring[(vr)->vring.size]) ++ ++/* ++ * The following is used with VIRTIO_RING_F_EVENT_IDX. ++ * Assuming a given event_idx value from the other size, if we have ++ * just incremented index from old to new_idx, should we trigger an ++ * event? ++ */ ++static inline int ++spdk_need_event(uint16_t event_idx, uint16_t new_idx, uint16_t old) ++{ ++ return (uint16_t)(new_idx - event_idx - 1) < (uint16_t)(new_idx - old); ++} ++ + int + vhost_vq_used_signal(struct spdk_vhost_session *vsession, + struct spdk_vhost_virtqueue *virtqueue) +@@ -357,6 +386,37 @@ vhost_vq_used_signal(struct spdk_vhost_session *vsession, + SPDK_DEBUGLOG(vhost_ring, + "Queue %td - USED RING: sending IRQ: last used %"PRIu16"\n", + virtqueue - vsession->virtqueue, virtqueue->last_used_idx); ++ if (spdk_vhost_get_backend_interrupt_coalescing() == true) { ++ bool used_signalled_valid = virtqueue->used_signalled_valid; ++ uint16_t old = virtqueue->used_signalled; ++ uint16_t new = virtqueue->last_used_idx; ++ ++ struct rte_vhost_vring *vring = &virtqueue->vring; ++ struct vring_avail *avail = vring->avail; ++ uint16_t guest_used_event = spdk_vhost_used_event(virtqueue); ++ uint16_t cur_ring_size = (uint16_t)(avail->idx - guest_used_event); ++ uint16_t target; ++ ++ if(cur_ring_size == 1) { ++ // only one remained, complete it ASAP. ++ target = guest_used_event; ++ } else if (cur_ring_size > vring->size * 3 / 4) { ++ // vring almost full, let's interrupt front end quick. ++ target = guest_used_event + cur_ring_size * 1 / 8; ++ } else if (cur_ring_size > vring->size * 1 / 4) { ++ // vring isn't so full, let's interrupt front end a little slow. ++ target = guest_used_event + cur_ring_size * 1 / 4; ++ } else { ++ // vring almost empty, let's interrupt less for more queue item. ++ target = guest_used_event + cur_ring_size * 1 / 2; ++ } ++ ++ if(!spdk_need_event(target, new, old) && used_signalled_valid) { ++ return 0; ++ } ++ virtqueue->used_signalled_valid = true; ++ virtqueue->used_signalled = virtqueue->last_used_idx; ++ } + + #if RTE_VERSION < RTE_VERSION_NUM(22, 11, 0, 0) + if (rte_vhost_vring_call(vsession->vid, virtqueue->vring_idx) == 0) { +diff --git a/lib/vhost/spdk_vhost.map b/lib/vhost/spdk_vhost.map +index f8b9d55476bc..0a0b2ab05e88 100644 +--- a/lib/vhost/spdk_vhost.map ++++ b/lib/vhost/spdk_vhost.map +@@ -2,6 +2,7 @@ + global: + + # public functions ++ spdk_vhost_set_backend_interrupt_coalescing; + spdk_vhost_set_socket_path; + spdk_vhost_scsi_init; + spdk_vhost_scsi_fini; +diff --git a/lib/vhost/vhost_internal.h b/lib/vhost/vhost_internal.h +index 04e7440632b2..f94c9e157d46 100644 +--- a/lib/vhost/vhost_internal.h ++++ b/lib/vhost/vhost_internal.h +@@ -66,6 +66,8 @@ struct spdk_vhost_virtqueue { + struct rte_vhost_ring_inflight vring_inflight; + uint16_t last_avail_idx; + uint16_t last_used_idx; ++ uint16_t used_signalled; ++ uint16_t used_signalled_valid; + + struct { + /* To mark a descriptor as available in packed ring +@@ -615,4 +617,6 @@ static void __attribute__((constructor)) _virtio_blk_transport_register_##name(v + virtio_blk_transport_register(transport_ops); \ + } + ++bool spdk_vhost_get_backend_interrupt_coalescing(void); ++ + #endif /* SPDK_VHOST_INTERNAL_H */ + +base-commit: d4c2d3730293f91bc71c5fc38cc8ae27a7c7c9ce +-- +2.50.1 + diff --git a/spdk.spec b/spdk.spec index 3520b0dfdb63be5de0190b409a5c818ff55d30b3..d9c1100eb8c32e39b4ae4297075bd3d4a4439a5f 100644 --- a/spdk.spec +++ b/spdk.spec @@ -4,7 +4,7 @@ Name: spdk Version: 24.01 -Release: 8 +Release: 9 Summary: Set of libraries and utilities for high performance user-mode storage License: BSD and MIT URL: http://spdk.io @@ -12,6 +12,7 @@ Source0: https://github.com/spdk/spdk/archive/refs/tags/v%{version}.tar.gz Patch1: 0001-Add-without-ISA-L-option-and-disabled-by-default.patch Patch2: 0002-backport-Add-ctrlr_lock-for-cuse-register-and-unregister.patch Patch3: 0100-spdk-uos-add-sw64-support.patch +Patch4: 0004-vhost-add-vhost-interrupt-coalescing.patch %define package_version %{version}-%{release} @@ -179,6 +180,9 @@ mv doc/output/html/ %{install_docdir} %changelog +* Tue Aug 19 2025 jiaqingtong - 24.01-9 +- vhost: add vhost interrupt coalescing model + * Fri Feb 28 2025 zhangshaoning - 24.01-8 - Add sw_64 support