|SUCCESS| [v5,v5,3/3] doc: add new section topology

dpdklab at iol.unh.edu dpdklab at iol.unh.edu
Thu Apr 16 01:22:54 CEST 2026


Test-Label: ai-code-review
Test-Status: SUCCESS
https://dpdk.org/patch/163066

_AI Code Review_

=== Patch Review: series.patch (via Claude) ===
Review date: 2026-04-15

# DPDK Patch Review

commit SHA: 20260414193850.1696-2-vipin.varghese at amd.com (patch 1/3)
commit SHA: 20260414193850.1696-3-vipin.varghese at amd.com (patch 2/3)
commit SHA: 20260414193850.1696-4-vipin.varghese at amd.com (patch 3/3)

Author: Vipin Varghese <vipin.varghese at amd.com>

Subject: [PATCH v5 v5 1/3] eal/topology: add Topology grouping for lcores

This series introduces NUMA topology awareness for DPDK logical cores
with support for domain partitioning based on CPU and I/O topology.

---

## Patch 1/3: eal/topology

> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2026 AMD Corporation
> + */

Does this file need the Intel copyright from the header template comment
indicating it was based on rte_lcore.h?

> +#include <inttypes.h>
> +#include <stdlib.h>
> +#include <string.h>
> +
> +#include <rte_topology.h>
> +#include <rte_malloc.h>

Whitespace: Are these includes meant to have a blank line between system
and DPDK headers?

> +static inline bool is_valid_single_domain(unsigned int domainbits)
> +{
> +	if ((domainbits == 0) || (domainbits & ~RTE_TOPO_DOMAIN_ALL))
> +		return false;
> +
> +	return (__builtin_popcount(domainbits) == 1);
> +}

Coding style: Are the extra parentheses around the conditions needed?
The coding standard discourages unnecessary parentheses in conditionals.

> +static unsigned int
> +get_domain_count(unsigned int domain_sel)
> +{
> +	if (is_valid_single_domain(domain_sel) == false)
> +		return 0;

Coding style: Should this use "!is_valid_single_domain()" rather than
comparing to false explicitly?

> +	unsigned int domain_cnt =
> +		(domain_sel & RTE_TOPO_DOMAIN_NUMA) ? topo_cnfg.numa_count :
> +		(domain_sel & RTE_TOPO_DOMAIN_L4) ? topo_cnfg.l4_count :
> +		(domain_sel & RTE_TOPO_DOMAIN_L3) ? topo_cnfg.l3_count :
> +		(domain_sel & RTE_TOPO_DOMAIN_L2) ? topo_cnfg.l2_count :
> +		(domain_sel & RTE_TOPO_DOMAIN_L1) ? topo_cnfg.l1_count : 0;

Does this chained ternary need more clarity? Would a switch statement or
helper function improve maintainability?

> +	return ptr->cores[pos];
> +}
> +#endif

Can the #ifdef blocks cause issues if RTE_LIBHWLOC_PROBE is undefined?
Are all the functions properly stubbed?

> +	RTE_SET_USED(domain_sel);
> +	RTE_SET_USED(lcore);
> +	return -3;

Does returning -3 here have a specific meaning that should be documented?

> +	return ((domain_sel & RTE_TOPO_DOMAIN_NUMA) ? topo_cnfg.lcore_map[lcore].numa_domain :
> +		(domain_sel & RTE_TOPO_DOMAIN_L4) ? topo_cnfg.lcore_map[lcore].l4_domain :
> +		(domain_sel & RTE_TOPO_DOMAIN_L3) ? topo_cnfg.lcore_map[lcore].l3_domain :
> +		(domain_sel & RTE_TOPO_DOMAIN_L2) ? topo_cnfg.lcore_map[lcore].l2_domain :
> +		(domain_sel & RTE_TOPO_DOMAIN_L1) ? topo_cnfg.lcore_map[lcore].l1_domain : -3);

Long line: Does this line exceed 79 characters? Should it be wrapped?

> +RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_topo_get_lcore_count_from_domain, 26.07)
> +unsigned int
> +rte_topo_get_lcore_count_from_domain(unsigned int domain_sel __rte_unused,
> +unsigned int domain_indx __rte_unused)

Whitespace: Is the indentation of the second parameter line correct?

> +			for (unsigned int i = 0; i < ptr->core_count; i++) {
> +				uint16_t lcore = ptr->cores[i];
> +
> +				EAL_LOG(DEBUG, "Found lcore (%u) in domain (%d) at pos %u",
> +					lcore, domain_index, i);

Format string: Should domain_index be %u since it's unsigned int, not %d?

> +				return lcore;
> +			}
> +		}
> +
> +		return RTE_MAX_LCORE;

Does this code path always ensure a valid return or could undefined
behavior occur?

