[PATCH v3 16/16] test/pmd_ring: test per-queue xstats
Stephen Hemminger
stephen at networkplumber.org
Thu Aug 13 19:55:15 CEST 2026
Add a test that per-queue xstats are reported for every configured
queue, and only for those. Uses different Rx and Tx queue counts so
that each direction is checked independently.
Signed-off-by: Stephen Hemminger <stephen at networkplumber.org>
---
app/test/test_pmd_ring.c | 145 +++++++++++++++++++++++++++++++++++++++
1 file changed, 145 insertions(+)
diff --git a/app/test/test_pmd_ring.c b/app/test/test_pmd_ring.c
index cb08dcf1d9..e7682906df 100644
--- a/app/test/test_pmd_ring.c
+++ b/app/test/test_pmd_ring.c
@@ -4,7 +4,10 @@
#include "test.h"
#include <string.h>
+#include <inttypes.h>
+#include <stdbool.h>
#include <stdio.h>
+#include <stdlib.h>
#include <rte_eth_ring.h>
#include <rte_ethdev.h>
@@ -557,6 +560,147 @@ test_ethdev_configure_ports(void)
return TEST_SUCCESS;
}
+/*
+ * Per-queue xstats are added by ethdev for all configured queues.
+ * Use a port with different Rx and Tx queue counts to check that each
+ * direction is reported independently.
+ */
+#define QSTATS_NB_RXQ 3
+#define QSTATS_NB_TXQ 5
+#define QSTATS_NB_RINGS RTE_MAX(QSTATS_NB_RXQ, QSTATS_NB_TXQ)
+
+static int
+test_queue_xstats(void)
+{
+ struct rte_ring *qrings[QSTATS_NB_RINGS] = { };
+ struct rte_eth_xstat_name *names = NULL;
+ struct rte_eth_xstat *xstats = NULL;
+ struct rte_eth_conf null_conf;
+ unsigned int i, nb_names, found;
+ char expected[RTE_ETH_XSTATS_NAME_SIZE];
+ int port = -1, nb_xstats, ret = -1;
+ uint16_t q;
+
+ for (q = 0; q < QSTATS_NB_RINGS; q++) {
+ char name[RTE_RING_NAMESIZE];
+
+ snprintf(name, sizeof(name), "RQ%u", q);
+ qrings[q] = rte_ring_create(name, RING_SIZE, SOCKET0,
+ RING_F_SP_ENQ | RING_F_SC_DEQ);
+ if (qrings[q] == NULL) {
+ printf("rte_ring_create %s failed\n", name);
+ goto out;
+ }
+ }
+
+ port = rte_eth_from_rings("net_ringq", qrings, QSTATS_NB_RXQ,
+ qrings, QSTATS_NB_TXQ, SOCKET0);
+ if (port < 0) {
+ printf("failed to create port\n");
+ goto out;
+ }
+
+ memset(&null_conf, 0, sizeof(null_conf));
+ if (rte_eth_dev_configure(port, QSTATS_NB_RXQ, QSTATS_NB_TXQ,
+ &null_conf) < 0) {
+ printf("configure failed\n");
+ goto out;
+ }
+
+ for (q = 0; q < QSTATS_NB_RXQ; q++) {
+ if (rte_eth_rx_queue_setup(port, q, RING_SIZE, SOCKET0,
+ NULL, mp) < 0) {
+ printf("Rx queue %u setup failed\n", q);
+ goto out;
+ }
+ }
+ for (q = 0; q < QSTATS_NB_TXQ; q++) {
+ if (rte_eth_tx_queue_setup(port, q, RING_SIZE, SOCKET0,
+ NULL) < 0) {
+ printf("Tx queue %u setup failed\n", q);
+ goto out;
+ }
+ }
+
+ nb_xstats = rte_eth_xstats_get_names(port, NULL, 0);
+ if (nb_xstats <= 0) {
+ printf("no xstats reported\n");
+ goto out;
+ }
+
+ names = calloc(nb_xstats, sizeof(*names));
+ xstats = calloc(nb_xstats, sizeof(*xstats));
+ if (names == NULL || xstats == NULL) {
+ printf("out of memory\n");
+ goto out;
+ }
+
+ nb_names = rte_eth_xstats_get_names(port, names, nb_xstats);
+ if (nb_names != (unsigned int)nb_xstats) {
+ printf("got %u names, expected %d\n", nb_names, nb_xstats);
+ goto out;
+ }
+
+ if (rte_eth_xstats_get(port, xstats, nb_xstats) != nb_xstats) {
+ printf("xstats count does not match names count\n");
+ goto out;
+ }
+
+ /* No traffic has passed, so every counter must still be zero. */
+ for (i = 0; i < (unsigned int)nb_xstats; i++) {
+ if (xstats[i].value != 0) {
+ printf("xstat '%s' is %"PRIu64", expected 0\n",
+ names[xstats[i].id].name, xstats[i].value);
+ goto out;
+ }
+ }
+
+ /* Every configured queue must have its counters, in both directions. */
+ for (q = 0; q < QSTATS_NB_RXQ + QSTATS_NB_TXQ; q++) {
+ bool rx = q < QSTATS_NB_RXQ;
+
+ snprintf(expected, sizeof(expected), "%s_q%u_packets",
+ rx ? "rx" : "tx", rx ? q : q - QSTATS_NB_RXQ);
+
+ for (i = 0, found = 0; i < nb_names; i++)
+ if (strcmp(names[i].name, expected) == 0)
+ found++;
+
+ if (found != 1) {
+ printf("expected one '%s', got %u\n", expected, found);
+ goto out;
+ }
+ }
+
+ /* Queues beyond the configured count must not be reported. */
+ snprintf(expected, sizeof(expected), "rx_q%u_packets", QSTATS_NB_RXQ);
+ for (i = 0; i < nb_names; i++) {
+ if (strcmp(names[i].name, expected) == 0) {
+ printf("unexpected stat '%s'\n", expected);
+ goto out;
+ }
+ }
+
+ snprintf(expected, sizeof(expected), "tx_q%u_packets", QSTATS_NB_TXQ);
+ for (i = 0; i < nb_names; i++) {
+ if (strcmp(names[i].name, expected) == 0) {
+ printf("unexpected stat '%s'\n", expected);
+ goto out;
+ }
+ }
+
+ ret = TEST_SUCCESS;
+out:
+ free(names);
+ free(xstats);
+ if (port >= 0)
+ rte_eth_dev_close(port);
+ for (q = 0; q < QSTATS_NB_RINGS; q++)
+ rte_ring_free(qrings[q]);
+
+ return ret;
+}
+
static int
test_get_stats_for_port(void)
{
@@ -581,6 +725,7 @@ unit_test_suite test_pmd_ring_suite = {
TEST_CASE(test_send_basic_packets),
TEST_CASE(test_get_stats_for_port),
TEST_CASE(test_stats_reset_for_port),
+ TEST_CASE(test_queue_xstats),
TEST_CASE(test_pmd_ring_pair_create_attach),
TEST_CASE(test_command_line_ring_port),
TEST_CASES_END()
--
2.53.0
More information about the dev
mailing list