1 /*
2 * Copyright © 2016-2018 Inria. All rights reserved.
3 *
4 * $COPYRIGHT$
5 *
6 * Additional copyrights may follow
7 * See COPYING in top-level directory.
8 *
9 * $HEADER$
10 */
11
12 #define _GNU_SOURCE /* See feature_test_macros(7) */
13
14 #include <sys/types.h>
15 #include <dirent.h>
16 #include <libgen.h>
17
18 #include <private/netloc.h>
19 #include <netloc.h>
20 #include <hwloc.h>
21
22 static UT_icd topos_icd = {sizeof(hwloc_topology_t), NULL, NULL, NULL};
23
netloc_topology_read_hwloc(netloc_topology_t * topology,int num_nodes,netloc_node_t ** node_list)24 int netloc_topology_read_hwloc(netloc_topology_t *topology, int num_nodes,
25 netloc_node_t **node_list)
26 {
27 int ret = 0;
28 int all = 0;
29
30 char *hwloc_path;
31
32 if (!topology->hwlocpath) {
33 printf("No hwloc directory recorded in the topology\n");
34 return NETLOC_ERROR;
35 }
36
37 if (topology->hwlocpath[0] != '/') {
38 char *path_tmp = strdup(topology->topopath);
39 asprintf(&hwloc_path, "%s/%s", dirname(path_tmp), topology->hwlocpath);
40 free(path_tmp);
41 } else {
42 hwloc_path = strdup(topology->hwlocpath);
43 }
44
45 DIR* dir = opendir(hwloc_path);
46 /* Directory does not exist */
47 if (!dir) {
48 printf("Directory (%s) to hwloc does not exist\n", hwloc_path);
49 free(hwloc_path);
50 return NETLOC_ERROR;
51 }
52 else {
53 closedir(dir);
54 }
55
56 UT_array *hwloc_topo_names = topology->topos;
57 UT_array *hwloc_topos;
58 utarray_new(hwloc_topos, &topos_icd);
59
60 int num_diffs = 0;
61
62 if (!num_nodes) {
63 netloc_node_t *node, *node_tmp;
64 num_nodes = HASH_COUNT(topology->nodes);
65 node_list = (netloc_node_t **)malloc(sizeof(netloc_node_t *[num_nodes]));
66 int n = 0;
67 netloc_topology_iter_nodes(topology, node, node_tmp) {
68 node_list[n++] = node;
69 }
70 all = 1;
71 }
72
73 for (int n = 0; n < num_nodes; n++) {
74 netloc_node_t *node = node_list[n];
75 char *hwloc_file;
76 char *refname;
77
78 if (netloc_node_is_switch(node))
79 continue;
80
81 /* We try to find a diff file */
82 asprintf(&hwloc_file, "%s/%s.diff.xml", hwloc_path, node->hostname);
83 hwloc_topology_diff_t diff;
84 int err;
85 if ((err = hwloc_topology_diff_load_xml(hwloc_file, &diff, &refname)) >= 0) {
86 refname[strlen(refname)-4] = '\0';
87 hwloc_topology_diff_destroy(diff);
88 num_diffs++;
89 }
90 else {
91 free(hwloc_file);
92 /* We try to find a regular file */
93 asprintf(&hwloc_file, "%s/%s.xml", hwloc_path, node->hostname);
94 FILE *fxml;
95 if (!(fxml = fopen(hwloc_file, "r"))) {
96 printf("Missing hwloc file: %s\n", hwloc_file);
97 }
98 else
99 fclose(fxml);
100 asprintf(&refname, "%s", node->hostname);
101 }
102
103 /* Add the hwloc topology */
104 unsigned int t = 0;
105 while (t < utarray_len(hwloc_topo_names) &&
106 strcmp(*(char **)utarray_eltptr(hwloc_topo_names, t), refname)) {
107 t++;
108 }
109 /* Topology not found */
110 if (t == utarray_len(hwloc_topo_names)) {
111 utarray_push_back(hwloc_topo_names, &refname);
112
113 /* Read the hwloc topology */
114 hwloc_topology_t topology;
115 hwloc_topology_init(&topology);
116 hwloc_topology_set_flags(topology, HWLOC_TOPOLOGY_FLAG_INCLUDE_DISALLOWED);
117
118 char *hwloc_ref_path;
119 asprintf(&hwloc_ref_path, "%s/%s.xml", hwloc_path, refname);
120 ret = hwloc_topology_set_xml(topology, hwloc_ref_path);
121 free(hwloc_ref_path);
122 if (ret == -1) {
123 void *null = NULL;
124 utarray_push_back(hwloc_topos, &null);
125 fprintf(stdout, "Warning: no topology for %s\n", refname);
126 hwloc_topology_destroy(topology);
127 free(refname); free(hwloc_file);
128 continue;
129 }
130
131 ret = hwloc_topology_set_all_types_filter(topology, HWLOC_TYPE_FILTER_KEEP_STRUCTURE);
132 if (ret == -1) {
133 fprintf(stderr, "hwloc_topology_set_all_types_filter failed\n");
134 free(refname); free(hwloc_file);
135 goto ERROR;
136 }
137
138 ret = hwloc_topology_set_io_types_filter(topology, HWLOC_TYPE_FILTER_KEEP_NONE);
139 if (ret == -1) {
140 fprintf(stderr, "hwloc_topology_set_all_types_filter failed\n");
141 free(refname); free(hwloc_file);
142 goto ERROR;
143 }
144
145 ret = hwloc_topology_load(topology);
146 if (ret == -1) {
147 fprintf(stderr, "hwloc_topology_load failed\n");
148 free(refname); free(hwloc_file);
149 goto ERROR;
150 }
151 utarray_push_back(hwloc_topos, &topology);
152 }
153 free(refname);
154 free(hwloc_file);
155 node->hwlocTopo = *(hwloc_topology_t *)utarray_eltptr(hwloc_topos, t);
156 node->hwlocTopoIdx = t;
157 }
158
159 if (!num_diffs) {
160 printf("Warning: no hwloc diff file found!\n");
161 }
162
163 topology->topos = hwloc_topo_names;
164 topology->hwloc_topos = (hwloc_topology_t *)hwloc_topos->d;
165
166 printf("%d hwloc topologies found:\n", utarray_len(topology->topos));
167 for (unsigned int p = 0; p < utarray_len(topology->topos); p++) {
168 printf("\t'%s'\n", *(char **)utarray_eltptr(topology->topos, p));
169 }
170
171 ret = NETLOC_SUCCESS;
172
173 ERROR:
174 if (all) {
175 free(node_list);
176 }
177 free(hwloc_path);
178 if (ret == NETLOC_SUCCESS)
179 free(hwloc_topos);
180 else
181 utarray_free(hwloc_topos);
182 return ret;
183 }
184
185 /* Set the info from hwloc of the node in the correspondig arch */
netloc_arch_node_get_hwloc_info(netloc_arch_node_t * arch_node)186 int netloc_arch_node_get_hwloc_info(netloc_arch_node_t *arch_node)
187 {
188 hwloc_topology_t topology = arch_node->node->hwlocTopo;
189
190 hwloc_obj_t root = hwloc_get_root_obj(topology);
191
192 int depth = hwloc_topology_get_depth(topology);
193 hwloc_obj_t first_object = root->first_child;
194
195 UT_array **down_degrees_by_level;
196 NETLOC_int *max_down_degrees_by_level;
197
198 down_degrees_by_level = (UT_array **)malloc(depth*sizeof(UT_array *));
199 for (int l = 0; l < depth; l++) {
200 utarray_new(down_degrees_by_level[l], &ut_int_icd);
201 }
202 max_down_degrees_by_level = (NETLOC_int *)
203 calloc(depth-1, sizeof(NETLOC_int));
204
205 int level = depth-1;
206 hwloc_obj_t current_object = first_object;
207 while (level >= 1) {
208 int degree = 1;
209 /* we go through the siblings */
210 while (current_object->next_sibling) {
211 current_object = current_object->next_sibling;
212 degree++;
213 }
214 /* Add the degree to the list of degrees */
215 utarray_push_back(down_degrees_by_level[depth-1-level], °ree);
216 max_down_degrees_by_level[depth-1-level] =
217 max_down_degrees_by_level[depth-1-level] > degree ?
218 max_down_degrees_by_level[depth-1-level] : degree;
219
220 current_object = current_object->next_cousin;
221
222 if (!current_object) {
223 level--;
224 if (!first_object->first_child)
225 break;
226 first_object = first_object->first_child;
227 current_object = first_object;
228 }
229 }
230
231 /* List of PUs */
232 unsigned int max_os_index = 0;
233 UT_array *ordered_host_array;
234 int *ordered_hosts;
235 utarray_new(ordered_host_array, &ut_int_icd);
236 current_object = first_object;
237 while (current_object) {
238 max_os_index = (max_os_index >= current_object->os_index)?
239 max_os_index: current_object->os_index;
240 utarray_push_back(ordered_host_array, ¤t_object->os_index);
241 current_object = current_object->next_cousin;
242 }
243 ordered_hosts = (int *)ordered_host_array->d;;
244
245 /* Weight for the edges in the tree */
246 NETLOC_int *cost = (NETLOC_int *)malloc((depth-1)*sizeof(NETLOC_int));
247 int level_coeff = 3;
248 cost[depth-2] = 1;
249 for (int l = depth-3; l >= 0; l--) {
250 cost[l] = cost[l+1]*level_coeff;
251 }
252
253 netloc_arch_tree_t *tree = (netloc_arch_tree_t *)
254 malloc(sizeof(netloc_arch_tree_t));
255 tree->num_levels = depth-1;
256 tree->degrees = max_down_degrees_by_level;
257 tree->cost = cost;
258
259 int *arch_idx;
260 int num_cores = utarray_len(ordered_host_array);
261 netloc_arch_tree_complete(tree, down_degrees_by_level, num_cores, &arch_idx);
262
263 int *slot_idx = (int *)malloc(sizeof(int[max_os_index+1]));
264 for (int i = 0; i < num_cores; i++) {
265 slot_idx[ordered_hosts[i]] = arch_idx[i];
266 }
267
268 int num_leaves = netloc_arch_tree_num_leaves(tree);
269 int *slot_os_idx = (int *)malloc(sizeof(int[num_leaves]));
270 for (int i = 0; i < num_cores; i++) {
271 slot_os_idx[arch_idx[i]] = ordered_hosts[i];
272 }
273 free(arch_idx);
274
275 arch_node->slot_tree = tree;
276 arch_node->slot_idx = slot_idx;
277 arch_node->slot_os_idx = slot_os_idx;
278 arch_node->num_slots = max_os_index+1;
279
280 for (int l = 0; l < depth; l++) {
281 utarray_free(down_degrees_by_level[l]);
282 }
283 free(down_degrees_by_level);
284
285 utarray_free(ordered_host_array);
286
287 return NETLOC_SUCCESS;
288 }
289