Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:01:15

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