Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-25 09:16:39

0001 /*
0002  * SPDX-License-Identifier: BSD-3-Clause
0003  * Copyright © 2010-2023 Inria.  All rights reserved.
0004  * Copyright © 2010-2011 Université Bordeaux
0005  * Copyright © 2011 Cisco Systems, Inc.  All rights reserved.
0006  * See COPYING in top-level directory.
0007  */
0008 
0009 /** \file
0010  * \brief Macros to help interaction between hwloc and the CUDA Runtime API.
0011  *
0012  * Applications that use both hwloc and the CUDA Runtime API may want to
0013  * include this file so as to get topology information for CUDA devices.
0014  *
0015  */
0016 
0017 #ifndef HWLOC_CUDART_H
0018 #define HWLOC_CUDART_H
0019 
0020 #include "hwloc.h"
0021 #include "hwloc/autogen/config.h"
0022 #include "hwloc/helper.h"
0023 #ifdef HWLOC_LINUX_SYS
0024 #include "hwloc/linux.h"
0025 #endif
0026 
0027 #include <cuda.h> /* for CUDA_VERSION */
0028 #include <cuda_runtime_api.h>
0029 
0030 
0031 #ifdef __cplusplus
0032 extern "C" {
0033 #endif
0034 
0035 
0036 /** \defgroup hwlocality_cudart Interoperability with the CUDA Runtime API
0037  *
0038  * This interface offers ways to retrieve topology information about
0039  * CUDA devices when using the CUDA Runtime API.
0040  *
0041  * @{
0042  */
0043 
0044 /** \brief Return the domain, bus and device IDs of the CUDA device whose index is \p idx.
0045  *
0046  * Device index \p idx must match the local machine.
0047  *
0048  * \return 0 on success.
0049  * \return -1 on error, for instance if device information could not be found.
0050  */
0051 static __hwloc_inline int
0052 hwloc_cudart_get_device_pci_ids(hwloc_topology_t topology __hwloc_attribute_unused,
0053                 int idx, int *domain, int *bus, int *dev)
0054 {
0055   cudaError_t cerr;
0056   struct cudaDeviceProp prop;
0057 
0058   cerr = cudaGetDeviceProperties(&prop, idx);
0059   if (cerr) {
0060     errno = ENOSYS;
0061     return -1;
0062   }
0063 
0064 #if CUDA_VERSION >= 4000
0065   *domain = prop.pciDomainID;
0066 #else
0067   *domain = 0;
0068 #endif
0069 
0070   *bus = prop.pciBusID;
0071   *dev = prop.pciDeviceID;
0072 
0073   return 0;
0074 }
0075 
0076 /** \brief Get the CPU set of processors that are physically
0077  * close to device \p idx.
0078  *
0079  * Store in \p set the CPU-set describing the locality of the CUDA device
0080  * whose index is \p idx.
0081  *
0082  * Topology \p topology and device \p idx must match the local machine.
0083  * I/O devices detection and the CUDA component are not needed in the topology.
0084  *
0085  * The function only returns the locality of the device.
0086  * If more information about the device is needed, OS objects should
0087  * be used instead, see hwloc_cudart_get_device_osdev_by_index().
0088  *
0089  * This function is currently only implemented in a meaningful way for
0090  * Linux; other systems will simply get a full cpuset.
0091  *
0092  * \return 0 on success.
0093  * \return -1 on error, for instance if device information could not be found.
0094  */
0095 static __hwloc_inline int
0096 hwloc_cudart_get_device_cpuset(hwloc_topology_t topology __hwloc_attribute_unused,
0097                    int idx, hwloc_cpuset_t set)
0098 {
0099 #ifdef HWLOC_LINUX_SYS
0100   /* If we're on Linux, use the sysfs mechanism to get the local cpus */
0101 #define HWLOC_CUDART_DEVICE_SYSFS_PATH_MAX 128
0102   char path[HWLOC_CUDART_DEVICE_SYSFS_PATH_MAX];
0103   int domain, bus, dev;
0104 
0105   if (hwloc_cudart_get_device_pci_ids(topology, idx, &domain, &bus, &dev))
0106     return -1;
0107 
0108   if (!hwloc_topology_is_thissystem(topology)) {
0109     errno = EINVAL;
0110     return -1;
0111   }
0112 
0113   sprintf(path, "/sys/bus/pci/devices/%04x:%02x:%02x.0/local_cpus", (unsigned) domain, (unsigned) bus, (unsigned) dev);
0114   if (hwloc_linux_read_path_as_cpumask(path, set) < 0
0115       || hwloc_bitmap_iszero(set))
0116     hwloc_bitmap_copy(set, hwloc_topology_get_complete_cpuset(topology));
0117 #else
0118   /* Non-Linux systems simply get a full cpuset */
0119   hwloc_bitmap_copy(set, hwloc_topology_get_complete_cpuset(topology));
0120 #endif
0121   return 0;
0122 }
0123 
0124 /** \brief Get the hwloc PCI device object corresponding to the
0125  * CUDA device whose index is \p idx.
0126  *
0127  * \return The hwloc PCI device object describing the CUDA device whose index is \p idx.
0128  * \return \c NULL if none could be found.
0129  *
0130  * Topology \p topology and device \p idx must match the local machine.
0131  * I/O devices detection must be enabled in topology \p topology.
0132  * The CUDA component is not needed in the topology.
0133  */
0134 static __hwloc_inline hwloc_obj_t
0135 hwloc_cudart_get_device_pcidev(hwloc_topology_t topology, int idx)
0136 {
0137   int domain, bus, dev;
0138 
0139   if (hwloc_cudart_get_device_pci_ids(topology, idx, &domain, &bus, &dev))
0140     return NULL;
0141 
0142   return hwloc_get_pcidev_by_busid(topology, domain, bus, dev, 0);
0143 }
0144 
0145 /** \brief Get the hwloc OS device object corresponding to the
0146  * CUDA device whose index is \p idx.
0147  *
0148  * \return The hwloc OS device object describing the CUDA device whose index is \p idx.
0149  * \return \c NULL if none could be found.
0150  *
0151  * The topology \p topology does not necessarily have to match the current
0152  * machine. For instance the topology may be an XML import of a remote host.
0153  * I/O devices detection and the CUDA component must be enabled in the topology.
0154  * If not, the locality of the object may still be found using
0155  * hwloc_cudart_get_device_cpuset().
0156  *
0157  * \note The corresponding PCI device object can be obtained by looking
0158  * at the OS device parent object (unless PCI devices are filtered out).
0159  *
0160  * \note This function is identical to hwloc_cuda_get_device_osdev_by_index().
0161  */
0162 static __hwloc_inline hwloc_obj_t
0163 hwloc_cudart_get_device_osdev_by_index(hwloc_topology_t topology, unsigned idx)
0164 {
0165     hwloc_obj_t osdev = NULL;
0166     while ((osdev = hwloc_get_next_osdev(topology, osdev)) != NULL) {
0167         if (HWLOC_OBJ_OSDEV_COPROC == osdev->attr->osdev.type
0168             && osdev->name
0169             && !strncmp("cuda", osdev->name, 4)
0170             && atoi(osdev->name + 4) == (int) idx)
0171             return osdev;
0172     }
0173     return NULL;
0174 }
0175 
0176 /** @} */
0177 
0178 
0179 #ifdef __cplusplus
0180 } /* extern "C" */
0181 #endif
0182 
0183 
0184 #endif /* HWLOC_CUDART_H */