levelzero.h 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. /*
  2. * Copyright © 2021-2023 Inria. All rights reserved.
  3. * See COPYING in top-level directory.
  4. */
  5. /** \file
  6. * \brief Macros to help interaction between hwloc and the oneAPI Level Zero interface.
  7. *
  8. * Applications that use both hwloc and Level Zero may want to
  9. * include this file so as to get topology information for L0 devices.
  10. */
  11. #ifndef HWLOC_LEVELZERO_H
  12. #define HWLOC_LEVELZERO_H
  13. #include "hwloc.h"
  14. #include "hwloc/autogen/config.h"
  15. #include "hwloc/helper.h"
  16. #ifdef HWLOC_LINUX_SYS
  17. #include "hwloc/linux.h"
  18. #endif
  19. #include <level_zero/ze_api.h>
  20. #include <level_zero/zes_api.h>
  21. #ifdef __cplusplus
  22. extern "C" {
  23. #endif
  24. /** \defgroup hwlocality_levelzero Interoperability with the oneAPI Level Zero interface.
  25. *
  26. * This interface offers ways to retrieve topology information about
  27. * devices managed by the Level Zero API.
  28. *
  29. * @{
  30. */
  31. /** \brief Get the CPU set of logical processors that are physically
  32. * close to the Level Zero device \p device
  33. *
  34. * Store in \p set the CPU-set describing the locality of
  35. * the Level Zero device \p device.
  36. *
  37. * Topology \p topology and device \p device must match the local machine.
  38. * The Level Zero must have been initialized with Sysman enabled
  39. * (ZES_ENABLE_SYSMAN=1 in the environment).
  40. * I/O devices detection and the Level Zero component are not needed in the
  41. * topology.
  42. *
  43. * The function only returns the locality of the device.
  44. * If more information about the device is needed, OS objects should
  45. * be used instead, see hwloc_levelzero_get_device_osdev().
  46. *
  47. * This function is currently only implemented in a meaningful way for
  48. * Linux; other systems will simply get a full cpuset.
  49. *
  50. * \return 0 on success.
  51. * \return -1 on error, for instance if device information could not be found.
  52. */
  53. static __hwloc_inline int
  54. hwloc_levelzero_get_device_cpuset(hwloc_topology_t topology __hwloc_attribute_unused,
  55. ze_device_handle_t device, hwloc_cpuset_t set)
  56. {
  57. #ifdef HWLOC_LINUX_SYS
  58. /* If we're on Linux, use the sysfs mechanism to get the local cpus */
  59. #define HWLOC_LEVELZERO_DEVICE_SYSFS_PATH_MAX 128
  60. char path[HWLOC_LEVELZERO_DEVICE_SYSFS_PATH_MAX];
  61. zes_pci_properties_t pci;
  62. zes_device_handle_t sdevice = device;
  63. ze_result_t res;
  64. if (!hwloc_topology_is_thissystem(topology)) {
  65. errno = EINVAL;
  66. return -1;
  67. }
  68. res = zesDevicePciGetProperties(sdevice, &pci);
  69. if (res != ZE_RESULT_SUCCESS) {
  70. errno = EINVAL;
  71. return -1;
  72. }
  73. sprintf(path, "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/local_cpus",
  74. pci.address.domain, pci.address.bus, pci.address.device, pci.address.function);
  75. if (hwloc_linux_read_path_as_cpumask(path, set) < 0
  76. || hwloc_bitmap_iszero(set))
  77. hwloc_bitmap_copy(set, hwloc_topology_get_complete_cpuset(topology));
  78. #else
  79. /* Non-Linux systems simply get a full cpuset */
  80. hwloc_bitmap_copy(set, hwloc_topology_get_complete_cpuset(topology));
  81. #endif
  82. return 0;
  83. }
  84. /** \brief Get the hwloc OS device object corresponding to Level Zero device
  85. * \p device.
  86. *
  87. * \return The hwloc OS device object that describes the given Level Zero device \p device.
  88. * \return \c NULL if none could be found.
  89. *
  90. * Topology \p topology and device \p dv_ind must match the local machine.
  91. * I/O devices detection and the Level Zero component must be enabled in the
  92. * topology. If not, the locality of the object may still be found using
  93. * hwloc_levelzero_get_device_cpuset().
  94. *
  95. * \note The corresponding hwloc PCI device may be found by looking
  96. * at the result parent pointer (unless PCI devices are filtered out).
  97. */
  98. static __hwloc_inline hwloc_obj_t
  99. hwloc_levelzero_get_device_osdev(hwloc_topology_t topology, ze_device_handle_t device)
  100. {
  101. zes_device_handle_t sdevice = device;
  102. zes_pci_properties_t pci;
  103. ze_result_t res;
  104. hwloc_obj_t osdev;
  105. if (!hwloc_topology_is_thissystem(topology)) {
  106. errno = EINVAL;
  107. return NULL;
  108. }
  109. res = zesDevicePciGetProperties(sdevice, &pci);
  110. if (res != ZE_RESULT_SUCCESS) {
  111. /* L0 was likely initialized without sysman, don't bother */
  112. errno = EINVAL;
  113. return NULL;
  114. }
  115. osdev = NULL;
  116. while ((osdev = hwloc_get_next_osdev(topology, osdev)) != NULL) {
  117. hwloc_obj_t pcidev = osdev->parent;
  118. if (strncmp(osdev->name, "ze", 2))
  119. continue;
  120. if (pcidev
  121. && pcidev->type == HWLOC_OBJ_PCI_DEVICE
  122. && pcidev->attr->pcidev.domain == pci.address.domain
  123. && pcidev->attr->pcidev.bus == pci.address.bus
  124. && pcidev->attr->pcidev.dev == pci.address.device
  125. && pcidev->attr->pcidev.func == pci.address.function)
  126. return osdev;
  127. /* FIXME: when we'll have serialnumber, try it in case PCI is filtered-out */
  128. }
  129. return NULL;
  130. }
  131. /** @} */
  132. #ifdef __cplusplus
  133. } /* extern "C" */
  134. #endif
  135. #endif /* HWLOC_LEVELZERO_H */