1 /*
2  * Copyright © 2009      CNRS
3  * Copyright © 2009-2011 inria.  All rights reserved.
4  * Copyright © 2009-2012 Université Bordeaux 1
5  * Copyright © 2009-2011 Cisco Systems, Inc.  All rights reserved.
6  *
7  * See COPYING in top-level directory.
8  */
9 
10 /* Internal types and helpers. */
11 
12 #ifndef HWLOC_PRIVATE_H
13 #define HWLOC_PRIVATE_H
14 
15 #include <private/autogen/config.h>
16 #include <hwloc.h>
17 #include <hwloc/bitmap.h>
18 #include <private/debug.h>
19 #include <sys/types.h>
20 #ifdef HAVE_STDINT_H
21 #include <stdint.h>
22 #endif
23 #ifdef HAVE_SYS_UTSNAME_H
24 #include <sys/utsname.h>
25 #endif
26 #include <string.h>
27 
28 #if defined(HAVE_GETPAGESIZE) && defined(NEEDS_GETPAGESIZE_DECL)
29 int getpagesize(void);
30 #endif
31 
32 #ifdef HWLOC_HAVE_ATTRIBUTE_FORMAT
33 # if HWLOC_HAVE_ATTRIBUTE_FORMAT
34 #  define __hwloc_attribute_format(type, str, arg)  __attribute__((__format__(type, str, arg)))
35 # else
36 #  define __hwloc_attribute_format(type, str, arg)
37 # endif
38 #else
39 # define __hwloc_attribute_format(type, str, arg)
40 #endif
41 
42 enum hwloc_ignore_type_e {
43   HWLOC_IGNORE_TYPE_NEVER = 0,
44   HWLOC_IGNORE_TYPE_KEEP_STRUCTURE,
45   HWLOC_IGNORE_TYPE_ALWAYS
46 };
47 
48 #define HWLOC_DEPTH_MAX 128
49 
50 typedef enum hwloc_backend_e {
51   HWLOC_BACKEND_NONE,
52   HWLOC_BACKEND_SYNTHETIC,
53 #ifdef HWLOC_LINUX_SYS
54   HWLOC_BACKEND_LINUXFS,
55 #endif
56   HWLOC_BACKEND_XML,
57   HWLOC_BACKEND_CUSTOM,
58   /* This value is only here so that we can end the enum list without
59      a comma (thereby preventing compiler warnings) */
60   HWLOC_BACKEND_MAX
61 } hwloc_backend_t;
62 
63 struct hwloc__xml_import_state_s;
64 
65 struct hwloc_topology {
66   unsigned nb_levels;					/* Number of horizontal levels */
67   unsigned next_group_depth;				/* Depth of the next Group object that we may create */
68   unsigned level_nbobjects[HWLOC_DEPTH_MAX]; 		/* Number of objects on each horizontal level */
69   struct hwloc_obj **levels[HWLOC_DEPTH_MAX];		/* Direct access to levels, levels[l = 0 .. nblevels-1][0..level_nbobjects[l]] */
70   unsigned long flags;
71   int type_depth[HWLOC_OBJ_TYPE_MAX];
72   enum hwloc_ignore_type_e ignored_types[HWLOC_OBJ_TYPE_MAX];
73   int is_thissystem;
74   int is_loaded;
75   hwloc_pid_t pid;                                      /* Process ID the topology is view from, 0 for self */
76 
77   unsigned bridge_nbobjects;
78   struct hwloc_obj **bridge_level;
79   struct hwloc_obj *first_bridge, *last_bridge;
80   unsigned pcidev_nbobjects;
81   struct hwloc_obj **pcidev_level;
82   struct hwloc_obj *first_pcidev, *last_pcidev;
83   unsigned osdev_nbobjects;
84   struct hwloc_obj **osdev_level;
85   struct hwloc_obj *first_osdev, *last_osdev;
86 
87   int (*set_thisproc_cpubind)(hwloc_topology_t topology, hwloc_const_cpuset_t set, int flags);
88   int (*get_thisproc_cpubind)(hwloc_topology_t topology, hwloc_cpuset_t set, int flags);
89   int (*set_thisthread_cpubind)(hwloc_topology_t topology, hwloc_const_cpuset_t set, int flags);
90   int (*get_thisthread_cpubind)(hwloc_topology_t topology, hwloc_cpuset_t set, int flags);
91   int (*set_proc_cpubind)(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_const_cpuset_t set, int flags);
92   int (*get_proc_cpubind)(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_cpuset_t set, int flags);
93 #ifdef hwloc_thread_t
94   int (*set_thread_cpubind)(hwloc_topology_t topology, hwloc_thread_t tid, hwloc_const_cpuset_t set, int flags);
95   int (*get_thread_cpubind)(hwloc_topology_t topology, hwloc_thread_t tid, hwloc_cpuset_t set, int flags);
96 #endif
97 
98   int (*get_thisproc_last_cpu_location)(hwloc_topology_t topology, hwloc_cpuset_t set, int flags);
99   int (*get_thisthread_last_cpu_location)(hwloc_topology_t topology, hwloc_cpuset_t set, int flags);
100   int (*get_proc_last_cpu_location)(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_cpuset_t set, int flags);
101 
102   int (*set_thisproc_membind)(hwloc_topology_t topology, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags);
103   int (*get_thisproc_membind)(hwloc_topology_t topology, hwloc_nodeset_t nodeset, hwloc_membind_policy_t * policy, int flags);
104   int (*set_thisthread_membind)(hwloc_topology_t topology, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags);
105   int (*get_thisthread_membind)(hwloc_topology_t topology, hwloc_nodeset_t nodeset, hwloc_membind_policy_t * policy, int flags);
106   int (*set_proc_membind)(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags);
107   int (*get_proc_membind)(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_nodeset_t nodeset, hwloc_membind_policy_t * policy, int flags);
108   int (*set_area_membind)(hwloc_topology_t topology, const void *addr, size_t len, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags);
109   int (*get_area_membind)(hwloc_topology_t topology, const void *addr, size_t len, hwloc_nodeset_t nodeset, hwloc_membind_policy_t * policy, int flags);
110   /* This has to return the same kind of pointer as alloc_membind, so that free_membind can be used on it */
111   void *(*alloc)(hwloc_topology_t topology, size_t len);
112   /* alloc_membind has to always succeed if !(flags & HWLOC_MEMBIND_STRICT).
113    * see hwloc_alloc_or_fail which is convenient for that.  */
114   void *(*alloc_membind)(hwloc_topology_t topology, size_t len, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags);
115   int (*free_membind)(hwloc_topology_t topology, void *addr, size_t len);
116 
117   struct hwloc_topology_support support;
118 
119   struct hwloc_os_distances_s {
120     hwloc_obj_type_t type;
121     int nbobjs;
122     unsigned *indexes; /* array of OS indexes before we can convert them into objs. always available.
123 			*/
124     struct hwloc_obj **objs; /* array of objects, in the same order as above.
125 			      * either given (by a backend) together with the indexes array above.
126 			      * or build from the above indexes array when not given (by the user).
127 			      */
128     float *distances; /* distance matrices, ordered according to the above indexes/objs array.
129 		       * distance from i to j is stored in slot i*nbnodes+j.
130 		       * will be copied into the main logical-index-ordered distance at the end of the discovery.
131 		       */
132     int forced; /* set if the user forced a matrix to ignore the OS one */
133 
134     struct hwloc_os_distances_s *prev, *next;
135   } *first_osdist, *last_osdist;
136 
137   hwloc_backend_t backend_type;
138   union hwloc_backend_params_u {
139 #ifdef HWLOC_LINUX_SYS
140     struct hwloc_backend_params_linuxfs_s {
141       /* FS root parameters */
142       char *root_path; /* The path of the file system root, used when browsing, e.g., Linux' sysfs and procfs. */
143       int root_fd; /* The file descriptor for the file system root, used when browsing, e.g., Linux' sysfs and procfs. */
144       struct utsname utsname; /* cached result of uname, used multiple times */
145     } linuxfs;
146 #endif /* HWLOC_LINUX_SYS */
147 #if defined(HWLOC_OSF_SYS) || defined(HWLOC_COMPILE_PORTS)
148     struct hwloc_backend_params_osf {
149       int nbnodes;
150     } osf;
151 #endif /* HWLOC_OSF_SYS */
152     struct hwloc_backend_params_xml_s {
153       /* xml backend parameters */
154       int (*look)(struct hwloc_topology *topology, struct hwloc__xml_import_state_s *state);
155       void (*look_failed)(struct hwloc_topology *topology);
156       void (*backend_exit)(struct hwloc_topology *topology);
157       void *data; /* libxml2 doc, or nolibxml buffer */
158       struct hwloc_xml_imported_distances_s {
159 	hwloc_obj_t root;
160 	struct hwloc_distances_s distances;
161 	struct hwloc_xml_imported_distances_s *prev, *next;
162       } *first_distances, *last_distances;
163     } xml;
164     struct hwloc_backend_params_synthetic_s {
165       /* synthetic backend parameters */
166       char *string;
167 #define HWLOC_SYNTHETIC_MAX_DEPTH 128
168       unsigned arity[HWLOC_SYNTHETIC_MAX_DEPTH];
169       hwloc_obj_type_t type[HWLOC_SYNTHETIC_MAX_DEPTH];
170       unsigned id[HWLOC_SYNTHETIC_MAX_DEPTH];
171       unsigned depth[HWLOC_SYNTHETIC_MAX_DEPTH]; /* For cache/misc */
172     } synthetic;
173   } backend_params;
174 };
175 
176 
177 extern void hwloc_setup_pu_level(struct hwloc_topology *topology, unsigned nb_pus);
178 extern int hwloc_get_sysctlbyname(const char *name, int64_t *n);
179 extern int hwloc_get_sysctl(int name[], unsigned namelen, int *n);
180 extern unsigned hwloc_fallback_nbprocessors(struct hwloc_topology *topology);
181 extern void hwloc_connect_children(hwloc_obj_t obj);
182 extern int hwloc_connect_levels(hwloc_topology_t topology);
183 
184 
185 #if defined(HWLOC_LINUX_SYS)
186 extern void hwloc_look_linuxfs(struct hwloc_topology *topology);
187 extern void hwloc_set_linuxfs_hooks(struct hwloc_topology *topology);
188 extern int hwloc_backend_linuxfs_init(struct hwloc_topology *topology, const char *fsroot_path);
189 extern void hwloc_backend_linuxfs_exit(struct hwloc_topology *topology);
190 extern void hwloc_linuxfs_pci_lookup_osdevices(struct hwloc_topology *topology, struct hwloc_obj *pcidev);
191 extern int hwloc_linuxfs_get_pcidev_cpuset(struct hwloc_topology *topology, struct hwloc_obj *pcidev, hwloc_bitmap_t cpuset);
192 #endif /* HWLOC_LINUX_SYS */
193 
194 extern int hwloc_backend_xml_init(struct hwloc_topology *topology, const char *xmlpath, const char *xmlbuffer, int buflen);
195 extern int hwloc_look_xml(struct hwloc_topology *topology);
196 extern void hwloc_backend_xml_exit(struct hwloc_topology *topology);
197 
198 #ifdef HWLOC_SOLARIS_SYS
199 extern void hwloc_look_solaris(struct hwloc_topology *topology);
200 extern void hwloc_set_solaris_hooks(struct hwloc_topology *topology);
201 #endif /* HWLOC_SOLARIS_SYS */
202 
203 #ifdef HWLOC_AIX_SYS
204 extern void hwloc_look_aix(struct hwloc_topology *topology);
205 extern void hwloc_set_aix_hooks(struct hwloc_topology *topology);
206 #endif /* HWLOC_AIX_SYS */
207 
208 #ifdef HWLOC_OSF_SYS
209 extern void hwloc_look_osf(struct hwloc_topology *topology);
210 extern void hwloc_set_osf_hooks(struct hwloc_topology *topology);
211 #endif /* HWLOC_OSF_SYS */
212 
213 #ifdef HWLOC_WIN_SYS
214 extern void hwloc_look_windows(struct hwloc_topology *topology);
215 extern void hwloc_set_windows_hooks(struct hwloc_topology *topology);
216 #endif /* HWLOC_WIN_SYS */
217 
218 #ifdef HWLOC_DARWIN_SYS
219 extern void hwloc_look_darwin(struct hwloc_topology *topology);
220 extern void hwloc_set_darwin_hooks(struct hwloc_topology *topology);
221 #endif /* HWLOC_DARWIN_SYS */
222 
223 #ifdef HWLOC_FREEBSD_SYS
224 extern void hwloc_look_freebsd(struct hwloc_topology *topology);
225 extern void hwloc_set_freebsd_hooks(struct hwloc_topology *topology);
226 #endif /* HWLOC_FREEBSD_SYS */
227 
228 #ifdef HWLOC_HPUX_SYS
229 extern void hwloc_look_hpux(struct hwloc_topology *topology);
230 extern void hwloc_set_hpux_hooks(struct hwloc_topology *topology);
231 #endif /* HWLOC_HPUX_SYS */
232 
233 extern void hwloc_look_x86(struct hwloc_topology *topology, unsigned nbprocs);
234 
235 #ifdef HWLOC_HAVE_LIBPCI
236 extern void hwloc_look_libpci(struct hwloc_topology *topology);
237 #endif /* HWLOC_HAVE_LIBPCI */
238 
239 extern int hwloc_backend_synthetic_init(struct hwloc_topology *topology, const char *description);
240 extern void hwloc_backend_synthetic_exit(struct hwloc_topology *topology);
241 extern void hwloc_look_synthetic (struct hwloc_topology *topology);
242 
243 /*
244  * Add an object to the topology.
245  * It is sorted along the tree of other objects according to the inclusion of
246  * cpusets, to eventually be added as a child of the smallest object including
247  * this object.
248  *
249  * If the cpuset is empty, the type of the object (and maybe some attributes)
250  * must be enough to find where to insert the object. This is especially true
251  * for NUMA nodes with memory and no CPUs.
252  *
253  * The given object should not have children.
254  *
255  * This shall only be called before levels are built.
256  *
257  * In case of error, hwloc_report_os_error() is called.
258  */
259 extern void hwloc_insert_object_by_cpuset(struct hwloc_topology *topology, hwloc_obj_t obj);
260 
261 /* Error reporting */
262 typedef void (*hwloc_report_error_t)(const char * msg, int line);
263 extern void hwloc_report_os_error(const char * msg, int line);
264 extern int hwloc_hide_errors(void);
265 /*
266  * Add an object to the topology and specify which error callback to use
267  */
268 extern int hwloc__insert_object_by_cpuset(struct hwloc_topology *topology, hwloc_obj_t obj, hwloc_report_error_t report_error);
269 
270 /*
271  * Insert an object somewhere in the topology.
272  *
273  * It is added as the last child of the given parent.
274  * The cpuset is completely ignored, so strange objects such as I/O devices should
275  * preferably be inserted with this.
276  *
277  * The given object may have children.
278  *
279  * Remember to call topology_connect() afterwards to fix handy pointers.
280  */
281 extern void hwloc_insert_object_by_parent(struct hwloc_topology *topology, hwloc_obj_t parent, hwloc_obj_t obj);
282 
283 /* Insert uname-specific names/values in the object infos array */
284 extern void hwloc_add_uname_info(struct hwloc_topology *topology);
285 
286 #ifdef HWLOC_INSIDE_LIBHWLOC
287 /** \brief Return a locally-allocated stringified bitmap for printf-like calls. */
288 static __hwloc_inline char *
hwloc_bitmap_printf_value(hwloc_const_bitmap_t bitmap)289 hwloc_bitmap_printf_value(hwloc_const_bitmap_t bitmap)
290 {
291   char *buf;
292   hwloc_bitmap_asprintf(&buf, bitmap);
293   return buf;
294 }
295 
296 static __hwloc_inline struct hwloc_obj *
hwloc_alloc_setup_object(hwloc_obj_type_t type,signed idx)297 hwloc_alloc_setup_object(hwloc_obj_type_t type, signed idx)
298 {
299   struct hwloc_obj *obj = malloc(sizeof(*obj));
300   memset(obj, 0, sizeof(*obj));
301   obj->type = type;
302   obj->os_index = idx;
303   obj->os_level = -1;
304   obj->attr = malloc(sizeof(*obj->attr));
305   memset(obj->attr, 0, sizeof(*obj->attr));
306   /* do not allocate the cpuset here, let the caller do it */
307   return obj;
308 }
309 
310 extern void hwloc_free_unlinked_object(hwloc_obj_t obj);
311 #endif
312 
313 /* This can be used for the alloc field to get allocated data that can be freed by free() */
314 void *hwloc_alloc_heap(hwloc_topology_t topology, size_t len);
315 
316 /* This can be used for the alloc field to get allocated data that can be freed by munmap() */
317 void *hwloc_alloc_mmap(hwloc_topology_t topology, size_t len);
318 
319 /* This can be used for the free_membind field to free data using free() */
320 int hwloc_free_heap(hwloc_topology_t topology, void *addr, size_t len);
321 
322 /* This can be used for the free_membind field to free data using munmap() */
323 int hwloc_free_mmap(hwloc_topology_t topology, void *addr, size_t len);
324 
325 /* Allocates unbound memory or fail, depending on whether STRICT is requested
326  * or not */
327 static __hwloc_inline void *
hwloc_alloc_or_fail(hwloc_topology_t topology,size_t len,int flags)328 hwloc_alloc_or_fail(hwloc_topology_t topology, size_t len, int flags)
329 {
330   if (flags & HWLOC_MEMBIND_STRICT)
331     return NULL;
332   return hwloc_alloc(topology, len);
333 }
334 
335 extern void hwloc_distances_init(struct hwloc_topology *topology);
336 extern void hwloc_distances_clear(struct hwloc_topology *topology);
337 extern void hwloc_distances_destroy(struct hwloc_topology *topology);
338 extern void hwloc_distances_set(struct hwloc_topology *topology, hwloc_obj_type_t type, unsigned nbobjs, unsigned *indexes, hwloc_obj_t *objs, float *distances, int force);
339 extern void hwloc_distances_set_from_env(struct hwloc_topology *topology);
340 extern void hwloc_distances_restrict_os(struct hwloc_topology *topology);
341 extern void hwloc_distances_restrict(struct hwloc_topology *topology, unsigned long flags);
342 extern void hwloc_distances_finalize_os(struct hwloc_topology *topology);
343 extern void hwloc_distances_finalize_logical(struct hwloc_topology *topology);
344 extern void hwloc_clear_object_distances(struct hwloc_obj *obj);
345 extern void hwloc_clear_object_distances_one(struct hwloc_distances_s *distances);
346 extern void hwloc_group_by_distances(struct hwloc_topology *topology);
347 
348 #ifdef HAVE_USELOCALE
349 #include "locale.h"
350 #ifdef HAVE_XLOCALE_H
351 #include "xlocale.h"
352 #endif
353 #define hwloc_localeswitch_declare locale_t __old_locale = (locale_t)0, __new_locale
354 #define hwloc_localeswitch_init() do {                     \
355   __new_locale = newlocale(LC_ALL_MASK, "C", (locale_t)0); \
356   if (__new_locale != (locale_t)0)                         \
357     __old_locale = uselocale(__new_locale);                \
358 } while (0)
359 #define hwloc_localeswitch_fini() do { \
360   if (__new_locale != (locale_t)0) {   \
361     uselocale(__old_locale);           \
362     freelocale(__new_locale);          \
363   }                                    \
364 } while(0)
365 #else /* HAVE_USELOCALE */
366 #define hwloc_localeswitch_declare int __dummy_nolocale __hwloc_attribute_unused
367 #define hwloc_localeswitch_init()
368 #define hwloc_localeswitch_fini()
369 #endif /* HAVE_USELOCALE */
370 
371 #if !HAVE_DECL_FABSF
372 #define fabsf(f) fabs((double)(f))
373 #endif
374 
375 #endif /* HWLOC_PRIVATE_H */
376