Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-17 09:16:56

0001 /*
0002  * SPDX-License-Identifier: BSD-3-Clause
0003  * Copyright © 2021-2024 Inria.  All rights reserved.
0004  * See COPYING in top-level directory.
0005  */
0006 
0007 /** \file
0008  * \brief Macros to help interaction between hwloc and the oneAPI Level Zero interface.
0009  *
0010  * Applications that use both hwloc and Level Zero may want to
0011  * include this file so as to get topology information for L0 devices.
0012  */
0013 
0014 #ifndef HWLOC_LEVELZERO_H
0015 #define HWLOC_LEVELZERO_H
0016 
0017 #include "hwloc.h"
0018 #include "hwloc/autogen/config.h"
0019 #include "hwloc/helper.h"
0020 #ifdef HWLOC_LINUX_SYS
0021 #include "hwloc/linux.h"
0022 #endif
0023 
0024 #include <level_zero/ze_api.h>
0025 #include <level_zero/zes_api.h>
0026 
0027 
0028 #ifdef __cplusplus
0029 extern "C" {
0030 #endif
0031 
0032 
0033 /** \defgroup hwlocality_levelzero Interoperability with the oneAPI Level Zero interface.
0034  *
0035  * This interface offers ways to retrieve topology information about
0036  * devices managed by the Level Zero API, both for main Core devices (ZE API)
0037  * and the Sysman devices (ZES API).
0038  *
0039  * @{
0040  */
0041 
0042 /** \brief Get the CPU set of logical processors that are physically
0043  * close to the Level Zero device \p device
0044  *
0045  * Store in \p set the CPU-set describing the locality of
0046  * the Level Zero device \p device.
0047  *
0048  * Topology \p topology and device \p device must match the local machine.
0049  * The Level Zero library must have been initialized with zeInit().
0050  * I/O devices detection and the Level Zero component are not needed in the
0051  * topology.
0052  *
0053  * The function only returns the locality of the device.
0054  * If more information about the device is needed, OS objects should
0055  * be used instead, see hwloc_levelzero_get_device_osdev().
0056  *
0057  * This function is currently only implemented in a meaningful way for
0058  * Linux; other systems will simply get a full cpuset.
0059  *
0060  * \return 0 on success.
0061  * \return -1 on error, for instance if device information could not be found.
0062  *
0063  * \note zeDevicePciGetPropertiesExt() must be supported, or the entire machine
0064  * locality will be returned.
0065  */
0066 static __hwloc_inline int
0067 hwloc_levelzero_get_device_cpuset(hwloc_topology_t topology __hwloc_attribute_unused,
0068                                   ze_device_handle_t device, hwloc_cpuset_t set)
0069 {
0070 #ifdef HWLOC_LINUX_SYS
0071   /* If we're on Linux, use the sysfs mechanism to get the local cpus */
0072 #define HWLOC_LEVELZERO_DEVICE_SYSFS_PATH_MAX 128
0073   char path[HWLOC_LEVELZERO_DEVICE_SYSFS_PATH_MAX];
0074   ze_pci_ext_properties_t pci;
0075   ze_result_t res;
0076 
0077   if (!hwloc_topology_is_thissystem(topology)) {
0078     errno = EINVAL;
0079     return -1;
0080   }
0081 
0082   pci.stype =  ZE_STRUCTURE_TYPE_PCI_EXT_PROPERTIES;
0083   pci.pNext = NULL;
0084   res = zeDevicePciGetPropertiesExt(device, &pci);
0085   if (res != ZE_RESULT_SUCCESS) {
0086     errno = EINVAL;
0087     return -1;
0088   }
0089 
0090   sprintf(path, "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/local_cpus",
0091           pci.address.domain, pci.address.bus, pci.address.device, pci.address.function);
0092   if (hwloc_linux_read_path_as_cpumask(path, set) < 0
0093       || hwloc_bitmap_iszero(set))
0094     hwloc_bitmap_copy(set, hwloc_topology_get_complete_cpuset(topology));
0095 #else
0096   /* Non-Linux systems simply get a full cpuset */
0097   hwloc_bitmap_copy(set, hwloc_topology_get_complete_cpuset(topology));
0098 #endif
0099   return 0;
0100 }
0101 
0102 /** \brief Get the CPU set of logical processors that are physically
0103  * close to the Level Zero Sysman device \p device
0104  *
0105  * Store in \p set the CPU-set describing the locality of
0106  * the Level Zero device \p device.
0107  *
0108  * Topology \p topology and device \p device must match the local machine.
0109  * The Level Zero library must have been initialized with Sysman enabled
0110  * with zesInit().
0111  * I/O devices detection and the Level Zero component are not needed in the
0112  * topology.
0113  *
0114  * The function only returns the locality of the device.
0115  * If more information about the device is needed, OS objects should
0116  * be used instead, see hwloc_levelzero_get_device_osdev().
0117  *
0118  * This function is currently only implemented in a meaningful way for
0119  * Linux; other systems will simply get a full cpuset.
0120  *
0121  * \return 0 on success.
0122  * \return -1 on error, for instance if device information could not be found.
0123  */
0124 static __hwloc_inline int
0125 hwloc_levelzero_get_sysman_device_cpuset(hwloc_topology_t topology __hwloc_attribute_unused,
0126                                          zes_device_handle_t device, hwloc_cpuset_t set)
0127 {
0128 #ifdef HWLOC_LINUX_SYS
0129   /* If we're on Linux, use the sysfs mechanism to get the local cpus */
0130 #define HWLOC_LEVELZERO_DEVICE_SYSFS_PATH_MAX 128
0131   char path[HWLOC_LEVELZERO_DEVICE_SYSFS_PATH_MAX];
0132   zes_pci_properties_t pci;
0133   ze_result_t res;
0134 
0135   if (!hwloc_topology_is_thissystem(topology)) {
0136     errno = EINVAL;
0137     return -1;
0138   }
0139 
0140   res = zesDevicePciGetProperties(device, &pci);
0141   if (res != ZE_RESULT_SUCCESS) {
0142     errno = EINVAL;
0143     return -1;
0144   }
0145 
0146   sprintf(path, "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/local_cpus",
0147           pci.address.domain, pci.address.bus, pci.address.device, pci.address.function);
0148   if (hwloc_linux_read_path_as_cpumask(path, set) < 0
0149       || hwloc_bitmap_iszero(set))
0150     hwloc_bitmap_copy(set, hwloc_topology_get_complete_cpuset(topology));
0151 #else
0152   /* Non-Linux systems simply get a full cpuset */
0153   hwloc_bitmap_copy(set, hwloc_topology_get_complete_cpuset(topology));
0154 #endif
0155   return 0;
0156 }
0157 
0158 /** \brief Get the hwloc OS device object corresponding to Level Zero device
0159  * \p device.
0160  *
0161  * \return The hwloc OS device object that describes the given Level Zero device \p device.
0162  * \return \c NULL if none could be found.
0163  *
0164  * Topology \p topology and device \p dv_ind must match the local machine.
0165  * The Level Zero library must have been initialized with zeInit().
0166  * I/O devices detection and the Level Zero component must be enabled in the
0167  * topology. If not, the locality of the object may still be found using
0168  * hwloc_levelzero_get_device_cpuset().
0169  *
0170  * \note If the input ZE device is actually a subdevice, then its parent
0171  * (root device) is actually translated, i.e. the main hwloc OS device
0172  * is returned instead of one of its children.
0173  *
0174  * \note The corresponding hwloc PCI device may be found by looking
0175  * at the result parent pointer (unless PCI devices are filtered out).
0176  *
0177  * \note zeDevicePciGetPropertiesExt() must be supported.
0178  */
0179 static __hwloc_inline hwloc_obj_t
0180 hwloc_levelzero_get_device_osdev(hwloc_topology_t topology, ze_device_handle_t device)
0181 {
0182   ze_pci_ext_properties_t pci;
0183   ze_result_t res;
0184   hwloc_obj_t osdev;
0185 
0186   if (!hwloc_topology_is_thissystem(topology)) {
0187     errno = EINVAL;
0188     return NULL;
0189   }
0190 
0191   pci.stype = ZE_STRUCTURE_TYPE_PCI_EXT_PROPERTIES;
0192   pci.pNext = NULL;
0193   res = zeDevicePciGetPropertiesExt(device, &pci);
0194   if (res != ZE_RESULT_SUCCESS) {
0195     errno = EINVAL;
0196     return NULL;
0197   }
0198 
0199   osdev = NULL;
0200   while ((osdev = hwloc_get_next_osdev(topology, osdev)) != NULL) {
0201     hwloc_obj_t pcidev;
0202 
0203     if (strncmp(osdev->name, "ze", 2))
0204       continue;
0205 
0206     pcidev = osdev;
0207     while (pcidev && pcidev->type != HWLOC_OBJ_PCI_DEVICE)
0208       pcidev = pcidev->parent;
0209     if (!pcidev)
0210       continue;
0211 
0212     if (pcidev
0213       && pcidev->type == HWLOC_OBJ_PCI_DEVICE
0214       && pcidev->attr->pcidev.domain == pci.address.domain
0215       && pcidev->attr->pcidev.bus == pci.address.bus
0216       && pcidev->attr->pcidev.dev == pci.address.device
0217       && pcidev->attr->pcidev.func == pci.address.function)
0218       return osdev;
0219 
0220     /* FIXME: when we'll have serialnumber, try it in case PCI is filtered-out */
0221   }
0222 
0223   return NULL;
0224 }
0225 
0226 /** \brief Get the hwloc OS device object corresponding to Level Zero Sysman device
0227  * \p device.
0228  *
0229  * \return The hwloc OS device object that describes the given Level Zero device \p device.
0230  * \return \c NULL if none could be found.
0231  *
0232  * Topology \p topology and device \p dv_ind must match the local machine.
0233  * The Level Zero library must have been initialized with Sysman enabled
0234  * with zesInit().
0235  * I/O devices detection and the Level Zero component must be enabled in the
0236  * topology. If not, the locality of the object may still be found using
0237  * hwloc_levelzero_get_device_cpuset().
0238  *
0239  * \note If the input ZES device is actually a subdevice, then its parent
0240  * (root device) is actually translated, i.e. the main hwloc OS device
0241  * is returned instead of one of its children.
0242  *
0243  * \note The corresponding hwloc PCI device may be found by looking
0244  * at the result parent pointer (unless PCI devices are filtered out).
0245  */
0246 static __hwloc_inline hwloc_obj_t
0247 hwloc_levelzero_get_sysman_device_osdev(hwloc_topology_t topology, zes_device_handle_t device)
0248 {
0249   zes_pci_properties_t pci;
0250   ze_result_t res;
0251   hwloc_obj_t osdev;
0252 
0253   if (!hwloc_topology_is_thissystem(topology)) {
0254     errno = EINVAL;
0255     return NULL;
0256   }
0257 
0258   res = zesDevicePciGetProperties(device, &pci);
0259   if (res != ZE_RESULT_SUCCESS) {
0260     errno = EINVAL;
0261     return NULL;
0262   }
0263 
0264   osdev = NULL;
0265   while ((osdev = hwloc_get_next_osdev(topology, osdev)) != NULL) {
0266     hwloc_obj_t pcidev;
0267 
0268     if (strncmp(osdev->name, "ze", 2))
0269       continue;
0270 
0271     pcidev = osdev;
0272     while (pcidev && pcidev->type != HWLOC_OBJ_PCI_DEVICE)
0273       pcidev = pcidev->parent;
0274     if (!pcidev)
0275       continue;
0276 
0277     if (pcidev
0278       && pcidev->type == HWLOC_OBJ_PCI_DEVICE
0279       && pcidev->attr->pcidev.domain == pci.address.domain
0280       && pcidev->attr->pcidev.bus == pci.address.bus
0281       && pcidev->attr->pcidev.dev == pci.address.device
0282       && pcidev->attr->pcidev.func == pci.address.function)
0283       return osdev;
0284 
0285     /* FIXME: when we'll have serialnumber, try it in case PCI is filtered-out */
0286   }
0287 
0288   return NULL;
0289 }
0290 
0291 /** @} */
0292 
0293 
0294 #ifdef __cplusplus
0295 } /* extern "C" */
0296 #endif
0297 
0298 
0299 #endif /* HWLOC_LEVELZERO_H */