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], &degree);
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, &current_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