Skip to content

Commit 12d650c

Browse files
author
ndenoyelle
committed
Add functions for distributing objects of the topology
1 parent f71fb7e commit 12d650c

File tree

5 files changed

+656
-1
lines changed

5 files changed

+656
-1
lines changed

hwloc/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ sources = \
3333
distances.c \
3434
components.c \
3535
bind.c \
36+
distrib.c \
3637
bitmap.c \
3738
pci-common.c \
3839
diff.c \

hwloc/distrib.c

Lines changed: 336 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,336 @@
1+
/***************************************************************************
2+
* Copyright 2019 UChicago Argonne, LLC.
3+
* Author: Nicolas Denoyelle
4+
* SPDX-License-Identifier: BSD-3-Clause
5+
* See COPYING in top-level directory.
6+
****************************************************************************/
7+
8+
#include "private/autogen/config.h"
9+
#include "hwloc.h"
10+
11+
struct hwloc_distrib_level{
12+
hwloc_obj_type_t type; // level type.
13+
unsigned depth; // level depth.
14+
size_t user_index; // Index of this level as provided by user order.
15+
size_t arity; // Number of children of this level below parent.
16+
size_t coord; // The current level object index [0..arity[.
17+
// Iteration order of this level objects. index[coord] give logical_index below parent.
18+
size_t *index;
19+
};
20+
21+
struct hwloc_distrib_iterator{
22+
hwloc_obj_t *roots;
23+
size_t n_roots;
24+
size_t root_coord;
25+
struct hwloc_distrib_level ** levels; // n_roots * n_levels
26+
size_t n_levels;
27+
};
28+
29+
static size_t* range(const size_t n){
30+
size_t* r = malloc(n*sizeof(*r));
31+
32+
if(r==NULL) return NULL;
33+
for(size_t i=0; i<n; i++){ r[i] = i; }
34+
return r;
35+
}
36+
37+
static size_t* reversed_range(const size_t n){
38+
size_t* r = malloc(n*sizeof(*r));
39+
40+
if(r==NULL) return NULL;
41+
for(size_t i=0; i<n; i++){ r[i] = n-i-1; }
42+
return r;
43+
}
44+
45+
static size_t* shuffled_range(const size_t n){
46+
size_t i, *index, *ret, val;
47+
48+
if ((index = range(n)) == NULL) return NULL;
49+
if ((ret = malloc(n*sizeof(*ret))) == NULL) { free(index); return NULL; }
50+
51+
srand(time(NULL));
52+
for(i=n-1;i>=0;i--){
53+
val = rand()%(i+1);
54+
ret[i] = index[val];
55+
index[val] = index[i];
56+
}
57+
free(index);
58+
return ret;
59+
}
60+
61+
static int hwloc_distrib_level_cmp_depth(void *la, void* lb){
62+
struct hwloc_distrib_level *a = (struct hwloc_distrib_level *)la;
63+
struct hwloc_distrib_level *b = (struct hwloc_distrib_level *)lb;
64+
if(a->depth > b->depth) { return 1; }
65+
if(a->depth < b->depth) { return -1; }
66+
return 0;
67+
}
68+
69+
static int hwloc_distrib_level_cmp_user_index(void *la, void* lb){
70+
struct hwloc_distrib_level *a = (struct hwloc_distrib_level *)la;
71+
struct hwloc_distrib_level *b = (struct hwloc_distrib_level *)lb;
72+
if(a->user_index > b->user_index) { return 1; }
73+
if(a->user_index < b->user_index) { return -1; }
74+
return 0;
75+
}
76+
77+
static struct hwloc_distrib_level *
78+
hwloc_distrib_root_levels(hwloc_topology_t topology,
79+
const hwloc_obj_t root,
80+
const hwloc_obj_type_t *types,
81+
const size_t n_types,
82+
const unsigned long flags)
83+
{
84+
struct hwloc_distrib_level *levels = malloc(n_types * sizeof(*levels));
85+
if(levels == NULL)
86+
return NULL;
87+
88+
for (size_t i=0; i<n_types; i++){
89+
levels[i].type = types[i];
90+
levels[i].depth = hwloc_get_type_depth(topology, types[i]);
91+
if (levels[i].depth < 0 ){
92+
fprintf(stderr, "Cannot build iterator with objects %s of negative depth.\n",
93+
hwloc_obj_type_string(types[i]));
94+
goto failure;
95+
}
96+
levels[i].index = NULL;
97+
levels[i].coord = 0;
98+
levels[i].user_index = i;
99+
levels[i].arity = 0; // not set
100+
}
101+
102+
// Sort by depth to compute arities.
103+
qsort(levels,
104+
n_types,
105+
sizeof(*levels),
106+
(__compar_fn_t)hwloc_distrib_level_cmp_depth);
107+
108+
// Walk from top to bottom and set arity to the maximum arity below root field.
109+
size_t arity;
110+
hwloc_obj_t parent=root;
111+
for (size_t i=0; i<n_types; i++){
112+
while (parent) {
113+
arity = hwloc_get_nbobjs_inside_cpuset_by_depth(topology,
114+
parent->cpuset,
115+
levels[i].depth);
116+
levels[i].arity = arity > levels[i].arity ? arity : levels[i].arity;
117+
parent = hwloc_get_next_obj_inside_cpuset_by_depth(topology,
118+
root->cpuset,
119+
parent->depth, parent);
120+
}
121+
122+
if (levels[i].arity == 0) {
123+
fprintf(stderr, "No object of type %s below level %s.\n",
124+
hwloc_obj_type_string(levels[i].type),
125+
hwloc_obj_type_string(levels[i-1].type));
126+
goto failure;
127+
}
128+
129+
parent = hwloc_get_obj_inside_cpuset_by_depth(topology,
130+
root->cpuset,
131+
levels[i].depth,
132+
0);
133+
}
134+
135+
// Allocate levels index.
136+
for (size_t i=0; i<n_types; i++){
137+
if (flags & HWLOC_DISTRIB_FLAG_SHUFFLE) {
138+
levels[i].index = shuffled_range(levels[i].arity);
139+
}
140+
else if (flags & HWLOC_DISTRIB_FLAG_REVERSE) {
141+
levels[i].index = reversed_range(levels[i].arity);
142+
}
143+
else {
144+
levels[i].index = range(levels[i].arity);
145+
}
146+
if (levels[i].index == NULL) {
147+
while(i--){ free(levels[i].index); }
148+
goto failure;
149+
}
150+
}
151+
152+
return levels;
153+
154+
failure:
155+
free(levels);
156+
return NULL;
157+
}
158+
159+
static void hwloc_distrib_destroy_level(struct hwloc_distrib_level *levels){
160+
free(levels->index);
161+
free(levels);
162+
}
163+
164+
165+
struct hwloc_distrib_iterator *
166+
hwloc_distrib_build_iterator(hwloc_topology_t topology,
167+
hwloc_obj_t *roots,
168+
const size_t n_roots,
169+
const hwloc_obj_type_t *levels,
170+
const size_t n_levels,
171+
const unsigned long flags){
172+
173+
struct hwloc_distrib_iterator *it = malloc(sizeof(*it) +
174+
sizeof(*it->levels) * n_roots);
175+
if(it == NULL) return NULL;
176+
177+
it->roots = roots;
178+
it->n_roots = n_roots;
179+
it->root_coord = 0;
180+
it->n_levels = n_levels;
181+
it->levels = (struct hwloc_distrib_level **)((char*)it + sizeof(*it));
182+
183+
for(size_t i=0; i<n_roots; i++){
184+
it->levels[i] = hwloc_distrib_root_levels(topology, roots[i], levels, n_levels, flags);
185+
if(it->levels[i] == NULL){
186+
while(i--){ hwloc_distrib_destroy_level(it->levels[i]); }
187+
goto failure;
188+
}
189+
}
190+
191+
return it;
192+
193+
failure:
194+
free(it);
195+
return NULL;
196+
}
197+
198+
HWLOC_DECLSPEC struct hwloc_distrib_iterator *
199+
hwloc_distrib_iterator_round_robin(hwloc_topology_t topology,
200+
const hwloc_obj_type_t type,
201+
const unsigned long flags){
202+
hwloc_obj_t root = hwloc_get_obj_by_depth(topology, 0, 0);
203+
struct hwloc_distrib_iterator *it = malloc(sizeof(*it) +
204+
sizeof(hwloc_obj_t) +
205+
sizeof(struct hwloc_distrib_level*));
206+
if(it == NULL) return NULL;
207+
208+
it->roots = (hwloc_obj_t*) ((char*)it + sizeof(*it));
209+
*it->roots = root;
210+
it->n_roots = 1;
211+
it->root_coord = 0;
212+
it->n_levels = 1;
213+
it->levels = (struct hwloc_distrib_level **)((char*)it +
214+
sizeof(*it) +
215+
sizeof(hwloc_obj_t));
216+
*it->levels = hwloc_distrib_root_levels(topology, root, &type, 1, flags);
217+
218+
if (*it->levels == NULL){ free(it); return NULL; }
219+
return it;
220+
}
221+
222+
HWLOC_DECLSPEC struct hwloc_distrib_iterator *
223+
hwloc_distrib_iterator_scatter(hwloc_topology_t topology,
224+
const hwloc_obj_type_t type,
225+
const unsigned long flags){
226+
227+
size_t i=0, n=0;
228+
hwloc_obj_t obj, root = hwloc_get_obj_by_depth(topology, 0, 0);
229+
obj = root;
230+
231+
// Count depths with a non empty cpuset.
232+
while(obj){
233+
if ((obj->cpuset != NULL && !hwloc_bitmap_iszero(obj->cpuset)) &&
234+
hwloc_get_type_depth(topology, obj->type) >= 0)
235+
n++;
236+
obj = obj->first_child;
237+
}
238+
239+
obj = root;
240+
hwloc_obj_type_t levels[n];
241+
// fill levels array.
242+
while(obj){
243+
if( obj->cpuset != NULL && !hwloc_bitmap_iszero(obj->cpuset) &&
244+
hwloc_get_type_depth(topology, obj->type) >= 0){
245+
levels[n-1-i] = obj->type;
246+
i++;
247+
}
248+
obj = obj->first_child;
249+
}
250+
251+
struct hwloc_distrib_iterator *it = malloc(sizeof(*it) +
252+
sizeof(hwloc_obj_t) +
253+
sizeof(struct hwloc_distrib_level*));
254+
if(it == NULL) return NULL;
255+
256+
it->roots = (hwloc_obj_t*) ((char*)it + sizeof(*it));
257+
*it->roots = root;
258+
it->n_roots = 1;
259+
it->root_coord = 0;
260+
it->n_levels = 1;
261+
it->levels = (struct hwloc_distrib_level **)((char*)it +
262+
sizeof(*it) +
263+
sizeof(hwloc_obj_t));
264+
265+
*it->levels = hwloc_distrib_root_levels(topology, root, levels, n, flags);
266+
267+
if (*it->levels == NULL){ free(it); return NULL; }
268+
return it;
269+
}
270+
271+
void hwloc_distrib_destroy_iterator(struct hwloc_distrib_iterator *it){
272+
for(size_t i=0; i<it->n_roots; i++)
273+
hwloc_distrib_destroy_level(it->levels[i]);
274+
free(it);
275+
}
276+
277+
// Increment coordinates by one. Return 1 if iterator reached end and reset it.
278+
// Else return 0.
279+
static int
280+
hwloc_distrib_iterator_inc(struct hwloc_distrib_iterator *it){
281+
int i;
282+
struct hwloc_distrib_level *levels;
283+
284+
do_root:
285+
// Sort by user_index to increment coordinates.
286+
levels = it->levels[it->root_coord];
287+
qsort(levels,
288+
it->n_levels,
289+
sizeof(*levels),
290+
(__compar_fn_t)hwloc_distrib_level_cmp_user_index);
291+
292+
for (i=it->n_levels-1; i>=0; i--){
293+
if(++levels[i].coord >= levels[i].arity)
294+
levels[i].coord = 0;
295+
else
296+
break;
297+
}
298+
if(i < 0 && levels[0].coord == 0){
299+
if (++it->root_coord == it->n_roots){
300+
it->root_coord = 0;
301+
return 0;
302+
} else {
303+
goto do_root;
304+
}
305+
}
306+
return 1;
307+
}
308+
309+
int
310+
hwloc_distrib_iterator_next(hwloc_topology_t topology,
311+
struct hwloc_distrib_iterator *it,
312+
hwloc_obj_t *next){
313+
struct hwloc_distrib_level *levels = it->levels[it->root_coord];
314+
hwloc_obj_t obj = it->roots[it->root_coord];
315+
size_t coord;
316+
317+
// Sort by depth to walk objects at set coordinates.
318+
qsort(levels,
319+
it->n_levels,
320+
sizeof(*levels),
321+
(__compar_fn_t)hwloc_distrib_level_cmp_depth);
322+
323+
for(size_t i=0; i<it->n_levels; i++){
324+
coord = levels[i].index[levels[i].coord];
325+
obj = hwloc_get_obj_inside_cpuset_by_depth(topology,
326+
obj->cpuset,
327+
levels[i].depth,
328+
coord);
329+
if( obj == NULL)
330+
return hwloc_distrib_iterator_inc(it) && hwloc_distrib_iterator_next(topology, it, next);
331+
332+
}
333+
334+
*next = obj;
335+
return hwloc_distrib_iterator_inc(it);
336+
}

0 commit comments

Comments
 (0)