From: Pravin Pathak <pravinpathakdev@gmail.com>
To: dev@dpdk.org
Cc: jerinj@marvell.com, mike.ximing.chen@intel.com,
bruce.richardson@intel.com, thomas@monjalon.net,
david.marchand@redhat.com, nipun.gupta@amd.com,
chenbox@nvidia.com, tirthendu.sarkar@intel.com,
Pravin Pathak <pravin.pathak.dev@gmail.com>
Subject: [PATCH v1 7/8] event/slb: update resets and credit defaults
Date: Fri, 6 Nov 2026 20:30:09 -0500 [thread overview]
Message-ID: <20261107013011.2443138-8-pravinpathakdev@gmail.com> (raw)
In-Reply-To: <20261107013011.2443138-1-pravinpathakdev@gmail.com>
From: Pravin Pathak <pravin.pathak.dev@gmail.com>
- Force RTE_SCHED_TYPE_ATOMIC on events dequeued from single-link queues
and skip atomic/ordered state allocations for single-link queues.
- Remove RTE_EVENT_DEV_CAP_RUNTIME_PORT_LINK advertisement from driver
info, feature matrix, and release notes.
- Reset atomic queue flow-to-port mappings, hold buffers, migration
state, per-port stats, ordered reorder buffers, and port history when
the device is stopped in slb_stop().
- Default port new_event_threshold in slb_port_def_conf() to 1/4 of
SLB_IN_RING_SIZE (clamped to nb_events_limit when configured) and
lower SLB_MIN_CREDIT_LOAN from 512 to 256 so more ports can borrow
credits concurrently.
Signed-off-by: Pravin Pathak <pravin.pathak.dev@gmail.com>
---
doc/guides/eventdevs/features/slb.ini | 1 -
doc/guides/eventdevs/slb.rst | 31 ++++------
drivers/event/slb/slb_evdev.c | 81 +++++++++++++++++++++------
drivers/event/slb/slb_evdev.h | 5 +-
drivers/event/slb/slb_event.c | 23 ++++++--
drivers/event/slb/slb_selftest.c | 12 ++++
6 files changed, 110 insertions(+), 43 deletions(-)
diff --git a/doc/guides/eventdevs/features/slb.ini b/doc/guides/eventdevs/features/slb.ini
index 0364840bc9..33036301a8 100644
--- a/doc/guides/eventdevs/features/slb.ini
+++ b/doc/guides/eventdevs/features/slb.ini
@@ -11,7 +11,6 @@ distributed_sched = Y
burst_mode = Y
implicit_release_disable = Y
nonseq_mode = Y
-runtime_port_link = Y
multiple_queue_port = Y
carry_flow_id = Y
maintenance_free = Y
diff --git a/doc/guides/eventdevs/slb.rst b/doc/guides/eventdevs/slb.rst
index d319b94920..b109a1e2ca 100644
--- a/doc/guides/eventdevs/slb.rst
+++ b/doc/guides/eventdevs/slb.rst
@@ -4,9 +4,10 @@
Software Load Balancer (SLB) Eventdev Driver
============================================
-The Software Load Balancer (SLB) event device is a poll-mode eventdev driver
-which distributes events among multiple worker ports and cores without requiring
-dedicated scheduling service cores or hardware coprocessors.
+The Software Load Balancer (SLB) is a software event device and a poll-mode Eventdev driver.
+It uses a distributed scheduler, allowing it to scale well. SLB does not require dedicated
+cores for scheduling. It supports Atomic, Parallel, and Ordered queues with dynamic atomic
+flow load balancing. SLB also requires no internal core communication and is maintenance-free.
Features
--------
@@ -19,25 +20,17 @@ Queues
* **Atomic**: Flow-pinned scheduling guaranteeing strict per-flow packet ordering.
Includes dynamic load tracking and automatic flow migration to rebalance overloaded
ports while preserving in-flight sequence integrity.
-* **Ordered**: Ticket-based sequence tracking and reorder buffer providing end-to-end
- packet order restoration across parallel processing workers.
-* **Single-Link**: Dedicated direct queue mapping from a producer port to a single
- consumer port using optimized single-consumer rings.
+* **Ordered**: Sequence number-based tracking and reordering.
+* **Single-Link**: Implemented using optimized multi-producer single-consumer rings.
Ports & Scheduling Capabilities
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-* **Distributed Scheduling**: No dedicated service core required; scheduling work is
- performed inline during enqueue and dequeue operations.
-* **Prefix Sum Burst Enqueue**: Interleaved multi-queue bursts are grouped and scattered
- via prefix-sum offsets, dispatching single batched bursts to queue rings to eliminate
- atomic Compare-And-Swap contention on multi-producer rings.
+* **Distributed Scheduling**: No dedicated service core required.
* **Dynamic Flow Migration**: Atomic queues monitor port dequeue loads and migrate
- eligible victim flows from overloaded ports to underloaded ports with cooling cycles.
+ Eligible flows from overloaded ports to underloaded ports with cooling cycles.
* **Credit Pool Management**: Centralized event credit pool with per-port credit caching
to enforce device-wide in-flight event limits (``max_num_events``).
-* **Runtime Port Linking**: Supports dynamic linking and unlinking of ports and queues
- both when stopped and at runtime.
* **Maintenance Free**: Operates without requiring periodic maintenance calls
(``RTE_EVENT_DEV_CAP_MAINTENANCE_FREE``).
@@ -62,7 +55,7 @@ application code or from the EAL command line:
Limitations
-----------
-* **Flow Hash Table Size**: Atomic queues use an internal flow mapping table
- dimensioned to 2048 concurrent active flows per queue (``SLB_ATOMIC_FLOWS``).
-* **Maximum Ports and Queues**: Configured for up to 64 ports (``SLB_MAX_PORTS``)
- and 64 queues (``SLB_MAX_QUEUES``).
+* **Maximum Ports and Queues**: Supports up to 64 ports and 64 queues.
+* **Priorities and linking**: Supports two levels of service priority to link up to
+ eight queues per port at each priority. SLB currently does not support event priority.
+* **Queues Types**: Does not support all-type queues.
diff --git a/drivers/event/slb/slb_evdev.c b/drivers/event/slb/slb_evdev.c
index c86b934b03..16bfefaa68 100644
--- a/drivers/event/slb/slb_evdev.c
+++ b/drivers/event/slb/slb_evdev.c
@@ -26,6 +26,7 @@ slb_port_reset_history(struct slb_port *port)
{
port->history[0].active = false;
port->history[0].next_free = SLB_PORT_HISTORY_FREE_END;
+ /* 1 -> 2 -> 3 ..... 255 -> END */
for (int i = 1; i < SLB_PORT_HISTORY_SIZE; i++) {
port->history[i].active = false;
port->history[i].next_free = i + 1;
@@ -36,7 +37,7 @@ slb_port_reset_history(struct slb_port *port)
port->history_avail = SLB_PORT_HISTORY_MAX_TOKENS;
}
-/* Setup Eventdev port. Reset all mapped queues */
+/* Setup Eventdev port. Reset all mapped queues and history tracking */
static int
slb_port_setup(struct rte_eventdev *dev, uint8_t port_id,
const struct rte_event_port_conf *conf)
@@ -103,12 +104,18 @@ slb_port_setup(struct rte_eventdev *dev, uint8_t port_id,
/* Default Eventdev port configuration for SLB */
static void
-slb_port_def_conf(struct rte_eventdev *dev __rte_unused,
+slb_port_def_conf(struct rte_eventdev *dev,
uint8_t port_id __rte_unused,
struct rte_event_port_conf *port_conf)
{
+ int32_t threshold = SLB_IN_RING_SIZE / 4;
+
+ if (dev->data->dev_conf.nb_events_limit > 0 &&
+ threshold > dev->data->dev_conf.nb_events_limit)
+ threshold = dev->data->dev_conf.nb_events_limit;
+
*port_conf = (struct rte_event_port_conf) {
- .new_event_threshold = 1024,
+ .new_event_threshold = threshold,
.dequeue_depth = SLB_MAX_PORT_DEQUEUE_DEPTH / 4,
.enqueue_depth = SLB_MAX_PORT_ENQUEUE_DEPTH / 4
};
@@ -146,7 +153,9 @@ slb_queue_release(struct rte_eventdev *dev, uint8_t queue_id)
}
}
-/* Setup Eventdev queue. Eventdev queues are implemented as DPDK rings */
+/* Setup Eventdev queue. Eventdev queues are implemented as DPDK rings.
+ * SLB Supports single-link, atomic, parallel, and ordered queues.
+ */
static int
slb_queue_setup(struct rte_eventdev *dev, uint8_t queue_id,
const struct rte_event_queue_conf *conf)
@@ -190,12 +199,15 @@ slb_queue_setup(struct rte_eventdev *dev, uint8_t queue_id,
return -ENOMEM;
queue->q_ring = ring;
- queue->schedule_type = conf->schedule_type;
+ /* Single-link queue uses atomic schedule type */
+ queue->schedule_type = queue->is_single_link ?
+ RTE_SCHED_TYPE_ATOMIC : conf->schedule_type;
queue->serving_ports_mask = 0;
queue->num_serving_ports = 0;
- /* Atomic queue allocation */
- if (conf->schedule_type == RTE_SCHED_TYPE_ATOMIC) {
+ /* Atomic queue state allocation */
+ if (!queue->is_single_link &&
+ conf->schedule_type == RTE_SCHED_TYPE_ATOMIC) {
for (int i = 0; i < SLB_MAX_PORTS; i++)
queue->per_port_rings[i] = NULL;
@@ -224,7 +236,8 @@ slb_queue_setup(struct rte_eventdev *dev, uint8_t queue_id,
}
/* Ordered queue reorder buffer allocation */
- if (conf->schedule_type == RTE_SCHED_TYPE_ORDERED) {
+ if (!queue->is_single_link &&
+ conf->schedule_type == RTE_SCHED_TYPE_ORDERED) {
queue->reorder_buffer = rte_zmalloc_socket("slb_reorder_buf",
sizeof(struct slb_reorder_entry) * ring->r.size,
RTE_CACHE_LINE_SIZE, dev->data->socket_id);
@@ -293,7 +306,8 @@ slb_port_link_one(struct slb_port *port, struct slb_queue *queue,
port->single_linked_q = queue;
port->single_linked_ring = queue->q_ring;
} else {
- if (queue->schedule_type == RTE_SCHED_TYPE_ATOMIC &&
+ if (!queue->is_single_link &&
+ queue->schedule_type == RTE_SCHED_TYPE_ATOMIC &&
queue->per_port_rings[port->id] == NULL) {
char ring_name[RTE_RING_NAMESIZE];
struct rte_event_ring *ring;
@@ -332,7 +346,8 @@ slb_port_link_one(struct slb_port *port, struct slb_queue *queue,
if (!found) {
uint16_t slot = port->num_q[prio];
struct rte_event_ring *dq_ring =
- (queue->schedule_type == RTE_SCHED_TYPE_ATOMIC) ?
+ (!queue->is_single_link &&
+ queue->schedule_type == RTE_SCHED_TYPE_ATOMIC) ?
queue->per_port_rings[port->id] : queue->q_ring;
if (slot >= SLB_PORT_MAX_Q_MAP_PER_PRIO) {
@@ -344,6 +359,8 @@ slb_port_link_one(struct slb_port *port, struct slb_queue *queue,
port->q_entries[prio][slot].queue_id = qid;
port->q_entries[prio][slot].schedule_type =
queue->schedule_type;
+ port->q_entries[prio][slot].is_single_link =
+ queue->is_single_link;
port->num_q[prio]++;
}
@@ -464,7 +481,6 @@ slb_info_get(struct rte_eventdev *dev __rte_unused,
RTE_EVENT_DEV_CAP_IMPLICIT_RELEASE_DISABLE |
RTE_EVENT_DEV_CAP_NONSEQ_MODE |
RTE_EVENT_DEV_CAP_MULTIPLE_QUEUE_PORT |
- RTE_EVENT_DEV_CAP_RUNTIME_PORT_LINK |
RTE_EVENT_DEV_CAP_CARRY_FLOW_ID |
RTE_EVENT_DEV_CAP_MAINTENANCE_FREE |
RTE_EVENT_DEV_CAP_INDEPENDENT_ENQ
@@ -555,22 +571,52 @@ slb_stop(struct rte_eventdev *dev)
for (uint8_t qid = 0; qid < slb->num_queues; qid++) {
struct slb_queue *q = &slb->queues[qid];
- if (q->schedule_type == RTE_SCHED_TYPE_ATOMIC && q->atomic_state != NULL) {
+ if (q->schedule_type == RTE_SCHED_TYPE_ATOMIC &&
+ q->atomic_state != NULL) {
+ struct slb_atomic_state *astate = q->atomic_state;
+
+ for (uint16_t h = 0; h < astate->hold_count; h++) {
+ if (flush != NULL)
+ flush(dev_id, astate->hold_buffer[h],
+ flush_arg);
+ }
+ astate->hold_count = 0;
+ astate->next_port_rr = 0;
+ astate->migration.in_progress = false;
+
for (int f = 0; f < SLB_ATOMIC_FLOWS; f++) {
rte_atomic_store_explicit(
- &q->atomic_state->flow_map.flows[f].port_id,
+ &astate->flow_map.flows[f].port_id,
-1, rte_memory_order_relaxed);
- q->atomic_state->flow_last_migrated[f] = 0;
+ astate->flow_last_migrated[f] = 0;
}
- q->atomic_state->migration.in_progress = false;
+
+ memset(astate->port_stats, 0,
+ sizeof(astate->port_stats));
for (uint16_t pid = 0; pid < slb->num_ports; pid++) {
- q->atomic_state->port_stats[pid].load_counter = 0;
if (q->per_port_rings[pid] != NULL)
slb_drain_ring(dev_id,
q->per_port_rings[pid],
flush, flush_arg);
}
+ } else if (q->schedule_type == RTE_SCHED_TYPE_ORDERED &&
+ q->reorder_buffer != NULL && q->q_ring != NULL) {
+ for (uint32_t s = 0; s < q->q_ring->r.size; s++) {
+ uint8_t st = rte_atomic_load_explicit(
+ &q->reorder_buffer[s].state,
+ rte_memory_order_relaxed);
+
+ if (st == SLB_REORDER_READY && flush != NULL)
+ flush(dev_id,
+ q->reorder_buffer[s].event,
+ flush_arg);
+ rte_atomic_store_explicit(
+ &q->reorder_buffer[s].state,
+ SLB_REORDER_EMPTY,
+ rte_memory_order_relaxed);
+ }
+ q->reorder_drain_idx = 0;
}
if (q->q_ring != NULL)
@@ -581,7 +627,10 @@ slb_stop(struct rte_eventdev *dev)
struct slb_port *port = &slb->ports[i];
port->inflight_credits = 0;
port->credits_drained = false;
+ port->pending_releases = 0;
port->is_loaded = false;
+ port->last_migrated_time = 0;
+ slb_port_reset_history(port);
for (int p = 0; p < SLB_MAX_PRIORITIES; p++)
port->next_q[p] = 0;
}
diff --git a/drivers/event/slb/slb_evdev.h b/drivers/event/slb/slb_evdev.h
index f727a1b83c..bf262903cd 100644
--- a/drivers/event/slb/slb_evdev.h
+++ b/drivers/event/slb/slb_evdev.h
@@ -28,7 +28,7 @@
#define SLB_MAX_FLOWS_MASK (SLB_MAX_FLOWS - 1)
/* Avoid making small 'loans' from the central in-flight event credit pool */
-#define SLB_MIN_CREDIT_LOAN (512)
+#define SLB_MIN_CREDIT_LOAN (256)
#define SLB_PORT_MAX_CREDITS (2 * SLB_MIN_CREDIT_LOAN)
#define SLB_PORT_MIN_CREDITS (SLB_MIN_CREDIT_LOAN)
@@ -56,7 +56,8 @@ struct slb_port_q_entry {
struct slb_queue *queue;
uint8_t queue_id;
uint8_t schedule_type;
- uint8_t pad[6];
+ bool is_single_link;
+ uint8_t pad[5];
};
#define SLB_PORT_HISTORY_SIZE 256
diff --git a/drivers/event/slb/slb_event.c b/drivers/event/slb/slb_event.c
index 3a0f7f6fde..c44deba905 100644
--- a/drivers/event/slb/slb_event.c
+++ b/drivers/event/slb/slb_event.c
@@ -976,8 +976,10 @@ slb_port_dequeue(struct slb_port *port, struct rte_event events[],
return 0;
dequeued = rte_event_ring_dequeue_burst(port->single_linked_ring,
events, num, NULL);
- for (uint16_t j = 0; j < dequeued; j++)
+ for (uint16_t j = 0; j < dequeued; j++) {
+ events[j].sched_type = RTE_SCHED_TYPE_ATOMIC;
events[j].impl_opaque = 0;
+ }
return dequeued;
}
@@ -1015,8 +1017,11 @@ slb_port_dequeue(struct slb_port *port, struct rte_event events[],
continue;
uint8_t sched_type = qent->schedule_type;
- bool is_ordered = (sched_type == RTE_SCHED_TYPE_ORDERED);
- bool is_atomic = (sched_type == RTE_SCHED_TYPE_ATOMIC);
+ bool is_single_link = qent->is_single_link;
+ bool is_ordered = !is_single_link &&
+ (sched_type == RTE_SCHED_TYPE_ORDERED);
+ bool is_atomic = !is_single_link &&
+ (sched_type == RTE_SCHED_TYPE_ATOMIC);
if (is_ordered || is_atomic) {
if (unlikely(port->history_avail == 0))
@@ -1050,8 +1055,16 @@ slb_port_dequeue(struct slb_port *port, struct rte_event events[],
} else {
dequeued = rte_event_ring_dequeue_burst(
ring_to_dq, events, num, NULL);
- for (uint16_t j = 0; j < dequeued; j++)
- events[j].impl_opaque = 0;
+ if (is_single_link) {
+ for (uint16_t j = 0; j < dequeued; j++) {
+ events[j].sched_type =
+ RTE_SCHED_TYPE_ATOMIC;
+ events[j].impl_opaque = 0;
+ }
+ } else {
+ for (uint16_t j = 0; j < dequeued; j++)
+ events[j].impl_opaque = 0;
+ }
}
if (dequeued > 0) {
diff --git a/drivers/event/slb/slb_selftest.c b/drivers/event/slb/slb_selftest.c
index 4a072b811b..776b6d6ab4 100644
--- a/drivers/event/slb/slb_selftest.c
+++ b/drivers/event/slb/slb_selftest.c
@@ -362,6 +362,12 @@ test_ordered_forward(void)
cons_rx, rx[i].u64);
return -1;
}
+ if (rx[i].sched_type != RTE_SCHED_TYPE_ATOMIC) {
+ SLB_LOG_LINE(ERR,
+ "Single-link dequeue sched_type expected %u, got %u",
+ RTE_SCHED_TYPE_ATOMIC, rx[i].sched_type);
+ return -1;
+ }
cons_rx++;
rx[i].op = RTE_EVENT_OP_RELEASE;
}
@@ -416,6 +422,12 @@ test_single_link(void)
for (i = 0; i < 16; i++) {
if (rx[i].u64 != (uint64_t)(5000 + i))
return -1;
+ if (rx[i].sched_type != RTE_SCHED_TYPE_ATOMIC) {
+ SLB_LOG_LINE(ERR,
+ "Single-link dequeue sched_type expected %u, got %u",
+ RTE_SCHED_TYPE_ATOMIC, rx[i].sched_type);
+ return -1;
+ }
rx[i].op = RTE_EVENT_OP_RELEASE;
}
rte_event_enqueue_burst(g_dev_id, PORT_CONS, rx, 16);
--
2.53.0
next prev parent reply other threads:[~2026-11-07 1:31 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-07 1:30 [PATCH v1 0/8] event/slb: introducing software load balancer eventdev PMD Pravin Pathak
2026-11-07 1:30 ` [PATCH v1 1/8] event/slb: introduce software load balancer PMD Pravin Pathak
2026-11-07 1:30 ` [PATCH v1 2/8] event/slb: add support for ordered queues Pravin Pathak
2026-11-07 1:30 ` [PATCH v1 3/8] event/slb: add support for atomic queues Pravin Pathak
2026-11-07 1:30 ` [PATCH v1 4/8] event/slb: add dynamic flow migration " Pravin Pathak
2026-11-07 1:30 ` [PATCH v1 5/8] event/slb: add extended statistics and diagnostics Pravin Pathak
2026-11-07 1:30 ` [PATCH v1 6/8] event/slb: add self-test and documentation Pravin Pathak
2026-11-07 1:30 ` Pravin Pathak [this message]
2026-11-07 1:30 ` [PATCH v1 8/8] event/slb: improve port linking, config checks and atomic refill Pravin Pathak
2026-11-07 7:29 ` [PATCH v1 0/8] event/slb: introducing software load balancer eventdev PMD Jerin Jacob
2026-11-08 17:10 ` Stephen Hemminger
2026-11-09 2:30 ` Pravin Pathak
2026-11-09 12:55 ` Jerin Jacob
2026-11-11 14:22 ` Sarkar, Tirthendu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261107013011.2443138-8-pravinpathakdev@gmail.com \
--to=pravinpathakdev@gmail.com \
--cc=bruce.richardson@intel.com \
--cc=chenbox@nvidia.com \
--cc=david.marchand@redhat.com \
--cc=dev@dpdk.org \
--cc=jerinj@marvell.com \
--cc=mike.ximing.chen@intel.com \
--cc=nipun.gupta@amd.com \
--cc=pravin.pathak.dev@gmail.com \
--cc=thomas@monjalon.net \
--cc=tirthendu.sarkar@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.