changes:
 - rework stack and ring with domain lcores
 - add new test cases for topology API

ring_test inspired from [email protected]

Suggested-by: Sivaprasad Tummala <[email protected]>
Signed-off-by: Vipin Varghese <[email protected]>
---
 app/test/meson.build       |   1 +
 app/test/test_ring_perf.c  | 416 ++++++++++++++++++++++-
 app/test/test_stack_perf.c | 409 ++++++++++++++++++++++
 app/test/test_topology.c   | 676 +++++++++++++++++++++++++++++++++++++
 4 files changed, 1499 insertions(+), 3 deletions(-)
 create mode 100644 app/test/test_topology.c

diff --git a/app/test/meson.build b/app/test/meson.build
index 7d458f9c07..f584ea66c1 100644
--- a/app/test/meson.build
+++ b/app/test/meson.build
@@ -207,6 +207,7 @@ source_file_deps = {
     'test_timer_perf.c': ['timer'],
     'test_timer_racecond.c': ['timer'],
     'test_timer_secondary.c': ['timer'],
+    'test_topology.c': [],
     'test_trace.c': [],
     'test_trace_perf.c': [],
     'test_trace_register.c': [],
diff --git a/app/test/test_ring_perf.c b/app/test/test_ring_perf.c
index 9a2a481458..1f0fd8a0fa 100644
--- a/app/test/test_ring_perf.c
+++ b/app/test/test_ring_perf.c
@@ -10,6 +10,9 @@
 #include <rte_cycles.h>
 #include <rte_launch.h>
 #include <rte_pause.h>
+#ifdef RTE_LIBHWLOC_PROBE
+#include <rte_topology.h>
+#endif
 #include <string.h>
 
 #include "test.h"
@@ -74,7 +77,7 @@ test_ring_print_test_string(unsigned int api_type, int esize,
 static int
 get_two_hyperthreads(struct lcore_pair *lcp)
 {
-       unsigned id1, id2;
+       unsigned int id1, id2;
        unsigned c1, c2, s1, s2;
        RTE_LCORE_FOREACH(id1) {
                /* inner loop just re-reads all id's. We could skip the first 
few
@@ -101,7 +104,7 @@ get_two_hyperthreads(struct lcore_pair *lcp)
 static int
 get_two_cores(struct lcore_pair *lcp)
 {
-       unsigned id1, id2;
+       unsigned int id1, id2;
        unsigned c1, c2, s1, s2;
        RTE_LCORE_FOREACH(id1) {
                RTE_LCORE_FOREACH(id2) {
@@ -125,7 +128,7 @@ get_two_cores(struct lcore_pair *lcp)
 static int
 get_two_sockets(struct lcore_pair *lcp)
 {
-       unsigned id1, id2;
+       unsigned int id1, id2;
        unsigned s1, s2;
        RTE_LCORE_FOREACH(id1) {
                RTE_LCORE_FOREACH(id2) {
@@ -143,6 +146,359 @@ get_two_sockets(struct lcore_pair *lcp)
        return 1;
 }
 
+#ifdef RTE_LIBHWLOC_PROBE
+static int
+get_same_numa_domains(struct lcore_pair *lcp)
+{
+       if (rte_topo_get_domain_count(RTE_TOPO_DOMAIN_NUMA) == 0)
+               return 1;
+
+       unsigned int id1 = RTE_MAX_LCORE, id2 = RTE_MAX_LCORE;
+       unsigned int domain = 0;
+
+       RTE_TOPO_FOREACH_DOMAIN(domain, RTE_TOPO_DOMAIN_NUMA) {
+               if ((id1 != RTE_MAX_LCORE) && (id2 != RTE_MAX_LCORE))
+                       break;
+
+               if (rte_topo_get_lcore_count_from_domain(RTE_TOPO_DOMAIN_NUMA, 
domain) < 2)
+                       continue;
+
+               id1 = rte_topo_get_nth_lcore_from_domain(domain, 0, 0, 
RTE_TOPO_DOMAIN_NUMA);
+               id2 = rte_topo_get_nth_lcore_from_domain(domain, 1, 0, 
RTE_TOPO_DOMAIN_NUMA);
+       }
+
+       if ((id1 == RTE_MAX_LCORE) || (id2 == RTE_MAX_LCORE))
+               return 2;
+
+       if (id1 == id2)
+               return 3;
+
+       lcp->c1 = id1;
+       lcp->c2 = id2;
+
+       return 0;
+}
+
+static int
+get_same_l4_domains(struct lcore_pair *lcp)
+{
+       if (rte_topo_get_domain_count(RTE_TOPO_DOMAIN_L4) == 0)
+               return 1;
+
+       unsigned int id1 = RTE_MAX_LCORE, id2 = RTE_MAX_LCORE;
+       unsigned int domain = 0;
+
+       RTE_TOPO_FOREACH_DOMAIN(domain, RTE_TOPO_DOMAIN_L4) {
+               if ((id1 != RTE_MAX_LCORE) && (id2 != RTE_MAX_LCORE))
+                       break;
+
+               if (rte_topo_get_lcore_count_from_domain(RTE_TOPO_DOMAIN_L4, 
domain) < 2)
+                       continue;
+
+               id1 = rte_topo_get_nth_lcore_from_domain(domain, 0, 0, 
RTE_TOPO_DOMAIN_L4);
+               id2 = rte_topo_get_nth_lcore_from_domain(domain, 1, 0, 
RTE_TOPO_DOMAIN_L4);
+       }
+
+       if ((id1 == RTE_MAX_LCORE) || (id2 == RTE_MAX_LCORE))
+               return 2;
+
+       if (id1 == id2)
+               return 3;
+
+       lcp->c1 = id1;
+       lcp->c2 = id2;
+       return 0;
+}
+
+static int
+get_same_l3_domains(struct lcore_pair *lcp)
+{      if (rte_topo_get_domain_count(RTE_TOPO_DOMAIN_L3) == 0)
+               return 1;
+
+       unsigned int id1 = RTE_MAX_LCORE, id2 = RTE_MAX_LCORE;
+       unsigned int domain = 0;
+
+       RTE_TOPO_FOREACH_DOMAIN(domain, RTE_TOPO_DOMAIN_L3) {
+               if ((id1 != RTE_MAX_LCORE) && (id2 != RTE_MAX_LCORE))
+                       break;
+
+               if (rte_topo_get_lcore_count_from_domain(RTE_TOPO_DOMAIN_L3, 
domain) < 2)
+                       continue;
+
+               id1 = rte_topo_get_nth_lcore_from_domain(domain, 0, 0, 
RTE_TOPO_DOMAIN_L3);
+               id2 = rte_topo_get_nth_lcore_from_domain(domain, 1, 0, 
RTE_TOPO_DOMAIN_L3);
+       }
+
+       if ((id1 == RTE_MAX_LCORE) || (id2 == RTE_MAX_LCORE))
+               return 2;
+
+       if (id1 == id2)
+               return 3;
+
+       lcp->c1 = id1;
+       lcp->c2 = id2;
+
+       return 0;
+
+}
+
+static int
+get_same_l2_domains(struct lcore_pair *lcp)
+{      if (rte_topo_get_domain_count(RTE_TOPO_DOMAIN_L2) == 0)
+               return 1;
+
+       unsigned int id1 = RTE_MAX_LCORE, id2 = RTE_MAX_LCORE;
+       unsigned int domain = 0;
+
+       RTE_TOPO_FOREACH_DOMAIN(domain, RTE_TOPO_DOMAIN_L2) {
+               if ((id1 != RTE_MAX_LCORE) && (id2 != RTE_MAX_LCORE))
+                       break;
+
+               if (rte_topo_get_lcore_count_from_domain(RTE_TOPO_DOMAIN_L2, 
domain) < 2)
+                       continue;
+
+               id1 = rte_topo_get_nth_lcore_from_domain(domain, 0, 0, 
RTE_TOPO_DOMAIN_L2);
+               id2 = rte_topo_get_nth_lcore_from_domain(domain, 1, 0, 
RTE_TOPO_DOMAIN_L2);
+       }
+
+       if ((id1 == RTE_MAX_LCORE) || (id2 == RTE_MAX_LCORE))
+               return 2;
+
+       if (id1 == id2)
+               return 3;
+
+       lcp->c1 = id1;
+       lcp->c2 = id2;
+
+       return 0;
+
+}
+
+static int
+get_same_l1_domains(struct lcore_pair *lcp)
+{
+       if (rte_topo_get_domain_count(RTE_TOPO_DOMAIN_L1) == 0)
+               return 1;
+
+       unsigned int id1 = RTE_MAX_LCORE, id2 = RTE_MAX_LCORE;
+       unsigned int domain = 0;
+
+       RTE_TOPO_FOREACH_DOMAIN(domain, RTE_TOPO_DOMAIN_L1) {
+               if ((id1 != RTE_MAX_LCORE) && (id2 != RTE_MAX_LCORE))
+                       break;
+
+               if (rte_topo_get_lcore_count_from_domain(RTE_TOPO_DOMAIN_L1, 
domain) < 2)
+                       continue;
+
+               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);
+       }
+
+       if ((id1 == RTE_MAX_LCORE) || (id2 == RTE_MAX_LCORE))
+               return 2;
+
+       if (id1 == id2)
+               return 3;
+
+       lcp->c1 = id1;
+       lcp->c2 = id2;
+
+       return 0;
+
+}
+static int
+get_two_numa_domains(struct lcore_pair *lcp)
+{
+       if (rte_topo_get_domain_count(RTE_TOPO_DOMAIN_NUMA) < 2)
+               return 1;
+
+       unsigned int id1 = RTE_MAX_LCORE, id2 = RTE_MAX_LCORE;
+       unsigned int domain = 0;
+
+       RTE_TOPO_FOREACH_DOMAIN(domain, RTE_TOPO_DOMAIN_NUMA) {
+               if ((id1 != RTE_MAX_LCORE) && (id2 != RTE_MAX_LCORE))
+                       break;
+
+               if (rte_topo_get_lcore_count_from_domain(RTE_TOPO_DOMAIN_NUMA, 
domain) == 0)
+                       continue;
+
+               if (id1 == RTE_MAX_LCORE) {
+                       id1 = rte_topo_get_nth_lcore_from_domain(domain,
+                               0, 0, RTE_TOPO_DOMAIN_NUMA);
+                       continue;
+               }
+               if (id2 == RTE_MAX_LCORE) {
+                       id2 = rte_topo_get_nth_lcore_from_domain(domain,
+                               0, 0, RTE_TOPO_DOMAIN_NUMA);
+                       continue;
+               }
+       }
+
+       if ((id1 == RTE_MAX_LCORE) || (id2 == RTE_MAX_LCORE))
+               return 2;
+
+       if (id1 == id2)
+               return 3;
+
+       lcp->c1 = id1;
+       lcp->c2 = id2;
+
+       return 0;
+}
+
+static int
+get_two_l4_domains(struct lcore_pair *lcp)
+{
+       if (rte_topo_get_domain_count(RTE_TOPO_DOMAIN_L4) < 2)
+               return 1;
+
+       unsigned int id1 = RTE_MAX_LCORE, id2 = RTE_MAX_LCORE;
+       unsigned int domain = 0;
+
+       RTE_TOPO_FOREACH_DOMAIN(domain, RTE_TOPO_DOMAIN_L4) {
+               if ((id1 != RTE_MAX_LCORE) && (id2 != RTE_MAX_LCORE))
+                       break;
+
+               if (rte_topo_get_lcore_count_from_domain(RTE_TOPO_DOMAIN_L4, 
domain) == 0)
+                       continue;
+
+               if (id1 == RTE_MAX_LCORE) {
+                       id1 = rte_topo_get_nth_lcore_from_domain(domain, 0, 0, 
RTE_TOPO_DOMAIN_L4);
+                       continue;
+               }
+               if (id2 == RTE_MAX_LCORE) {
+                       id2 = rte_topo_get_nth_lcore_from_domain(domain, 0, 0, 
RTE_TOPO_DOMAIN_L4);
+                       continue;
+               }
+       }
+
+       if ((id1 == RTE_MAX_LCORE) || (id2 == RTE_MAX_LCORE))
+               return 2;
+
+       if (id1 == id2)
+               return 3;
+
+       lcp->c1 = id1;
+       lcp->c2 = id2;
+       return 0;
+}
+
+static int
+get_two_l3_domains(struct lcore_pair *lcp)
+{      if (rte_topo_get_domain_count(RTE_TOPO_DOMAIN_L3) < 2)
+               return 1;
+
+       unsigned int id1 = RTE_MAX_LCORE, id2 = RTE_MAX_LCORE;
+       unsigned int domain = 0;
+
+       RTE_TOPO_FOREACH_DOMAIN(domain, RTE_TOPO_DOMAIN_L3) {
+               if ((id1 != RTE_MAX_LCORE) && (id2 != RTE_MAX_LCORE))
+                       break;
+
+               if (rte_topo_get_lcore_count_from_domain(RTE_TOPO_DOMAIN_L3, 
domain) == 0)
+                       continue;
+
+               if (id1 == RTE_MAX_LCORE) {
+                       id1 = rte_topo_get_nth_lcore_from_domain(domain, 0, 0, 
RTE_TOPO_DOMAIN_L3);
+                       continue;
+               }
+               if (id2 == RTE_MAX_LCORE) {
+                       id2 = rte_topo_get_nth_lcore_from_domain(domain, 0, 0, 
RTE_TOPO_DOMAIN_L3);
+                       continue;
+               }
+       }
+
+       if ((id1 == RTE_MAX_LCORE) || (id2 == RTE_MAX_LCORE))
+               return 2;
+
+       if (id1 == id2)
+               return 3;
+
+       lcp->c1 = id1;
+       lcp->c2 = id2;
+
+       return 0;
+
+}
+
+static int
+get_two_l2_domains(struct lcore_pair *lcp)
+{      if (rte_topo_get_domain_count(RTE_TOPO_DOMAIN_L2) < 2)
+               return 1;
+
+       unsigned int id1 = RTE_MAX_LCORE, id2 = RTE_MAX_LCORE;
+       unsigned int domain = 0;
+
+       RTE_TOPO_FOREACH_DOMAIN(domain, RTE_TOPO_DOMAIN_L2) {
+               if ((id1 != RTE_MAX_LCORE) && (id2 != RTE_MAX_LCORE))
+                       break;
+
+               if (rte_topo_get_lcore_count_from_domain(RTE_TOPO_DOMAIN_L2, 
domain) == 0)
+                       continue;
+
+               if (id1 == RTE_MAX_LCORE) {
+                       id1 = rte_topo_get_nth_lcore_from_domain(domain, 0, 0, 
RTE_TOPO_DOMAIN_L2);
+                       continue;
+               }
+               if (id2 == RTE_MAX_LCORE) {
+                       id2 = rte_topo_get_nth_lcore_from_domain(domain, 0, 0, 
RTE_TOPO_DOMAIN_L2);
+                       continue;
+               }
+       }
+
+       if ((id1 == RTE_MAX_LCORE) || (id2 == RTE_MAX_LCORE))
+               return 2;
+
+       if (id1 == id2)
+               return 3;
+
+       lcp->c1 = id1;
+       lcp->c2 = id2;
+
+       return 0;
+
+}
+
+static int
+get_two_l1_domains(struct lcore_pair *lcp)
+{
+       if (rte_topo_get_domain_count(RTE_TOPO_DOMAIN_L1) < 2)
+               return 1;
+
+       unsigned int id1 = RTE_MAX_LCORE, id2 = RTE_MAX_LCORE;
+       unsigned int domain = 0;
+
+       RTE_TOPO_FOREACH_DOMAIN(domain, RTE_TOPO_DOMAIN_L1) {
+               if ((id1 != RTE_MAX_LCORE) && (id2 != RTE_MAX_LCORE))
+                       break;
+
+               if (rte_topo_get_lcore_count_from_domain(RTE_TOPO_DOMAIN_L1, 
domain) == 0)
+                       continue;
+
+               if (id1 == RTE_MAX_LCORE) {
+                       id1 = rte_topo_get_nth_lcore_from_domain(domain, 0, 0, 
RTE_TOPO_DOMAIN_L1);
+                       continue;
+               }
+               if (id2 == RTE_MAX_LCORE) {
+                       id2 = rte_topo_get_nth_lcore_from_domain(domain, 0, 0, 
RTE_TOPO_DOMAIN_L1);
+                       continue;
+               }
+       }
+
+       if ((id1 == RTE_MAX_LCORE) || (id2 == RTE_MAX_LCORE))
+               return 2;
+
+       if (id1 == id2)
+               return 3;
+
+       lcp->c1 = id1;
+       lcp->c2 = id2;
+
+       return 0;
+
+}
+#endif
+
 /* Get cycle counts for dequeuing from an empty ring. Should be 2 or 3 cycles 
*/
 static void
 test_empty_dequeue(struct rte_ring *r, const int esize,
@@ -488,6 +844,60 @@ test_ring_perf_esize_run_on_two_cores(
                if (run_on_core_pair(&cores, param1, param2) < 0)
                        return -1;
        }
+#ifdef RTE_LIBHWLOC_PROBE
+       if (rte_lcore_count() > 2) {
+               if (get_same_numa_domains(&cores) == 0) {
+                       printf("\n### Testing using same numa domain nodes 
###\n");
+                       if (run_on_core_pair(&cores, param1, param2) < 0)
+                               return -1;
+               }
+               if (get_same_l4_domains(&cores) == 0) {
+                       printf("\n### Testing using same l4 domain nodes 
###\n");
+                       if (run_on_core_pair(&cores, param1, param2) < 0)
+                               return -1;
+               }
+               if (get_same_l3_domains(&cores) == 0) {
+                       printf("\n### Testing using same l3 domain nodes 
###\n");
+                       if (run_on_core_pair(&cores, param1, param2) < 0)
+                               return -1;
+               }
+               if (get_same_l2_domains(&cores) == 0) {
+                       printf("\n### Testing using same l2 domain nodes 
###\n");
+                       if (run_on_core_pair(&cores, param1, param2) < 0)
+                               return -1;
+               }
+               if (get_same_l1_domains(&cores) == 0) {
+                       printf("\n### Testing using same l1 domain nodes 
###\n");
+                       if (run_on_core_pair(&cores, param1, param2) < 0)
+                               return -1;
+               }
+               if (get_two_numa_domains(&cores) == 0) {
+                       printf("\n### Testing using two numa domain nodes 
###\n");
+                       if (run_on_core_pair(&cores, param1, param2) < 0)
+                               return -1;
+               }
+               if (get_two_l4_domains(&cores) == 0) {
+                       printf("\n### Testing using two l4 domain nodes ###\n");
+                       if (run_on_core_pair(&cores, param1, param2) < 0)
+                               return -1;
+               }
+               if (get_two_l3_domains(&cores) == 0) {
+                       printf("\n### Testing using two l3 domain nodes ###\n");
+                       if (run_on_core_pair(&cores, param1, param2) < 0)
+                               return -1;
+               }
+               if (get_two_l2_domains(&cores) == 0) {
+                       printf("\n### Testing using two l2 domain nodes ###\n");
+                       if (run_on_core_pair(&cores, param1, param2) < 0)
+                               return -1;
+               }
+               if (get_two_l1_domains(&cores) == 0) {
+                       printf("\n### Testing using two l1 domain nodes ###\n");
+                       if (run_on_core_pair(&cores, param1, param2) < 0)
+                               return -1;
+               }
+       }
+#endif
        return 0;
 }
 
diff --git a/app/test/test_stack_perf.c b/app/test/test_stack_perf.c
index 3f17a2606c..e5b038a3e8 100644
--- a/app/test/test_stack_perf.c
+++ b/app/test/test_stack_perf.c
@@ -10,6 +10,9 @@
 #include <rte_launch.h>
 #include <rte_pause.h>
 #include <rte_stack.h>
+#ifdef RTE_LIBHWLOC_PROBE
+#include <rte_topology.h>
+#endif
 
 #include "test.h"
 
@@ -105,6 +108,367 @@ get_two_sockets(struct lcore_pair *lcp)
        return 1;
 }
 
+#ifdef RTE_LIBHWLOC_PROBE
+static int
+get_same_numa_domains(struct lcore_pair *lcp)
+{
+       if (rte_topo_get_domain_count(RTE_TOPO_DOMAIN_NUMA) == 0)
+               return 1;
+
+       unsigned int id1 = RTE_MAX_LCORE, id2 = RTE_MAX_LCORE;
+       unsigned int domain = 0;
+
+       RTE_TOPO_FOREACH_DOMAIN(domain, RTE_TOPO_DOMAIN_NUMA) {
+               if ((id1 != RTE_MAX_LCORE) && (id2 != RTE_MAX_LCORE))
+                       break;
+
+               if (rte_topo_get_lcore_count_from_domain(RTE_TOPO_DOMAIN_NUMA, 
domain) < 2)
+                       continue;
+
+               id1 = rte_topo_get_nth_lcore_from_domain(domain, 0, 0, 
RTE_TOPO_DOMAIN_NUMA);
+               id2 = rte_topo_get_nth_lcore_from_domain(domain, 1, 0, 
RTE_TOPO_DOMAIN_NUMA);
+       }
+
+       if ((id1 == RTE_MAX_LCORE) || (id2 == RTE_MAX_LCORE))
+               return 2;
+
+       if (id1 == id2)
+               return 3;
+
+       lcp->c1 = id1;
+       lcp->c2 = id2;
+
+       return 0;
+}
+
+static int
+get_same_l4_domains(struct lcore_pair *lcp)
+{
+       if (rte_topo_get_domain_count(RTE_TOPO_DOMAIN_L4) == 0)
+               return 1;
+
+       unsigned int id1 = RTE_MAX_LCORE, id2 = RTE_MAX_LCORE;
+       unsigned int domain = 0;
+
+       RTE_TOPO_FOREACH_DOMAIN(domain, RTE_TOPO_DOMAIN_L4) {
+               if ((id1 != RTE_MAX_LCORE) && (id2 != RTE_MAX_LCORE))
+                       break;
+
+               if (rte_topo_get_lcore_count_from_domain(RTE_TOPO_DOMAIN_L4, 
domain) < 2)
+                       continue;
+
+               id1 = rte_topo_get_nth_lcore_from_domain(domain, 0, 0, 
RTE_TOPO_DOMAIN_L4);
+               id2 = rte_topo_get_nth_lcore_from_domain(domain, 1, 0, 
RTE_TOPO_DOMAIN_L4);
+       }
+
+       if ((id1 == RTE_MAX_LCORE) || (id2 == RTE_MAX_LCORE))
+               return 2;
+
+       if (id1 == id2)
+               return 3;
+
+       lcp->c1 = id1;
+       lcp->c2 = id2;
+
+       return 0;
+}
+
+static int
+get_same_l3_domains(struct lcore_pair *lcp)
+{
+       if (rte_topo_get_domain_count(RTE_TOPO_DOMAIN_L3) == 0)
+               return 1;
+
+       unsigned int id1 = RTE_MAX_LCORE, id2 = RTE_MAX_LCORE;
+       unsigned int domain = 0;
+
+       RTE_TOPO_FOREACH_DOMAIN(domain, RTE_TOPO_DOMAIN_L3) {
+               if ((id1 != RTE_MAX_LCORE) && (id2 != RTE_MAX_LCORE))
+                       break;
+
+               if (rte_topo_get_lcore_count_from_domain(RTE_TOPO_DOMAIN_L3, 
domain) < 2)
+                       continue;
+
+               id1 = rte_topo_get_nth_lcore_from_domain(domain, 0, 0, 
RTE_TOPO_DOMAIN_L3);
+               id2 = rte_topo_get_nth_lcore_from_domain(domain, 1, 0, 
RTE_TOPO_DOMAIN_L3);
+       }
+
+       if ((id1 == RTE_MAX_LCORE) || (id2 == RTE_MAX_LCORE))
+               return 2;
+
+       if (id1 == id2)
+               return 3;
+
+       lcp->c1 = id1;
+       lcp->c2 = id2;
+
+       return 0;
+}
+
+static int
+get_same_l2_domains(struct lcore_pair *lcp)
+{
+       if (rte_topo_get_domain_count(RTE_TOPO_DOMAIN_L2) == 0)
+               return 1;
+
+       unsigned int id1 = RTE_MAX_LCORE, id2 = RTE_MAX_LCORE;
+       unsigned int domain = 0;
+
+       RTE_TOPO_FOREACH_DOMAIN(domain, RTE_TOPO_DOMAIN_L2) {
+               if ((id1 != RTE_MAX_LCORE) && (id2 != RTE_MAX_LCORE))
+                       break;
+
+               if (rte_topo_get_lcore_count_from_domain(RTE_TOPO_DOMAIN_L2, 
domain) < 2)
+                       continue;
+
+               id1 = rte_topo_get_nth_lcore_from_domain(domain, 0, 0, 
RTE_TOPO_DOMAIN_L2);
+               id2 = rte_topo_get_nth_lcore_from_domain(domain, 1, 0, 
RTE_TOPO_DOMAIN_L2);
+       }
+
+       if ((id1 == RTE_MAX_LCORE) || (id2 == RTE_MAX_LCORE))
+               return 2;
+
+       if (id1 == id2)
+               return 3;
+
+       lcp->c1 = id1;
+       lcp->c2 = id2;
+
+       return 0;
+}
+
+static int
+get_same_l1_domains(struct lcore_pair *lcp)
+{
+       if (rte_topo_get_domain_count(RTE_TOPO_DOMAIN_L1) == 0)
+               return 1;
+
+       unsigned int id1 = RTE_MAX_LCORE, id2 = RTE_MAX_LCORE;
+       unsigned int domain = 0;
+
+       RTE_TOPO_FOREACH_DOMAIN(domain, RTE_TOPO_DOMAIN_L1) {
+               if (rte_topo_is_main_lcore_in_domain(domain, 
RTE_TOPO_DOMAIN_L1))
+                       continue;
+
+               if ((id1 != RTE_MAX_LCORE) && (id2 != RTE_MAX_LCORE))
+                       break;
+
+               if (rte_topo_get_lcore_count_from_domain(RTE_TOPO_DOMAIN_L1, 
domain) < 2)
+                       continue;
+
+               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);
+       }
+
+       if ((id1 == RTE_MAX_LCORE) || (id2 == RTE_MAX_LCORE))
+               return 2;
+
+       if (id1 == id2)
+               return 3;
+
+       lcp->c1 = id1;
+       lcp->c2 = id2;
+
+       return 0;
+}
+static int
+get_two_numa_domains(struct lcore_pair *lcp)
+{
+       if (rte_topo_get_domain_count(RTE_TOPO_DOMAIN_NUMA) < 2)
+               return 1;
+
+       unsigned int id1 = RTE_MAX_LCORE, id2 = RTE_MAX_LCORE;
+       unsigned int domain = 0;
+
+       RTE_TOPO_FOREACH_DOMAIN(domain, RTE_TOPO_DOMAIN_NUMA) {
+               if ((id1 != RTE_MAX_LCORE) && (id2 != RTE_MAX_LCORE))
+                       break;
+
+               if (rte_topo_get_lcore_count_from_domain(RTE_TOPO_DOMAIN_NUMA, 
domain) == 0)
+                       continue;
+
+               if (id1 == RTE_MAX_LCORE) {
+                       id1 = rte_topo_get_nth_lcore_from_domain(domain,
+                               0, 0, RTE_TOPO_DOMAIN_NUMA);
+                       continue;
+               }
+
+               if (id2 == RTE_MAX_LCORE) {
+                       id2 = rte_topo_get_nth_lcore_from_domain(domain,
+                               0, 0, RTE_TOPO_DOMAIN_NUMA);
+                       continue;
+               }
+       }
+
+       if ((id1 == RTE_MAX_LCORE) || (id2 == RTE_MAX_LCORE))
+               return 2;
+
+       if (id1 == id2)
+               return 3;
+
+       lcp->c1 = id1;
+       lcp->c2 = id2;
+
+       return 0;
+}
+
+static int
+get_two_l4_domains(struct lcore_pair *lcp)
+{
+       if (rte_topo_get_domain_count(RTE_TOPO_DOMAIN_L4) < 2)
+               return 1;
+
+       unsigned int id1 = RTE_MAX_LCORE, id2 = RTE_MAX_LCORE;
+       unsigned int domain = 0;
+
+       RTE_TOPO_FOREACH_DOMAIN(domain, RTE_TOPO_DOMAIN_L4) {
+               if ((id1 != RTE_MAX_LCORE) && (id2 != RTE_MAX_LCORE))
+                       break;
+
+               if (rte_topo_get_lcore_count_from_domain(RTE_TOPO_DOMAIN_L4, 
domain) == 0)
+                       continue;
+
+               if (id1 == RTE_MAX_LCORE) {
+                       id1 = rte_topo_get_nth_lcore_from_domain(domain, 0, 0, 
RTE_TOPO_DOMAIN_L4);
+                       continue;
+               }
+               if (id2 == RTE_MAX_LCORE) {
+                       id2 = rte_topo_get_nth_lcore_from_domain(domain, 0, 0, 
RTE_TOPO_DOMAIN_L4);
+                       continue;
+               }
+       }
+
+       if ((id1 == RTE_MAX_LCORE) || (id2 == RTE_MAX_LCORE))
+               return 2;
+
+       if (id1 == id2)
+               return 3;
+
+       lcp->c1 = id1;
+       lcp->c2 = id2;
+
+       return 0;
+}
+
+static int
+get_two_l3_domains(struct lcore_pair *lcp)
+{
+       if (rte_topo_get_domain_count(RTE_TOPO_DOMAIN_L3) < 2)
+               return 1;
+
+       unsigned int id1 = RTE_MAX_LCORE, id2 = RTE_MAX_LCORE;
+       unsigned int domain = 0;
+
+       RTE_TOPO_FOREACH_DOMAIN(domain, RTE_TOPO_DOMAIN_L3) {
+               if ((id1 != RTE_MAX_LCORE) && (id2 != RTE_MAX_LCORE))
+                       break;
+
+               if (rte_topo_get_lcore_count_from_domain(RTE_TOPO_DOMAIN_L3, 
domain) == 0)
+                       continue;
+
+               if (id1 == RTE_MAX_LCORE) {
+                       id1 = rte_topo_get_nth_lcore_from_domain(domain, 0, 0, 
RTE_TOPO_DOMAIN_L3);
+                       continue;
+               }
+
+               if (id2 == RTE_MAX_LCORE) {
+                       id2 = rte_topo_get_nth_lcore_from_domain(domain, 0, 0, 
RTE_TOPO_DOMAIN_L3);
+                       continue;
+               }
+       }
+
+       if ((id1 == RTE_MAX_LCORE) || (id2 == RTE_MAX_LCORE))
+               return 2;
+
+       if (id1 == id2)
+               return 3;
+
+       lcp->c1 = id1;
+       lcp->c2 = id2;
+
+       return 0;
+}
+
+static int
+get_two_l2_domains(struct lcore_pair *lcp)
+{
+       if (rte_topo_get_domain_count(RTE_TOPO_DOMAIN_L2) < 2)
+               return 1;
+
+       unsigned int id1 = RTE_MAX_LCORE, id2 = RTE_MAX_LCORE;
+       unsigned int domain = 0;
+
+       RTE_TOPO_FOREACH_DOMAIN(domain, RTE_TOPO_DOMAIN_L2) {
+               if ((id1 != RTE_MAX_LCORE) && (id2 != RTE_MAX_LCORE))
+                       break;
+
+               if (rte_topo_get_lcore_count_from_domain(RTE_TOPO_DOMAIN_L2, 
domain) == 0)
+                       continue;
+
+               if (id1 == RTE_MAX_LCORE) {
+                       id1 = rte_topo_get_nth_lcore_from_domain(domain, 0, 0, 
RTE_TOPO_DOMAIN_L2);
+                       continue;
+               }
+
+               if (id2 == RTE_MAX_LCORE) {
+                       id2 = rte_topo_get_nth_lcore_from_domain(domain, 0, 0, 
RTE_TOPO_DOMAIN_L2);
+                       continue;
+               }
+       }
+
+       if ((id1 == RTE_MAX_LCORE) || (id2 == RTE_MAX_LCORE))
+               return 2;
+
+       if (id1 == id2)
+               return 3;
+
+       lcp->c1 = id1;
+       lcp->c2 = id2;
+
+       return 0;
+}
+
+static int
+get_two_l1_domains(struct lcore_pair *lcp)
+{
+       if (rte_topo_get_domain_count(RTE_TOPO_DOMAIN_L1) < 2)
+               return 1;
+
+       unsigned int id1 = RTE_MAX_LCORE, id2 = RTE_MAX_LCORE;
+       unsigned int domain = 0;
+
+       RTE_TOPO_FOREACH_DOMAIN(domain, RTE_TOPO_DOMAIN_L1) {
+               if ((id1 != RTE_MAX_LCORE) && (id2 != RTE_MAX_LCORE))
+                       break;
+
+               if (rte_topo_get_lcore_count_from_domain(RTE_TOPO_DOMAIN_L1, 
domain) == 0)
+                       continue;
+
+               if (id1 == RTE_MAX_LCORE) {
+                       id1 = rte_topo_get_nth_lcore_from_domain(domain, 0, 0, 
RTE_TOPO_DOMAIN_L1);
+                       continue;
+               }
+
+               if (id2 == RTE_MAX_LCORE) {
+                       id2 = rte_topo_get_nth_lcore_from_domain(domain, 0, 0, 
RTE_TOPO_DOMAIN_L1);
+                       continue;
+               }
+       }
+
+       if ((id1 == RTE_MAX_LCORE) || (id2 == RTE_MAX_LCORE))
+               return 2;
+
+       if (id1 == id2)
+               return 3;
+
+       lcp->c1 = id1;
+       lcp->c2 = id2;
+
+       return 0;
+}
+#endif
+
+
 /* Measure the cycle cost of popping an empty stack. */
 static void
 test_empty_pop(struct rte_stack *s)
@@ -331,6 +695,51 @@ __test_stack_perf(uint32_t flags)
                run_on_core_pair(&cores, s, bulk_push_pop);
        }
 
+#ifdef RTE_LIBHWLOC_PROBE
+       if (rte_lcore_count() > 2) {
+               if (get_same_numa_domains(&cores) == 0) {
+                       printf("\n### Testing using same numa domain nodes 
###\n");
+                       run_on_core_pair(&cores, s, bulk_push_pop);
+               }
+               if (get_same_l4_domains(&cores) == 0) {
+                       printf("\n### Testing using same l4 domain nodes 
###\n");
+                       run_on_core_pair(&cores, s, bulk_push_pop);
+               }
+               if (get_same_l3_domains(&cores) == 0) {
+                       printf("\n### Testing using same l3 domain nodes 
###\n");
+                       run_on_core_pair(&cores, s, bulk_push_pop);
+               }
+               if (get_same_l2_domains(&cores) == 0) {
+                       printf("\n### Testing using same l2 domain nodes 
###\n");
+                       run_on_core_pair(&cores, s, bulk_push_pop);
+               }
+               if (get_same_l1_domains(&cores) == 0) {
+                       printf("\n### Testing using same l1 domain nodes 
###\n");
+                       run_on_core_pair(&cores, s, bulk_push_pop);
+               }
+               if (get_two_numa_domains(&cores) == 0) {
+                       printf("\n### Testing using two numa domain nodes 
###\n");
+                       run_on_core_pair(&cores, s, bulk_push_pop);
+               }
+               if (get_two_l4_domains(&cores) == 0) {
+                       printf("\n### Testing using two l4 domain nodes ###\n");
+                       run_on_core_pair(&cores, s, bulk_push_pop);
+               }
+               if (get_two_l3_domains(&cores) == 0) {
+                       printf("\n### Testing using two l3 domain nodes ###\n");
+                       run_on_core_pair(&cores, s, bulk_push_pop);
+               }
+               if (get_two_l2_domains(&cores) == 0) {
+                       printf("\n### Testing using two l2 domain nodes ###\n");
+                       run_on_core_pair(&cores, s, bulk_push_pop);
+               }
+               if (get_two_l1_domains(&cores) == 0) {
+                       printf("\n### Testing using two l1 domain nodes ###\n");
+                       run_on_core_pair(&cores, s, bulk_push_pop);
+               }
+       }
+#endif
+
        printf("\n### Testing on all %u lcores ###\n", rte_lcore_count());
        run_on_n_cores(s, bulk_push_pop, rte_lcore_count());
 
diff --git a/app/test/test_topology.c b/app/test/test_topology.c
new file mode 100644
index 0000000000..f2244ad807
--- /dev/null
+++ b/app/test/test_topology.c
@@ -0,0 +1,676 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 AMD Corporation
+ */
+
+#include <sched.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <rte_common.h>
+#include <rte_errno.h>
+#include <rte_lcore.h>
+#include <rte_thread.h>
+#include <rte_topology.h>
+
+#include "test.h"
+
+#ifndef _POSIX_PRIORITY_SCHEDULING
+/* sched_yield(2):
+ * POSIX systems on which sched_yield() is available define
+ * _POSIX_PRIORITY_SCHEDULING in <unistd.h>.
+ */
+#define sched_yield()
+#endif
+
+#ifdef RTE_LIBHWLOC_PROBE
+
+static const unsigned int domain_types[] = {
+       RTE_TOPO_DOMAIN_NUMA,
+       RTE_TOPO_DOMAIN_L4,
+       RTE_TOPO_DOMAIN_L3,
+       RTE_TOPO_DOMAIN_L2,
+       RTE_TOPO_DOMAIN_L1
+};
+
+static int
+test_topology_macro(void)
+{
+       unsigned int total_lcores = 0;
+       unsigned int total_wrkr_lcores = 0;
+
+       unsigned int count_lcore = 0;
+       unsigned int total_lcore = 0;
+       unsigned int total_wrkr_lcore = 0;
+
+       unsigned int lcore = 0, pos = 0, domain = 0;
+
+       /* get topology core count */
+       lcore = -1;
+       RTE_LCORE_FOREACH(lcore)
+               total_lcores += 1;
+
+       lcore = -1;
+       RTE_LCORE_FOREACH_WORKER(lcore)
+               total_wrkr_lcores += 1;
+
+       RTE_TEST_ASSERT(((total_wrkr_lcores + 1) == total_lcores),
+               "fail in MACRO for RTE_LCORE_FOREACH\n");
+
+       RTE_LOG(DEBUG, USER1, "Lcore: %u, Lcore Worker: %u\n", total_lcores, 
total_wrkr_lcores);
+       RTE_LOG(DEBUG, USER1, "| %10s | %10s | %10s | %10s |\n",
+               "domain name", "count", "LCORE", "WORKER");
+       RTE_LOG(DEBUG, USER1, 
"------------------------------------------------------\n");
+
+       for (unsigned int d = 0; d < RTE_DIM(domain_types); d++) {
+               count_lcore = 0;
+               total_lcore = 0;
+               total_wrkr_lcore = 0;
+               domain = RTE_TOPO_DOMAIN_MAX;
+               RTE_TOPO_FOREACH_DOMAIN(domain, domain_types[d]) {
+                       count_lcore +=
+                               
rte_topo_get_lcore_count_from_domain(domain_types[d], domain);
+
+                       lcore = RTE_MAX_LCORE;
+                       pos = 0;
+                       RTE_TOPO_FOREACH_LCORE_IN_DOMAIN(lcore, domain, pos, 
domain_types[d])
+                               total_lcore += 1;
+
+                       /* skip domain */
+                       if (rte_topo_is_main_lcore_in_domain(domain, 
domain_types[d]))
+                               continue;
+
+                       lcore = RTE_MAX_LCORE;
+                       RTE_TOPO_FOREACH_WORKER_LCORE_IN_DOMAIN(lcore, domain, 
domain_types[d]) {
+                               total_wrkr_lcore += 1;
+                       }
+               }
+
+               if (count_lcore) {
+                       RTE_TEST_ASSERT((total_wrkr_lcore < total_lcore),
+                               "unexpected workers in %s domain!\n",
+                               (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);
+
+                       RTE_LOG(DEBUG, USER1, "| %10s | %10u | %10u | %10u |\n",
+                               (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,
+                               rte_topo_get_domain_count(domain_types[d]),
+                               total_lcore, total_wrkr_lcore);
+               }
+       }
+       RTE_LOG(DEBUG, USER1, 
"---------------------------------------------------------\n");
+
+       printf("INFO: lcore DOMAIN macro: success!\n");
+       return TEST_SUCCESS;
+}
+
+static int
+test_lcore_count_from_domain(void)
+{
+       unsigned int total_lcores = 0;
+       unsigned int total_domain_lcores = 0;
+       unsigned int domain_count;
+       unsigned int i;
+
+       /* get topology core count */
+       total_lcores = rte_lcore_count();
+
+       RTE_LOG(DEBUG, USER1, "| %10s | %10s |\n", "domain", " LCORE");
+       RTE_LOG(DEBUG, USER1, "---------------------------------------\n");
+       RTE_LOG(DEBUG, USER1, "| %10s | %10u |\n", "rte_lcore", total_lcores);
+
+       for (unsigned int d = 0; d < RTE_DIM(domain_types); d++) {
+               total_domain_lcores = 0;
+               domain_count = rte_topo_get_domain_count(domain_types[d]);
+               for (i = 0; i < domain_count; i++)
+                       total_domain_lcores +=
+                               
rte_topo_get_lcore_count_from_domain(domain_types[d], i);
+
+               if (domain_count) {
+                       RTE_TEST_ASSERT((total_domain_lcores == total_lcores),
+                               "domain %s lcores does not match!\n",
+                               (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);
+
+                       RTE_LOG(DEBUG, USER1, "| %10s | %10u |\n",
+                               (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,
+                               total_domain_lcores);
+               }
+       }
+       RTE_LOG(DEBUG, USER1, "---------------------------------------\n");
+
+       printf("INFO: lcore count domain API: success\n");
+       return TEST_SUCCESS;
+}
+
+#ifdef RTE_HAS_CPUSET
+static int
+test_lcore_cpuset_from_domain(void)
+{
+       unsigned int domain_count;
+       uint16_t dmn_idx;
+       rte_cpuset_t cpu_set_list;
+
+       for (unsigned int d = 0; d < RTE_DIM(domain_types); d++) {
+               domain_count = rte_topo_get_domain_count(domain_types[d]);
+               for (dmn_idx = 0; dmn_idx < domain_count; dmn_idx++) {
+                       cpu_set_list = 
rte_topo_get_lcore_cpuset_in_domain(domain_types[d],
+                               dmn_idx);
+
+                       for (uint16_t cpu_idx = 0; cpu_idx < RTE_MAX_LCORE; 
cpu_idx++) {
+                               if (CPU_ISSET(cpu_idx, &cpu_set_list))
+                                       
RTE_TEST_ASSERT(rte_lcore_is_enabled(cpu_idx), "%s domain at %u lcore %u not 
enabled!\n",
+                                       (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,
+                                       dmn_idx, cpu_idx);
+
+                       }
+               }
+       }
+       printf("INFO: topology cpuset: success!\n");
+
+       for (unsigned int d = 0; d < RTE_DIM(domain_types); d++) {
+               cpu_set_list = 
rte_topo_get_lcore_cpuset_in_domain(domain_types[d], UINT32_MAX);
+               RTE_TEST_ASSERT((CPU_COUNT(&cpu_set_list) == 0),
+                       "lcore not expected for %s domain invalid index!\n",
+                       (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);
+       }
+
+       printf("INFO: cpuset_in_domain API: success!\n");
+       return TEST_SUCCESS;
+}
+#endif
+
+static int
+test_main_lcore_in_domain(void)
+{
+       for (unsigned int d = 0; d < RTE_DIM(domain_types); d++) {
+               bool main_lcore_found = false;
+               unsigned int domain_count = 
rte_topo_get_domain_count(domain_types[d]);
+               for (unsigned int dmn_idx = 0; dmn_idx < domain_count; 
dmn_idx++) {
+                       main_lcore_found = 
rte_topo_is_main_lcore_in_domain(RTE_TOPO_DOMAIN_NUMA,
+                               dmn_idx);
+                       if (main_lcore_found)
+                               break;
+               }
+
+               if (domain_count)
+                       RTE_TEST_ASSERT((main_lcore_found == true),
+                       "main lcore is not found in %s domain!\n",
+                       (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);
+       }
+
+       printf("INFO: is_main_lcore_in_domain API: success!\n");
+       return TEST_SUCCESS;
+}
+
+static int
+test_lcore_from_domain_negative(void)
+{
+       for (unsigned int d = 0; d < RTE_DIM(domain_types); d++) {
+               const unsigned int domain_count = 
rte_topo_get_domain_count(domain_types[d]);
+               if (domain_count)
+                       RTE_TEST_ASSERT(
+                               
(rte_topo_get_lcore_count_from_domain(domain_types[d],
+                                       domain_count) == 0),
+                               "domain %s API inconsistent for numa\n",
+                               (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);
+       }
+
+       printf("INFO: lcore domain API: success!\n");
+       return TEST_SUCCESS;
+}
+
+static int
+test_wrap_with_skip_main_edge_case(void)
+{
+       const unsigned int main_lcore = rte_get_main_lcore();
+
+       for (unsigned int d = 0; d < RTE_DIM(domain_types); d++) {
+               const unsigned int domain_count = 
rte_topo_get_domain_count(domain_types[d]);
+               for (unsigned int domain_index = 0; domain_index < 
domain_count; domain_index++) {
+                       unsigned int lcores_in_domain_index =
+                               
rte_topo_get_lcore_count_from_domain(domain_types[d],
+                                       domain_index);
+
+                       if (lcores_in_domain_index &&
+                               
(rte_topo_is_main_lcore_in_domain(domain_types[d],
+                                       lcores_in_domain_index))) {
+
+                               if (lcores_in_domain_index == 1)
+                                       continue;
+
+                               for (unsigned int i = 0; i < 
lcores_in_domain_index; i++) {
+                                       const uint16_t next_lcore =
+                                               
rte_topo_get_nth_lcore_from_domain(domain_index,
+                                                       i, 0, domain_types[d]);
+
+                                       RTE_TEST_ASSERT(next_lcore != 
main_lcore,
+                                               "expected domain %s, main lcore 
%u, to be skipped!",
+                                               (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,
+                                               main_lcore);
+                               }
+                       }
+               }
+       }
+
+       printf("INFO: skip main lcore API: success!\n");
+       return TEST_SUCCESS;
+}
+
+static int
+test_invalid_domain_selector(void)
+{
+       unsigned int count;
+       unsigned int lcore;
+       rte_cpuset_t cpuset;
+
+       /* Test with completely invalid domain selector */
+       count = rte_topo_get_domain_count(0xDEADBEEF);
+       RTE_TEST_ASSERT((count == 0), "Invalid domain selector should return 0 
count\n");
+
+       /* Test with 0 (no bits set) */
+       count = rte_topo_get_domain_count(0);
+       RTE_TEST_ASSERT((count == 0), "Zero domain selector should return 0 
count\n");
+
+       /* Test count_from_domain with invalid selector */
+       count = rte_topo_get_lcore_count_from_domain(0xBADC0DE, 0);
+       RTE_TEST_ASSERT((count == 0), "Invalid domain should return 0 cores\n");
+
+       /* Test get_lcore_in_domain with invalid selector */
+       lcore = rte_topo_get_nth_lcore_in_domain(0xBADC0DE, 0, 0);
+       RTE_TEST_ASSERT((lcore == RTE_MAX_LCORE), "Invalid domain should return 
RTE_MAX_LCORE\n");
+
+       /* Test cpuset with invalid selector */
+       cpuset = rte_topo_get_lcore_cpuset_in_domain(0xBADC0DE, 0);
+       RTE_TEST_ASSERT((CPU_COUNT(&cpuset) == 0), "Invalid domain should 
return empty cpuset\n");
+
+       printf("INFO: Invalid domain selector test: success\n");
+       return TEST_SUCCESS;
+}
+
+static int
+test_multiple_invalid_inputs(void)
+{
+       if (rte_lcore_count() == 1) {
+               printf("INFO: topology MACRO test requires more than 1 core, 
skipping!\n");
+               return TEST_SKIPPED;
+       }
+
+       /* Test all APIs with multiple types of invalid inputs */
+       unsigned int invalid_domains[] = {
+               0,             /* No bits set */
+               0xFFFFFFFF,    /* All bits set (not a single domain) */
+               0x80000000,    /* Bit outside valid range */
+               0x12345678,    /* Random invalid value */
+       };
+
+       for (int i = 0; i < 4; i++) {
+               unsigned int domain = invalid_domains[i];
+
+               /* All should return safe defaults */
+               RTE_TEST_ASSERT((rte_topo_get_domain_count(domain) == 0),
+                       "Invalid domain 0x%x should have NO count\n", domain);
+               RTE_TEST_ASSERT((rte_topo_get_lcore_count_from_domain(domain, 
0) == 0),
+                       "Invalid domain 0x%x should have NO cores\n", domain);
+               RTE_TEST_ASSERT((rte_topo_get_nth_lcore_in_domain(domain, 0, 0) 
== RTE_MAX_LCORE),
+                       "Invalid domain 0x%x should return MAX_LCORE\n", 
domain);
+       }
+
+       printf("INFO: Multiple invalid inputs test: success\n");
+       return TEST_SUCCESS;
+}
+
+static int
+test_large_index_values(void)
+{
+       if (rte_lcore_count() == 1) {
+               printf("INFO: topology MACRO test requires more than 1 core, 
skipping!\n");
+               return TEST_SKIPPED;
+       }
+
+       uint16_t test_lcore = 0;
+       unsigned int large_indices[] = {
+               RTE_MAX_LCORE,
+               RTE_MAX_LCORE + 1,
+               UINT32_MAX,
+               0x7FFFFFFF,
+       };
+
+       for (unsigned int d = 0; d < RTE_DIM(domain_types); d++) {
+               for (unsigned int i = 0; i < RTE_DIM(large_indices); i++) {
+                       unsigned int idx = large_indices[i];
+
+                       /* Should all handle gracefully and return safe 
defaults */
+                       test_lcore = 
rte_topo_get_lcore_count_from_domain(domain_types[d], idx);
+                       RTE_TEST_ASSERT(test_lcore == 0,
+                               "Large index %u in domain %s should return 0 
cores\n",
+                               idx,
+                               (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);
+
+                       test_lcore = 
rte_topo_get_nth_lcore_in_domain(domain_types[d], idx, 0);
+                       RTE_TEST_ASSERT(test_lcore == RTE_MAX_LCORE,
+                               "Large index %u in domain %s should return 
MAX_LCORE\n",
+                               idx,
+                               (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);
+
+#ifdef RTE_HAS_CPUSET
+                       rte_cpuset_t cpuset = 
rte_topo_get_lcore_cpuset_in_domain(domain_types[d],
+                               idx);
+                       RTE_TEST_ASSERT(CPU_COUNT(&cpuset) == 0,
+                               "Large index %u in domain %s should return 
empty cpuset",
+                               idx,
+                               (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);
+#endif
+               }
+       }
+
+       printf("INFO: Large index values test: success\n");
+       return TEST_SUCCESS;
+}
+
+
+static int
+test_domain_next_lcore_no_wrap(void)
+{
+       if (rte_lcore_count() == 1) {
+               printf("INFO: topology MACRO test requires more than 1 core, 
skipping!\n");
+               return TEST_SKIPPED;
+       }
+
+       for (unsigned int d = 0; d < RTE_DIM(domain_types); d++) {
+               const unsigned int lcores_in_domain = 
rte_topo_get_domain_count(domain_types[d]);
+
+               for (unsigned int domain_index = 0; domain_index < 
lcores_in_domain;
+                       domain_index++) {
+                       unsigned int lcores_in_domain_index =
+                               
rte_topo_get_lcore_count_from_domain(domain_types[d],
+                                       domain_index);
+
+                       for (unsigned int i = 0; i < lcores_in_domain_index; 
i++) {
+                               const uint16_t curr_lcore =
+                                       
rte_topo_get_nth_lcore_from_domain(domain_index,
+                                               i, 0, domain_types[d]);
+
+                               const uint16_t wrap_lcore =
+                                       
rte_topo_get_nth_lcore_from_domain(domain_index,
+                                               lcores_in_domain_index + i, 0, 
domain_types[d]);
+
+                               RTE_TEST_ASSERT(wrap_lcore == RTE_MAX_LCORE,
+                                       "expected domain %s, lcore %u, wrapped 
lcore %u should be RTE_MAX_LCORE!",
+                                       (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,
+                                       curr_lcore, wrap_lcore);
+                       }
+               }
+       }
+
+       printf("INFO: next lcore in domain test: success\n");
+       return TEST_SUCCESS;
+}
+
+static int
+test_domain_next_lcore_wrap(void)
+{
+       for (unsigned int d = 0; d < RTE_DIM(domain_types); d++) {
+               const unsigned int lcores_in_domain = 
rte_topo_get_domain_count(domain_types[d]);
+               for (unsigned int domain_index = 0; domain_index < 
lcores_in_domain;
+                       domain_index++) {
+                       unsigned int lcores_in_domain_index =
+                               
rte_topo_get_lcore_count_from_domain(domain_types[d],
+                                       domain_index);
+
+                       for (unsigned int i = 0; i < lcores_in_domain_index; 
i++) {
+                               const uint16_t curr_lcore =
+                                       
rte_topo_get_nth_lcore_from_domain(domain_index, i, 0,
+                                               domain_types[d]);
+                               const uint16_t wrap_lcore =
+                                       
rte_topo_get_nth_lcore_from_domain(domain_index,
+                                               lcores_in_domain_index + i, 1, 
domain_types[d]);
+
+                               RTE_TEST_ASSERT(curr_lcore == wrap_lcore,
+                                       "expected domain %s, lcore %u, wrapped 
lcore %u not same!",
+                                       (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,
+                                       curr_lcore, wrap_lcore);
+                       }
+               }
+       }
+
+       printf("INFO: wrap next lcore in domain test: success\n");
+       return TEST_SUCCESS;
+}
+
+
+static int
+test_multibit_domain_selector(void)
+{
+       const unsigned int bad_sel = RTE_TOPO_DOMAIN_L1 | RTE_TOPO_DOMAIN_L2;
+
+       unsigned int count;
+       unsigned int lcore;
+       rte_cpuset_t cpuset;
+
+       count = rte_topo_get_domain_count(bad_sel);
+       RTE_TEST_ASSERT(count == 0,
+               "Multi-bit selector should return 0 domains");
+
+       count = rte_topo_get_lcore_count_from_domain(bad_sel, 0);
+       RTE_TEST_ASSERT(count == 0,
+               "Multi-bit selector should return 0 lcores");
+
+       lcore = rte_topo_get_nth_lcore_in_domain(bad_sel, 0, 0);
+       RTE_TEST_ASSERT(lcore == RTE_MAX_LCORE,
+               "Multi-bit selector should return RTE_MAX_LCORE");
+
+#ifdef RTE_HAS_CPUSET
+       cpuset = rte_topo_get_lcore_cpuset_in_domain(bad_sel, 0);
+       RTE_TEST_ASSERT(CPU_COUNT(&cpuset) == 0,
+               "Multi-bit selector should return empty cpuset");
+#endif
+
+       printf("INFO: invalid domain select test: success\n");
+       return TEST_SUCCESS;
+}
+
+static int
+test_domain_lcore_round_trip(void)
+{
+       for (unsigned int d = 0; d < RTE_DIM(domain_types); d++) {
+               unsigned int dom_cnt = 
rte_topo_get_domain_count(domain_types[d]);
+
+               for (unsigned int i = 0; i < dom_cnt; i++) {
+                       unsigned int lcnt =
+                               
rte_topo_get_lcore_count_from_domain(domain_types[d], i);
+
+                       for (unsigned int p = 0; p < lcnt; p++) {
+                               uint16_t lcore =
+                                       
rte_topo_get_nth_lcore_in_domain(domain_types[d], i, p);
+
+                               int idx =
+                                       
rte_topo_get_domain_index_from_lcore(domain_types[d],
+                                               lcore);
+
+                               RTE_TEST_ASSERT(idx == (int)i,
+                                       "Round-trip mismatch: domain %u lcore 
%u -> idx %d",
+                                       i, lcore, idx);
+                       }
+               }
+       }
+
+       printf("INFO: lcore domain cross test: success\n");
+       return TEST_SUCCESS;
+}
+
+static int
+test_domain_lcore_ordering(void)
+{
+       unsigned int domain = RTE_TOPO_DOMAIN_L1;
+       if (rte_topo_get_domain_count(domain) == 0)
+               return TEST_SKIPPED;
+
+       unsigned int lcnt = rte_topo_get_lcore_count_from_domain(domain, 0);
+
+       uint16_t prev = 0;
+       bool first = true;
+
+       for (unsigned int i = 0; i < lcnt; i++) {
+               uint16_t cur = rte_topo_get_nth_lcore_in_domain(domain, 0, i);
+
+               if (!first)
+                       RTE_TEST_ASSERT(cur > prev, "Lcore ordering not 
strictly increasing");
+               first = false;
+               prev = cur;
+       }
+
+       printf("INFO: lcores ascending domain test: success\n");
+       return TEST_SUCCESS;
+}
+
+static int
+test_cpuset_matches_lcore_list(void)
+{
+#ifdef RTE_HAS_CPUSET
+       unsigned int domain = RTE_TOPO_DOMAIN_L1;
+       if (rte_topo_get_domain_count(domain) == 0)
+               return TEST_SKIPPED;
+
+       rte_cpuset_t cpuset = rte_topo_get_lcore_cpuset_in_domain(domain, 0);
+
+       unsigned int lcnt = rte_topo_get_lcore_count_from_domain(domain, 0);
+
+       for (unsigned int i = 0; i < lcnt; i++) {
+               int16_t lc = rte_topo_get_nth_lcore_in_domain(domain, 0, i);
+
+       RTE_TEST_ASSERT(CPU_ISSET(lc, &cpuset),
+               "Cpuset missing lcore %u", lc);
+       }
+
+       RTE_TEST_ASSERT(((unsigned int)CPU_COUNT(&cpuset) == lcnt), "Cpuset 
contains extra CPUs");
+
+       printf("INFO: cpuset lcore cross test: success\n");
+       return TEST_SUCCESS;
+#else
+       return TEST_SKIPPED;
+#endif
+}
+#endif
+
+static int
+test_topology_lcores(void)
+{
+#ifdef RTE_LIBHWLOC_PROBE
+       printf("\nTopology test\n");
+
+       printf("\nLcore dump mapped to topology\n");
+       rte_topo_dump(stdout);
+       printf("\n\n");
+
+       if (rte_lcore_count() == 1) {
+               RTE_LOG(INFO, USER1, "topology MACRO test requires more than 1 
core, skipping!\n");
+               return TEST_SKIPPED;
+       }
+
+       if (test_topology_macro() < 0)
+               return TEST_FAILED;
+
+       if (test_lcore_count_from_domain() < 0)
+               return TEST_FAILED;
+
+       if (test_lcore_from_domain_negative() < 0)
+               return TEST_FAILED;
+
+#ifdef RTE_HAS_CPUSET
+       if (test_lcore_cpuset_from_domain() < 0)
+               return TEST_FAILED;
+#endif
+
+       if (test_main_lcore_in_domain() < 0)
+               return TEST_FAILED;
+
+       if (test_wrap_with_skip_main_edge_case() < 0)
+               return TEST_FAILED;
+
+       if (test_invalid_domain_selector() < 0)
+               return TEST_FAILED;
+
+       if (test_multiple_invalid_inputs() < 0)
+               return TEST_FAILED;
+
+       if (test_large_index_values() < 0)
+               return TEST_FAILED;
+
+       if (test_domain_next_lcore_no_wrap() < 0)
+               return TEST_FAILED;
+
+       if (test_domain_next_lcore_wrap() < 0)
+               return TEST_FAILED;
+
+       if (test_multibit_domain_selector() < 0)
+               return TEST_FAILED;
+
+       if (test_domain_lcore_round_trip() < 0)
+               return TEST_FAILED;
+
+       if (test_domain_lcore_ordering() < 0)
+               return TEST_FAILED;
+
+       if (test_cpuset_matches_lcore_list() < 0)
+               return TEST_FAILED;
+#endif
+
+       return TEST_SUCCESS;
+}
+
+REGISTER_FAST_TEST(topology_autotest, NOHUGE_OK, ASAN_OK, 
test_topology_lcores);
-- 
2.43.0

Reply via email to