1 /*
2 * Copyright © 2013-2017 Inria. All rights reserved.
3 * Copyright © 2016 Cisco Systems, Inc. All rights reserved.
4 * See COPYING in top-level directory.
5 */
6
7 #ifndef HWLOC_PLUGINS_H
8 #define HWLOC_PLUGINS_H
9
10 /** \file
11 * \brief Public interface for building hwloc plugins.
12 */
13
14 struct hwloc_backend;
15
16 #include <hwloc.h>
17 #ifdef HWLOC_INSIDE_PLUGIN
18 /* needed for hwloc_plugin_check_namespace() */
19 #include <ltdl.h>
20 #endif
21
22
23
24 /** \defgroup hwlocality_disc_components Components and Plugins: Discovery components
25 * @{
26 */
27
28 /** \brief Discovery component type */
29 typedef enum hwloc_disc_component_type_e {
30 /** \brief CPU-only discovery through the OS, or generic no-OS support.
31 * \hideinitializer */
32 HWLOC_DISC_COMPONENT_TYPE_CPU = (1<<0),
33
34 /** \brief xml or synthetic,
35 * platform-specific components such as bgq.
36 * Anything the discovers CPU and everything else.
37 * No misc backend is expected to complement a global component.
38 * \hideinitializer */
39 HWLOC_DISC_COMPONENT_TYPE_GLOBAL = (1<<1),
40
41 /** \brief OpenCL, Cuda, etc.
42 * \hideinitializer */
43 HWLOC_DISC_COMPONENT_TYPE_MISC = (1<<2)
44 } hwloc_disc_component_type_t;
45
46 /** \brief Discovery component structure
47 *
48 * This is the major kind of components, taking care of the discovery.
49 * They are registered by generic components, either statically-built or as plugins.
50 */
51 struct hwloc_disc_component {
52 /** \brief Discovery component type */
53 hwloc_disc_component_type_t type;
54
55 /** \brief Name.
56 * If this component is built as a plugin, this name does not have to match the plugin filename.
57 */
58 const char *name;
59
60 /** \brief Component types to exclude, as an OR'ed set of ::hwloc_disc_component_type_e.
61 *
62 * For a GLOBAL component, this usually includes all other types (~0).
63 *
64 * Other components only exclude types that may bring conflicting
65 * topology information. MISC components should likely not be excluded
66 * since they usually bring non-primary additional information.
67 */
68 unsigned excludes;
69
70 /** \brief Instantiate callback to create a backend from the component.
71 * Parameters data1, data2, data3 are NULL except for components
72 * that have special enabling routines such as hwloc_topology_set_xml(). */
73 struct hwloc_backend * (*instantiate)(struct hwloc_disc_component *component, const void *data1, const void *data2, const void *data3);
74
75 /** \brief Component priority.
76 * Used to sort topology->components, higher priority first.
77 * Also used to decide between two components with the same name.
78 *
79 * Usual values are
80 * 50 for native OS (or platform) components,
81 * 45 for x86,
82 * 40 for no-OS fallback,
83 * 30 for global components (xml, synthetic),
84 * 20 for pci,
85 * 10 for other misc components (opencl etc.).
86 */
87 unsigned priority;
88
89 /** \brief Enabled by default.
90 * If unset, if will be disabled unless explicitly requested.
91 */
92 unsigned enabled_by_default;
93
94 /** \private Used internally to list components by priority on topology->components
95 * (the component structure is usually read-only,
96 * the core copies it before using this field for queueing)
97 */
98 struct hwloc_disc_component * next;
99 };
100
101 /** @} */
102
103
104
105
106 /** \defgroup hwlocality_disc_backends Components and Plugins: Discovery backends
107 * @{
108 */
109
110 /** \brief Discovery backend structure
111 *
112 * A backend is the instantiation of a discovery component.
113 * When a component gets enabled for a topology,
114 * its instantiate() callback creates a backend.
115 *
116 * hwloc_backend_alloc() initializes all fields to default values
117 * that the component may change (except "component" and "next")
118 * before enabling the backend with hwloc_backend_enable().
119 */
120 struct hwloc_backend {
121 /** \private Reserved for the core, set by hwloc_backend_alloc() */
122 struct hwloc_disc_component * component;
123 /** \private Reserved for the core, set by hwloc_backend_enable() */
124 struct hwloc_topology * topology;
125 /** \private Reserved for the core. Set to 1 if forced through envvar, 0 otherwise. */
126 int envvar_forced;
127 /** \private Reserved for the core. Used internally to list backends topology->backends. */
128 struct hwloc_backend * next;
129
130 /** \brief Backend flags, currently always 0. */
131 unsigned long flags;
132
133 /** \brief Backend-specific 'is_thissystem' property.
134 * Set to 0 or 1 if the backend should enforce the thissystem flag when it gets enabled.
135 * Set to -1 if the backend doesn't care (default). */
136 int is_thissystem;
137
138 /** \brief Backend private data, or NULL if none. */
139 void * private_data;
140 /** \brief Callback for freeing the private_data.
141 * May be NULL.
142 */
143 void (*disable)(struct hwloc_backend *backend);
144
145 /** \brief Main discovery callback.
146 * returns -1 on error, either because it couldn't add its objects ot the existing topology,
147 * or because of an actual discovery/gathering failure.
148 * May be NULL.
149 */
150 int (*discover)(struct hwloc_backend *backend);
151
152 /** \brief Callback used by the PCI backend to retrieve the locality of a PCI object from the OS/cpu backend.
153 * May be NULL. */
154 int (*get_pci_busid_cpuset)(struct hwloc_backend *backend, struct hwloc_pcidev_attr_s *busid, hwloc_bitmap_t cpuset);
155 };
156
157 /** \brief Allocate a backend structure, set good default values, initialize backend->component and topology, etc.
158 * The caller will then modify whatever needed, and call hwloc_backend_enable().
159 */
160 HWLOC_DECLSPEC struct hwloc_backend * hwloc_backend_alloc(struct hwloc_disc_component *component);
161
162 /** \brief Enable a previously allocated and setup backend. */
163 HWLOC_DECLSPEC int hwloc_backend_enable(struct hwloc_topology *topology, struct hwloc_backend *backend);
164
165 /** @} */
166
167
168
169
170 /** \defgroup hwlocality_generic_components Components and Plugins: Generic components
171 * @{
172 */
173
174 /** \brief Generic component type */
175 typedef enum hwloc_component_type_e {
176 /** \brief The data field must point to a struct hwloc_disc_component. */
177 HWLOC_COMPONENT_TYPE_DISC,
178
179 /** \brief The data field must point to a struct hwloc_xml_component. */
180 HWLOC_COMPONENT_TYPE_XML
181 } hwloc_component_type_t;
182
183 /** \brief Generic component structure
184 *
185 * Generic components structure, either statically listed by configure in static-components.h
186 * or dynamically loaded as a plugin.
187 */
188 struct hwloc_component {
189 /** \brief Component ABI version, set to ::HWLOC_COMPONENT_ABI */
190 unsigned abi;
191
192 /** \brief Process-wide component initialization callback.
193 *
194 * This optional callback is called when the component is registered
195 * to the hwloc core (after loading the plugin).
196 *
197 * When the component is built as a plugin, this callback
198 * should call hwloc_check_plugin_namespace()
199 * and return an negative error code on error.
200 *
201 * \p flags is always 0 for now.
202 *
203 * \return 0 on success, or a negative code on error.
204 *
205 * \note If the component uses ltdl for loading its own plugins,
206 * it should load/unload them only in init() and finalize(),
207 * to avoid race conditions with hwloc's use of ltdl.
208 */
209 int (*init)(unsigned long flags);
210
211 /** \brief Process-wide component termination callback.
212 *
213 * This optional callback is called after unregistering the component
214 * from the hwloc core (before unloading the plugin).
215 *
216 * \p flags is always 0 for now.
217 *
218 * \note If the component uses ltdl for loading its own plugins,
219 * it should load/unload them only in init() and finalize(),
220 * to avoid race conditions with hwloc's use of ltdl.
221 */
222 void (*finalize)(unsigned long flags);
223
224 /** \brief Component type */
225 hwloc_component_type_t type;
226
227 /** \brief Component flags, unused for now */
228 unsigned long flags;
229
230 /** \brief Component data, pointing to a struct hwloc_disc_component or struct hwloc_xml_component. */
231 void * data;
232 };
233
234 /** @} */
235
236
237
238
239 /** \defgroup hwlocality_components_core_funcs Components and Plugins: Core functions to be used by components
240 * @{
241 */
242
243 /** \brief Add an object to the topology.
244 *
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 * The caller should check whether the object type is filtered-out before calling this function.
260 *
261 * The topology cpuset/nodesets will be enlarged to include the object sets.
262 *
263 * Returns the object on success.
264 * Returns NULL and frees obj on error.
265 * Returns another object and frees obj if it was merged with an identical pre-existing object.
266 */
267 HWLOC_DECLSPEC struct hwloc_obj *hwloc_insert_object_by_cpuset(struct hwloc_topology *topology, hwloc_obj_t obj);
268
269 /** \brief Type of error callbacks during object insertion */
270 typedef void (*hwloc_report_error_t)(const char * msg, int line);
271 /** \brief Report an insertion error from a backend */
272 HWLOC_DECLSPEC void hwloc_report_os_error(const char * msg, int line);
273 /** \brief Check whether insertion errors are hidden */
274 HWLOC_DECLSPEC int hwloc_hide_errors(void);
275
276 /** \brief Add an object to the topology and specify which error callback to use.
277 *
278 * This function is similar to hwloc_insert_object_by_cpuset() but it allows specifying
279 * where to start insertion from (if \p root is NULL, the topology root object is used),
280 * and specifying the error callback.
281 */
282 HWLOC_DECLSPEC struct hwloc_obj *hwloc__insert_object_by_cpuset(struct hwloc_topology *topology, hwloc_obj_t root, hwloc_obj_t obj, hwloc_report_error_t report_error);
283
284 /** \brief Insert an object somewhere in the topology.
285 *
286 * It is added as the last child of the given parent.
287 * The cpuset is completely ignored, so strange objects such as I/O devices should
288 * preferably be inserted with this.
289 *
290 * When used for "normal" children with cpusets (when importing from XML
291 * when duplicating a topology), the caller should make sure that:
292 * - children are inserted in order,
293 * - children cpusets do not intersect.
294 *
295 * The given object may have normal, I/O or Misc children, as long as they are in order as well.
296 * These children must have valid parent and next_sibling pointers.
297 *
298 * The caller should check whether the object type is filtered-out before calling this function.
299 */
300 HWLOC_DECLSPEC void hwloc_insert_object_by_parent(struct hwloc_topology *topology, hwloc_obj_t parent, hwloc_obj_t obj);
301
302 /** \brief Allocate and initialize an object of the given type and physical index.
303 *
304 * If \p os_index is unknown or irrelevant, use \c HWLOC_UNKNOWN_INDEX.
305 */
306 HWLOC_DECLSPEC hwloc_obj_t hwloc_alloc_setup_object(hwloc_topology_t topology, hwloc_obj_type_t type, unsigned os_index);
307
308 /** \brief Setup object cpusets/nodesets by OR'ing its children.
309 *
310 * Used when adding an object late in the topology.
311 * Will update the new object by OR'ing all its new children sets.
312 *
313 * Used when PCI backend adds a hostbridge parent, when distances
314 * add a new Group, etc.
315 */
316 HWLOC_DECLSPEC int hwloc_obj_add_children_sets(hwloc_obj_t obj);
317
318 /** \brief Request a reconnection of children and levels in the topology.
319 *
320 * May be used by backends during discovery if they need arrays or lists
321 * of object within levels or children to be fully connected.
322 *
323 * \p flags is currently unused, must 0.
324 */
325 HWLOC_DECLSPEC int hwloc_topology_reconnect(hwloc_topology_t topology, unsigned long flags __hwloc_attribute_unused);
326
327 /** \brief Make sure that plugins can lookup core symbols.
328 *
329 * This is a sanity check to avoid lazy-lookup failures when libhwloc
330 * is loaded within a plugin, and later tries to load its own plugins.
331 * This may fail (and abort the program) if libhwloc symbols are in a
332 * private namespace.
333 *
334 * \return 0 on success.
335 * \return -1 if the plugin cannot be successfully loaded. The caller
336 * plugin init() callback should return a negative error code as well.
337 *
338 * Plugins should call this function in their init() callback to avoid
339 * later crashes if lazy symbol resolution is used by the upper layer that
340 * loaded hwloc (e.g. OpenCL implementations using dlopen with RTLD_LAZY).
341 *
342 * \note The build system must define HWLOC_INSIDE_PLUGIN if and only if
343 * building the caller as a plugin.
344 *
345 * \note This function should remain inline so plugins can call it even
346 * when they cannot find libhwloc symbols.
347 */
348 static __hwloc_inline int
349 hwloc_plugin_check_namespace(const char *pluginname __hwloc_attribute_unused, const char *symbol __hwloc_attribute_unused)
350 {
351 #ifdef HWLOC_INSIDE_PLUGIN
352 lt_dlhandle handle;
353 void *sym;
354 handle = lt_dlopen(NULL);
355 if (!handle)
356 /* cannot check, assume things will work */
357 return 0;
358 sym = lt_dlsym(handle, symbol);
359 lt_dlclose(handle);
360 if (!sym) {
361 static int verboseenv_checked = 0;
362 static int verboseenv_value = 0;
363 if (!verboseenv_checked) {
364 const char *verboseenv = getenv("HWLOC_PLUGINS_VERBOSE");
365 verboseenv_value = verboseenv ? atoi(verboseenv) : 0;
366 verboseenv_checked = 1;
367 }
368 if (verboseenv_value)
369 fprintf(stderr, "Plugin `%s' disabling itself because it cannot find the `%s' core symbol.\n",
370 pluginname, symbol);
371 return -1;
372 }
373 #endif /* HWLOC_INSIDE_PLUGIN */
374 return 0;
375 }
376
377 /** @} */
378
379
380
381
382 /** \defgroup hwlocality_components_filtering Components and Plugins: Filtering objects
383 * @{
384 */
385
386 /** \brief Check whether the given PCI device classid is important.
387 *
388 * \return 1 if important, 0 otherwise.
389 */
390 static __hwloc_inline int
391 hwloc_filter_check_pcidev_subtype_important(unsigned classid)
392 {
393 unsigned baseclass = classid >> 8;
394 return (baseclass == 0x03 /* PCI_BASE_CLASS_DISPLAY */
395 || baseclass == 0x02 /* PCI_BASE_CLASS_NETWORK */
396 || baseclass == 0x01 /* PCI_BASE_CLASS_STORAGE */
397 || baseclass == 0x0b /* PCI_BASE_CLASS_PROCESSOR */
398 || classid == 0x0c04 /* PCI_CLASS_SERIAL_FIBER */
399 || classid == 0x0c06 /* PCI_CLASS_SERIAL_INFINIBAND */
400 || baseclass == 0x12 /* Processing Accelerators */);
401 }
402
403 /** \brief Check whether the given OS device subtype is important.
404 *
405 * \return 1 if important, 0 otherwise.
406 */
407 static __hwloc_inline int
408 hwloc_filter_check_osdev_subtype_important(hwloc_obj_osdev_type_t subtype)
409 {
410 return (subtype != HWLOC_OBJ_OSDEV_DMA);
411 }
412
413 /** \brief Check whether a non-I/O object type should be filtered-out.
414 *
415 * Cannot be used for I/O objects.
416 *
417 * \return 1 if the object type should be kept, 0 otherwise.
418 */
419 static __hwloc_inline int
420 hwloc_filter_check_keep_object_type(hwloc_topology_t topology, hwloc_obj_type_t type)
421 {
422 enum hwloc_type_filter_e filter = HWLOC_TYPE_FILTER_KEEP_NONE;
423 hwloc_topology_get_type_filter(topology, type, &filter);
424 assert(filter != HWLOC_TYPE_FILTER_KEEP_IMPORTANT); /* IMPORTANT only used for I/O */
425 return filter == HWLOC_TYPE_FILTER_KEEP_NONE ? 0 : 1;
426 }
427
428 /** \brief Check whether the given object should be filtered-out.
429 *
430 * \return 1 if the object type should be kept, 0 otherwise.
431 */
432 static __hwloc_inline int
433 hwloc_filter_check_keep_object(hwloc_topology_t topology, hwloc_obj_t obj)
434 {
435 hwloc_obj_type_t type = obj->type;
436 enum hwloc_type_filter_e filter = HWLOC_TYPE_FILTER_KEEP_NONE;
437 hwloc_topology_get_type_filter(topology, type, &filter);
438 if (filter == HWLOC_TYPE_FILTER_KEEP_NONE)
439 return 0;
440 if (filter == HWLOC_TYPE_FILTER_KEEP_IMPORTANT) {
441 if (type == HWLOC_OBJ_PCI_DEVICE)
442 return hwloc_filter_check_pcidev_subtype_important(obj->attr->pcidev.class_id);
443 if (type == HWLOC_OBJ_OS_DEVICE)
444 return hwloc_filter_check_osdev_subtype_important(obj->attr->osdev.type);
445 }
446 return 1;
447 }
448
449 /** @} */
450
451
452
453
454 /** \defgroup hwlocality_components_pcidisc Components and Plugins: helpers for PCI discovery
455 * @{
456 */
457
458 /** \brief Return the offset of the given capability in the PCI config space buffer
459 *
460 * This function requires a 256-bytes config space. Unknown/unavailable bytes should be set to 0xff.
461 */
462 HWLOC_DECLSPEC unsigned hwloc_pcidisc_find_cap(const unsigned char *config, unsigned cap);
463
464 /** \brief Fill linkspeed by reading the PCI config space where PCI_CAP_ID_EXP is at position offset.
465 *
466 * Needs 20 bytes of EXP capability block starting at offset in the config space
467 * for registers up to link status.
468 */
469 HWLOC_DECLSPEC int hwloc_pcidisc_find_linkspeed(const unsigned char *config, unsigned offset, float *linkspeed);
470
471 /** \brief Return the hwloc object type (PCI device or Bridge) for the given class and configuration space.
472 *
473 * This function requires 16 bytes of common configuration header at the beginning of config.
474 */
475 HWLOC_DECLSPEC hwloc_obj_type_t hwloc_pcidisc_check_bridge_type(unsigned device_class, const unsigned char *config);
476
477 /** \brief Fills the attributes of the given PCI bridge using the given PCI config space.
478 *
479 * This function requires 32 bytes of common configuration header at the beginning of config.
480 *
481 * Returns -1 and destroys /p obj if bridge fields are invalid.
482 */
483 HWLOC_DECLSPEC int hwloc_pcidisc_setup_bridge_attr(hwloc_obj_t obj, const unsigned char *config);
484
485 /** \brief Insert a PCI object in the given PCI tree by looking at PCI bus IDs.
486 *
487 * If \p treep points to \c NULL, the new object is inserted there.
488 */
489 HWLOC_DECLSPEC void hwloc_pcidisc_tree_insert_by_busid(struct hwloc_obj **treep, struct hwloc_obj *obj);
490
491 /** \brief Add some hostbridges on top of the given tree of PCI objects and attach them to the topology.
492 *
493 * For now, they will be attached to the root object. The core will move them to their actual PCI
494 * locality using hwloc_pci_belowroot_apply_locality() at the end of the discovery.
495 *
496 * In the meantime, other backends lookup PCI objects or localities (for instance to attach OS devices)
497 * by using hwloc_pcidisc_find_by_busid() or hwloc_pcidisc_find_busid_parent().
498 */
499 HWLOC_DECLSPEC int hwloc_pcidisc_tree_attach(struct hwloc_topology *topology, struct hwloc_obj *tree);
500
501 /** @} */
502
503
504
505
506 /** \defgroup hwlocality_components_pcifind Components and Plugins: finding PCI objects during other discoveries
507 * @{
508 */
509
510 /** \brief Find the PCI object that matches the bus ID.
511 *
512 * To be used after a PCI backend added PCI devices with hwloc_pcidisc_tree_attach()
513 * and before the core moves them to their actual location with hwloc_pci_belowroot_apply_locality().
514 *
515 * If no exactly matching object is found, return the container bridge if any, or NULL.
516 *
517 * On failure, it may be possible to find the PCI locality (instead of the PCI device)
518 * by calling hwloc_pcidisc_find_busid_parent().
519 *
520 * \note This is semantically identical to hwloc_get_pcidev_by_busid() which only works
521 * after the topology is fully loaded.
522 */
523 HWLOC_DECLSPEC struct hwloc_obj * hwloc_pcidisc_find_by_busid(struct hwloc_topology *topology, unsigned domain, unsigned bus, unsigned dev, unsigned func);
524
525 /** \brief Find the normal parent of a PCI bus ID.
526 *
527 * Look at PCI affinity to find out where the given PCI bus ID should be attached.
528 *
529 * This function should be used to attach an I/O device directly under a normal
530 * (non-I/O) object, instead of below a PCI object.
531 * It is usually used by backends when hwloc_pcidisc_find_by_busid() failed
532 * to find the hwloc object corresponding to this bus ID, for instance because
533 * PCI discovery is not supported on this platform.
534 */
535 HWLOC_DECLSPEC struct hwloc_obj * hwloc_pcidisc_find_busid_parent(struct hwloc_topology *topology, unsigned domain, unsigned bus, unsigned dev, unsigned func);
536
537 /** @} */
538
539
540
541
542 #endif /* HWLOC_PLUGINS_H */