From: Robert Sanford <[email protected]> RIB nodes are allocated from a mempool created with no flags, so each object is cache-line aligned and padded for memory-channel spreading. On x86-64, an object takes 192 bytes for a 40-byte rte_rib_node or a 56-byte rte_rib6_node. Nodes are small and only accessed by the CPU, so the padding is wasted. The whole pool is reserved up front, and rte_fib and rte_fib6 size it at twice max_routes nodes.
Create the node pools with RTE_MEMPOOL_F_NO_CACHE_ALIGN, RTE_MEMPOOL_F_NO_SPREAD and RTE_MEMPOOL_F_NO_IOVA_CONTIG. RTE_MEMPOOL_F_NO_SPREAD is implied by RTE_MEMPOOL_F_NO_CACHE_ALIGN, but is passed explicitly to document the intent. Nodes remain 8-byte aligned, which is all the node structures need. The extension area returned by rte_rib_get_ext() and rte_rib6_get_ext() was only 8-byte aligned before as well. With 2M nodes (1M routes), the pool shrinks from 390 MiB to 128 MiB for IPv4 and to 160 MiB for IPv6. On an AMD EPYC 7643 with 1 GiB hugepages, fib_perf_autotest (about 1M IPv4 routes) shows average add and delete times 13 and 29 percent lower. Lookup times, and the add and delete times in fib6_perf_autotest, which uses 1000 routes, are unchanged. Signed-off-by: Robert Sanford <[email protected]> --- lib/rib/rte_rib.c | 10 +++++++++- lib/rib/rte_rib6.c | 10 +++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/lib/rib/rte_rib.c b/lib/rib/rte_rib.c index 046db131ca..2ba46393ed 100644 --- a/lib/rib/rte_rib.c +++ b/lib/rib/rte_rib.c @@ -425,9 +425,17 @@ rte_rib_create(const char *name, int socket_id, const struct rte_rib_conf *conf) } snprintf(mem_name, sizeof(mem_name), "MP_%s", name); + /* + * Nodes are small, CPU-only objects: skip cache-line alignment and + * memory-channel spreading, which otherwise grow each object well + * beyond sizeof(struct rte_rib_node), and IOVA contiguity, which + * only matters for device access. + */ node_pool = rte_mempool_create(mem_name, conf->max_nodes, sizeof(struct rte_rib_node) + conf->ext_sz, 0, 0, - NULL, NULL, NULL, NULL, socket_id, 0); + NULL, NULL, NULL, NULL, socket_id, + RTE_MEMPOOL_F_NO_SPREAD | RTE_MEMPOOL_F_NO_CACHE_ALIGN | + RTE_MEMPOOL_F_NO_IOVA_CONTIG); if (node_pool == NULL) { RIB_LOG(ERR, diff --git a/lib/rib/rte_rib6.c b/lib/rib/rte_rib6.c index 918ddbdfd3..808aac79ce 100644 --- a/lib/rib/rte_rib6.c +++ b/lib/rib/rte_rib6.c @@ -488,9 +488,17 @@ rte_rib6_create(const char *name, int socket_id, } snprintf(mem_name, sizeof(mem_name), "MP_%s", name); + /* + * Nodes are small, CPU-only objects: skip cache-line alignment and + * memory-channel spreading, which otherwise grow each object well + * beyond sizeof(struct rte_rib6_node), and IOVA contiguity, which + * only matters for device access. + */ node_pool = rte_mempool_create(mem_name, conf->max_nodes, sizeof(struct rte_rib6_node) + conf->ext_sz, 0, 0, - NULL, NULL, NULL, NULL, socket_id, 0); + NULL, NULL, NULL, NULL, socket_id, + RTE_MEMPOOL_F_NO_SPREAD | RTE_MEMPOOL_F_NO_CACHE_ALIGN | + RTE_MEMPOOL_F_NO_IOVA_CONTIG); if (node_pool == NULL) { RIB_LOG(ERR, -- 2.34.1