> +	while (1) {

Coding style: Should this be "for (;;)" per DPDK conventions?

> +		/* check if the domain has cores_to_skip */
> +		uint16_t new_lcore = ptr->cores[new_lcore_pos];

Comment mismatch: The comment mentions cores_to_skip but the code
doesn't check for that. Is this comment accurate?

> +	fprintf(f, "| %15s | %15s | %15s | %15s |\n",
> +		"Domain-Name", "Domains", "Domains-with-lcore", "Domain-total-lcore");

Long line: Does this fprintf statement exceed the line length limit?

> +			(domain_types[d] == RTE_TOPO_DOMAIN_NUMA) ? "NUMA" :
> +			(domain_types[d] == RTE_TOPO_DOMAIN_L4) ? "L4" :
> +			(domain_types[d] == RTE_TOPO_DOMAIN_L3) ? "L3" :
> +			(domain_types[d] == RTE_TOPO_DOMAIN_L2) ? "L2" :
> +			(domain_types[d] == RTE_TOPO_DOMAIN_L1) ? "L1" : NULL,

Does this pattern repeat in multiple places? Would a helper function
reduce duplication?

> +	for (uint16_t j = 0; j < *layer_cnt; j++) {

Variable naming: Is the use of single-letter variables like 'j' clear
enough, or should more descriptive names be used?

> +		struct core_domain_mapping *dm =
> +			rte_zmalloc(NULL, sizeof(struct core_domain_mapping), 0);
> +		if (!dm)
> +			return -1;

Resource leak: If this allocation fails, are the previously allocated
dm entries from earlier loop iterations freed?

> +		dm->cores = rte_malloc(NULL, sizeof(uint16_t) * cpu_count, 0);
> +		if (!dm->cores)
> +			return -1;

Resource leak: If dm->cores allocation fails, is the dm struct freed?

> +				int cpu_core = lcore_to_core(cpu_id);
> +				if (cpu_core == -1)
> +					return -1;

Error handling: Does returning -1 here leak the allocated topology
structures?

> +					struct core_domain_mapping *dm = (*layer_ptr)[k];
> +					if (dm == NULL)
> +						return -2;

Return code: Is the distinction between -1 and -2 documented anywhere?

> +	if (hwloc_topology_init(&topo_cnfg.topology) < 0)
> +		return -1;
> +
> +	if (hwloc_topology_load(topo_cnfg.topology) < 0) {
> +		hwloc_topology_destroy(topo_cnfg.topology);
> +		return -2;

Error path: Should this call rte_eal_topology_release() to ensure
complete cleanup?

> +	for (int i = 0; i < 5; i++) {

Magic number: Should 5 be replaced with RTE_DIM(layers) or similar?

> +		*layers[i].count = hwloc_get_nbobjs_by_depth(topo_cnfg.topology, layers[i].depth);
> +		if (eal_topology_map_layer(topo_cnfg.topology, layers[i].depth, layers[i].count,
> +			layers[i].ptr, layers[i].total_cores, layers[i].name) < 0) {

Long line: Does this exceed 79 characters?

> +	hwloc_topology_destroy(topo_cnfg.topology);
> +	topo_cnfg.topology = NULL;

Memory ordering: Is setting to NULL after destroy necessary? Does the
destroy function leave a dangling pointer?

> +static void
> +release_domain(struct domain_store *d)
> +{
> +	if (!d->map) {
> +		d->count = 0;
> +		d->core_count = 0;
> +		return;
> +	}

Does this function need to handle partially initialized domains?

> +	for (int i = 0; i < d->count; i++) {
> +		if (!d->map[i])
> +			continue;
> +		rte_free(d->map[i]->cores);
> +		d->map[i]->cores = NULL;
> +		rte_free(d->map[i]);
> +		d->map[i] = NULL;
> +	}

Double free: Can d->map[i]->cores be NULL when d->map[i] is non-NULL?
Does the code handle that case?

---

## Patch 2/3: app test cases

> +#ifdef RTE_LIBHWLOC_PROBE
> +#include <rte_topology.h>
> +#endif

Whitespace: Should there be a blank line before the system includes and
this section?

> +	unsigned int id1 = RTE_MAX_LCORE, id2 = RTE_MAX_LCORE;
> +	unsigned int domain = 0;

Initialization: Is initializing domain to 0 necessary since it's
immediately reassigned in the loop?

> +		id1 = rte_topo_get_nth_lcore_from_domain(domain, 0, 0, RTE_TOPO_DOMAIN_L1);
> +		id2 = rte_topo_get_nth_lcore_from_domain(domain, 0, 0, RTE_TOPO_DOMAIN_L1);

Copy-paste error: Are both calls using position 0 intentional? Should
the second use position 1?

> +static int
> +get_same_l2_domains(struct lcore_pair *lcp)
> +{	if (rte_topo_get_domain_count(RTE_TOPO_DOMAIN_L2) == 0)

Whitespace: Should there be a newline after the opening brace?

> +	if (rte_lcore_count() > 2) {

Comment: Would it be helpful to document why more than 2 cores are
needed for these tests?

---

## Patch 3/3: Documentation

> +  [topology](@ref rte_topology.h),

Alphabetical order: Is the list of headers alphabetically sorted? Should
topology come after lcore?

> +    topology_lib
> +
> +
> +-How to Guides
> +-------------

Whitespace: Should there be only one blank line before the section?

> +- ``hwloc-dev`` tested on `2.10.0`

Version requirement: Should there be a minimum version documented if
2.10.0 is only tested, not required?

> +.. code-block:: c
> +
> +   uint32_t
> +   rte_topo_get_domain_count(enum rte_topo_domain_sel domain_sel);

Return type: Does the actual API return unsigned int but the doc shows
uint32_t?


More information about the test-report mailing list