@@ -1936,8 +1936,23 @@ hwloc__xml_export_object_contents (hwloc__xml_export_state_t state, hwloc_topolo
19361936 }
19371937
19381938 if (obj -> cpuset ) {
1939- if (v1export && obj -> type == HWLOC_OBJ_NUMANODE && obj -> sibling_rank > 0 ) {
1940- /* v1 non-first NUMA nodes have empty cpusets */
1939+ int empty_cpusets = 0 ;
1940+
1941+ if (v1export && obj -> type == HWLOC_OBJ_NUMANODE ) {
1942+ /* walk up this memory hierarchy to find-out if we are the first numa node.
1943+ * v1 non-first NUMA nodes have empty cpusets.
1944+ */
1945+ hwloc_obj_t parent = obj ;
1946+ while (!hwloc_obj_type_is_normal (parent -> type )) {
1947+ if (parent -> sibling_rank > 0 ) {
1948+ empty_cpusets = 1 ;
1949+ break ;
1950+ }
1951+ parent = parent -> parent ;
1952+ }
1953+ }
1954+
1955+ if (empty_cpusets ) {
19411956 state -> new_prop (state , "cpuset" , "0x0" );
19421957 state -> new_prop (state , "online_cpuset" , "0x0" );
19431958 state -> new_prop (state , "complete_cpuset" , "0x0" );
@@ -2216,13 +2231,90 @@ hwloc__xml_v2export_object (hwloc__xml_export_state_t parentstate, hwloc_topolog
22162231static void
22172232hwloc__xml_v1export_object (hwloc__xml_export_state_t parentstate , hwloc_topology_t topology , hwloc_obj_t obj , unsigned long flags );
22182233
2234+ static hwloc_obj_t
2235+ hwloc__xml_v1export_object_next_numanode (hwloc_obj_t obj , hwloc_obj_t cur )
2236+ {
2237+ hwloc_obj_t parent ;
2238+
2239+ if (!cur ) {
2240+ /* first numa node is on the very bottom left */
2241+ cur = obj -> memory_first_child ;
2242+ goto find_first ;
2243+ }
2244+
2245+ /* walk-up until there's a next sibling */
2246+ parent = cur ;
2247+ while (1 ) {
2248+ if (parent -> next_sibling ) {
2249+ /* found a next sibling, we'll walk down-left from there */
2250+ cur = parent -> next_sibling ;
2251+ break ;
2252+ }
2253+ parent = parent -> parent ;
2254+ if (parent == obj )
2255+ return NULL ;
2256+ }
2257+
2258+ find_first :
2259+ while (cur -> type != HWLOC_OBJ_NUMANODE )
2260+ cur = cur -> memory_first_child ;
2261+ assert (cur );
2262+ return cur ;
2263+ }
2264+
2265+ static unsigned
2266+ hwloc__xml_v1export_object_list_numanodes (hwloc_obj_t obj , hwloc_obj_t * first_p , hwloc_obj_t * * nodes_p )
2267+ {
2268+ hwloc_obj_t * nodes , cur ;
2269+ unsigned nr ;
2270+
2271+ if (!obj -> memory_first_child ) {
2272+ * first_p = NULL ;
2273+ * nodes_p = NULL ;
2274+ return 0 ;
2275+ }
2276+ /* we're sure there's at least one numa node */
2277+
2278+ nr = hwloc_bitmap_weight (obj -> nodeset );
2279+ assert (nr > 0 );
2280+ /* these are local nodes, but some of them may be attached above instead of here */
2281+
2282+ nodes = calloc (nr , sizeof (* nodes ));
2283+ if (!nodes ) {
2284+ /* only return the first node */
2285+ cur = hwloc__xml_v1export_object_next_numanode (obj , NULL );
2286+ assert (cur );
2287+ * first_p = cur ;
2288+ * nodes_p = NULL ;
2289+ return 1 ;
2290+ }
2291+
2292+ nr = 0 ;
2293+ cur = NULL ;
2294+ while (1 ) {
2295+ cur = hwloc__xml_v1export_object_next_numanode (obj , cur );
2296+ if (!cur )
2297+ break ;
2298+ nodes [nr ++ ] = cur ;
2299+ }
2300+
2301+ * first_p = nodes [0 ];
2302+ * nodes_p = nodes ;
2303+ return nr ;
2304+ }
2305+
22192306static void
22202307hwloc__xml_v1export_object_with_memory (hwloc__xml_export_state_t parentstate , hwloc_topology_t topology , hwloc_obj_t obj , unsigned long flags )
22212308{
22222309 struct hwloc__xml_export_state_s gstate , mstate , ostate , * state = parentstate ;
22232310 hwloc_obj_t child ;
2311+ unsigned nr_numanodes ;
2312+ hwloc_obj_t * numanodes , first_numanode ;
2313+ unsigned i ;
22242314
2225- if (obj -> parent -> arity > 1 && obj -> memory_arity > 1 && parentstate -> global -> v1_memory_group ) {
2315+ nr_numanodes = hwloc__xml_v1export_object_list_numanodes (obj , & first_numanode , & numanodes );
2316+
2317+ if (obj -> parent -> arity > 1 && nr_numanodes > 1 && parentstate -> global -> v1_memory_group ) {
22262318 /* child has sibling, we must add a Group around those memory children */
22272319 hwloc_obj_t group = parentstate -> global -> v1_memory_group ;
22282320 parentstate -> new_child (parentstate , & gstate , "object" );
@@ -2239,10 +2331,8 @@ hwloc__xml_v1export_object_with_memory(hwloc__xml_export_state_t parentstate, hw
22392331 }
22402332
22412333 /* export first memory child */
2242- child = obj -> memory_first_child ;
2243- assert (child -> type == HWLOC_OBJ_NUMANODE );
22442334 state -> new_child (state , & mstate , "object" );
2245- hwloc__xml_export_object_contents (& mstate , topology , child , flags );
2335+ hwloc__xml_export_object_contents (& mstate , topology , first_numanode , flags );
22462336
22472337 /* then the actual object */
22482338 mstate .new_child (& mstate , & ostate , "object" );
@@ -2261,9 +2351,10 @@ hwloc__xml_v1export_object_with_memory(hwloc__xml_export_state_t parentstate, hw
22612351 mstate .end_object (& mstate , "object" );
22622352
22632353 /* now other memory children */
2264- for_each_memory_child (child , obj )
2265- if (child -> sibling_rank > 0 )
2266- hwloc__xml_v1export_object (state , topology , child , flags );
2354+ for (i = 1 ; i < nr_numanodes ; i ++ )
2355+ hwloc__xml_v1export_object (state , topology , numanodes [i ], flags );
2356+
2357+ free (numanodes );
22672358
22682359 if (state == & gstate ) {
22692360 /* close group if any */
@@ -2351,18 +2442,22 @@ hwloc__xml_export_topology(hwloc__xml_export_state_t state, hwloc_topology_t top
23512442 hwloc_obj_t root = hwloc_get_root_obj (topology );
23522443
23532444 if (flags & HWLOC_TOPOLOGY_EXPORT_XML_FLAG_V1 ) {
2354- if (root -> memory_first_child ) {
2445+ hwloc_obj_t * numanodes , first_numanode ;
2446+ unsigned nr_numanodes ;
2447+
2448+ nr_numanodes = hwloc__xml_v1export_object_list_numanodes (root , & first_numanode , & numanodes );
2449+
2450+ if (nr_numanodes ) {
23552451 /* we don't use hwloc__xml_v1export_object_with_memory() because we want/can keep root above the numa node */
23562452 struct hwloc__xml_export_state_s rstate , mstate ;
23572453 hwloc_obj_t child ;
2454+ unsigned i ;
23582455 /* export the root */
23592456 state -> new_child (state , & rstate , "object" );
23602457 hwloc__xml_export_object_contents (& rstate , topology , root , flags );
23612458 /* export first memory child */
2362- child = root -> memory_first_child ;
2363- assert (child -> type == HWLOC_OBJ_NUMANODE );
23642459 rstate .new_child (& rstate , & mstate , "object" );
2365- hwloc__xml_export_object_contents (& mstate , topology , child , flags );
2460+ hwloc__xml_export_object_contents (& mstate , topology , first_numanode , flags );
23662461 /* then its normal/io/misc children */
23672462 for_each_child (child , root )
23682463 hwloc__xml_v1export_object (& mstate , topology , child , flags );
@@ -2373,15 +2468,16 @@ hwloc__xml_export_topology(hwloc__xml_export_state_t state, hwloc_topology_t top
23732468 /* close first memory child */
23742469 mstate .end_object (& mstate , "object" );
23752470 /* now other memory children */
2376- for_each_memory_child (child , root )
2377- if (child -> sibling_rank > 0 )
2378- hwloc__xml_v1export_object (& rstate , topology , child , flags );
2471+ for (i = 1 ; i < nr_numanodes ; i ++ )
2472+ hwloc__xml_v1export_object (& rstate , topology , numanodes [i ], flags );
23792473 /* close the root */
23802474 rstate .end_object (& rstate , "object" );
23812475 } else {
23822476 hwloc__xml_v1export_object (state , topology , root , flags );
23832477 }
23842478
2479+ free (numanodes );
2480+
23852481 } else {
23862482 hwloc__xml_v2export_object (state , topology , root , flags );
23872483 hwloc__xml_v2export_distances (state , topology );
0 commit comments