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 */