diff --git a/.github/scripts/run-codespell.py b/.github/scripts/run-codespell.py index 14faf1e79..7fc4f5f3b 100644 --- a/.github/scripts/run-codespell.py +++ b/.github/scripts/run-codespell.py @@ -21,7 +21,7 @@ def codespell_scan(): "codespell", "-H", "--quiet-level=3", - "--skip=./.git,./.venv,./.github/workflows/.spellcheck-conf.toml", + "--skip=./.git,./.venv,./.github/workflows/.spellcheck-conf.toml,./src/deps", ], text=True, stdout=subprocess.PIPE, diff --git a/.github/workflows/.spellcheck-conf.toml b/.github/workflows/.spellcheck-conf.toml index bb0f480d6..bb35b3163 100644 --- a/.github/workflows/.spellcheck-conf.toml +++ b/.github/workflows/.spellcheck-conf.toml @@ -4,4 +4,4 @@ extend-ignore-words-re = ["ASSER", "Tne", "ba", "BA", "PN", "usm"] [files] # completely exclude those files from consideration: -extend-exclude = ["test/supp/*.supp"] +extend-exclude = ["test/supp/*.supp", "src/deps/**"] diff --git a/.github/workflows/reusable_basic.yml b/.github/workflows/reusable_basic.yml index a4108a9b3..80a88db57 100644 --- a/.github/workflows/reusable_basic.yml +++ b/.github/workflows/reusable_basic.yml @@ -33,6 +33,7 @@ jobs: cuda_provider: ['ON'] install_tbb: ['ON'] link_hwloc_statically: ['OFF'] + use_bundled_hwloc: ['OFF'] cmake_ver: ['default'] include: - os: ubuntu-22.04 @@ -135,7 +136,18 @@ jobs: link_hwloc_statically: 'ON' local_hwloc: 'mirror' cmake_ver: 'default' - name: Basic (${{matrix.os}}, build_type=${{matrix.build_type}}, compilers=${{matrix.compiler.c}}/${{matrix.compiler.cxx}}, shared_library=${{matrix.shared_library}}, level_zero_provider=${{matrix.level_zero_provider}}, cuda_provider=${{matrix.cuda_provider}}, install_tbb=${{matrix.install_tbb}}, link_hwloc_statically=${{matrix.link_hwloc_statically}}, cmake_ver=${{matrix.cmake_ver}}${{ matrix.local_hwloc && format(', local_hwloc={0}', matrix.local_hwloc) || '' }}) + # test static hwloc built from the bundled source (UMF_USE_BUNDLED_HWLOC) + - os: ubuntu-22.04 + build_type: Release + compiler: {c: gcc, cxx: g++} + shared_library: 'ON' + level_zero_provider: 'ON' + cuda_provider: 'ON' + install_tbb: 'ON' + link_hwloc_statically: 'ON' + use_bundled_hwloc: 'ON' + cmake_ver: 'default' + name: Basic (${{matrix.os}}, build_type=${{matrix.build_type}}, compilers=${{matrix.compiler.c}}/${{matrix.compiler.cxx}}, shared_library=${{matrix.shared_library}}, level_zero_provider=${{matrix.level_zero_provider}}, cuda_provider=${{matrix.cuda_provider}}, install_tbb=${{matrix.install_tbb}}, link_hwloc_statically=${{matrix.link_hwloc_statically}}, use_bundled_hwloc=${{matrix.use_bundled_hwloc || 'OFF'}}${{ matrix.local_hwloc && format(', local_hwloc={0}', matrix.local_hwloc) || '' }}, cmake_ver=${{matrix.cmake_ver}}) steps: - name: Checkout @@ -195,6 +207,7 @@ jobs: -DUMF_LINK_HWLOC_STATICALLY=${{matrix.link_hwloc_statically}} ${{ matrix.local_hwloc == 'source' && format('-DUMF_HWLOC_SOURCE_DIR={0}', env.HWLOC_SRC_DIR) || '' }} ${{ matrix.local_hwloc == 'mirror' && format('-DUMF_HWLOC_REPO={0}', env.HWLOC_MIRROR_DIR) || '' }} + -DUMF_USE_BUNDLED_HWLOC=${{matrix.use_bundled_hwloc || 'OFF'}} ${{ matrix.build_type == 'Debug' && matrix.compiler.c == 'gcc' && '-DUMF_USE_COVERAGE=ON' || '' }} ${{ matrix.llvm_linker || '' }} @@ -238,6 +251,53 @@ jobs: --umf-version ${{env.UMF_VERSION}} ${{ matrix.shared_library == 'ON' && '--shared-library' || '' }} + ubuntu-static_hwloc_installed_umf: + name: "Ubuntu static UMF + static hwloc, installed UMF (bundled=${{matrix.use_bundled_hwloc}})" + runs-on: ubuntu-latest + strategy: + matrix: + build_type: [Release] + use_bundled_hwloc: ['OFF', 'ON'] + + steps: + - name: Checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 0 + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y libhwloc-dev ${{ matrix.use_bundled_hwloc == 'OFF' && 'autoconf automake libtool' || '' }} + + - name: Configure build + run: > + cmake + -B ${{env.BUILD_DIR}} + -DCMAKE_INSTALL_PREFIX="${{env.INSTL_DIR}}" + -DCMAKE_BUILD_TYPE=${{matrix.build_type}} + -DUMF_BUILD_SHARED_LIBRARY=OFF + -DUMF_BUILD_TESTS=OFF + -DUMF_BUILD_EXAMPLES=OFF + -DUMF_FORMAT_CODE_STYLE=OFF + -DUMF_DEVELOPER_MODE=ON + -DUMF_BUILD_LIBUMF_POOL_JEMALLOC=OFF + -DUMF_BUILD_LEVEL_ZERO_PROVIDER=OFF + -DUMF_BUILD_CUDA_PROVIDER=OFF + -DUMF_LINK_HWLOC_STATICALLY=ON + -DUMF_USE_BUNDLED_HWLOC=${{matrix.use_bundled_hwloc}} + + - name: Build and install UMF + run: | + cmake --build ${{env.BUILD_DIR}} -j $(nproc) + cmake --install ${{env.BUILD_DIR}} + + - name: Build and run consumer of installed UMF + run: | + cmake -S ${{github.workspace}}/test/install_test -B ${{github.workspace}}/install_test-build -DCMAKE_BUILD_TYPE=${{matrix.build_type}} -DCMAKE_PREFIX_PATH="${{env.INSTL_DIR}}" -DUMF_TEST_LINK_USER_HWLOC=ON + cmake --build ${{github.workspace}}/install_test-build -j $(nproc) + ctest --test-dir ${{github.workspace}}/install_test-build --output-on-failure + windows-build: env: BUILD_DEBUG_DIR : "${{github.workspace}}/debug/build" @@ -493,10 +553,11 @@ jobs: key: ${{ steps.cache.outputs.cache-primary-key }} windows-dynamic_build_hwloc: - name: "Windows dynamic UMF + static hwloc" + name: "Windows dynamic UMF + static hwloc (bundled=${{matrix.use_bundled_hwloc}})" strategy: matrix: build_type: [Release] + use_bundled_hwloc: ['OFF', 'ON'] runs-on: 'windows-latest' @@ -520,6 +581,7 @@ jobs: -DUMF_BUILD_CUDA_PROVIDER=ON -DUMF_TESTS_FAIL_ON_SKIP=ON -DUMF_LINK_HWLOC_STATICALLY=ON + -DUMF_USE_BUNDLED_HWLOC=${{matrix.use_bundled_hwloc}} - name: Build UMF run: cmake --build ${{env.BUILD_DIR}} --config ${{matrix.build_type}} -j $Env:NUMBER_OF_PROCESSORS @@ -576,6 +638,62 @@ jobs: working-directory: ${{env.BUILD_DIR}} run: ctest -C ${{matrix.build_type}} --output-on-failure --test-dir test + windows-static_hwloc_installed_umf: + name: "Windows static UMF + static hwloc, installed UMF (bundled=${{matrix.use_bundled_hwloc}})" + strategy: + matrix: + build_type: [Release] + use_bundled_hwloc: ['OFF', 'ON'] + + runs-on: 'windows-latest' + + steps: + - name: Checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 0 + + - name: Configure build + run: > + cmake + -B ${{env.BUILD_DIR}} + -DCMAKE_INSTALL_PREFIX="${{env.INSTL_DIR}}" + -DUMF_BUILD_SHARED_LIBRARY=OFF + -DUMF_BUILD_TESTS=OFF + -DUMF_BUILD_EXAMPLES=OFF + -DUMF_FORMAT_CODE_STYLE=OFF + -DUMF_DEVELOPER_MODE=ON + -DUMF_BUILD_LIBUMF_POOL_JEMALLOC=OFF + -DUMF_BUILD_LEVEL_ZERO_PROVIDER=OFF + -DUMF_BUILD_CUDA_PROVIDER=OFF + -DUMF_LINK_HWLOC_STATICALLY=ON + -DUMF_USE_BUNDLED_HWLOC=${{matrix.use_bundled_hwloc}} + + - name: Build and install UMF + run: | + cmake --build ${{env.BUILD_DIR}} --config ${{matrix.build_type}} -j $Env:NUMBER_OF_PROCESSORS + cmake --install ${{env.BUILD_DIR}} --config ${{matrix.build_type}} + + # The bundled hwloc uses the umf_hwloc_ symbol prefix, so a consumer may + # link its own hwloc alongside the installed static UMF. + - name: Install user hwloc + if: matrix.use_bundled_hwloc == 'ON' + run: | + vcpkg install --classic hwloc:x64-windows + echo "$env:VCPKG_INSTALLATION_ROOT\installed\x64-windows\bin" >> $env:GITHUB_PATH + + - name: Build and run test of installed UMF + run: | + $extraArgs = @() + $prefixPath = "${{env.INSTL_DIR}}" + if ('${{matrix.use_bundled_hwloc}}' -eq 'ON') { + $prefixPath += ";$env:VCPKG_INSTALLATION_ROOT\installed\x64-windows" + $extraArgs += '-DUMF_TEST_LINK_USER_HWLOC=ON' + } + cmake -S ${{github.workspace}}/test/install_test -B ${{github.workspace}}/install_test-build -DCMAKE_PREFIX_PATH="$prefixPath" @extraArgs + cmake --build ${{github.workspace}}/install_test-build --config ${{matrix.build_type}} + ctest --test-dir ${{github.workspace}}/install_test-build -C ${{matrix.build_type}} --output-on-failure + macos-build: strategy: matrix: diff --git a/CMakeLists.txt b/CMakeLists.txt index 4aa315d64..1d3ef224f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -80,6 +80,13 @@ umf_option( UMF_LINK_HWLOC_STATICALLY "Link UMF with HWLOC library statically (proxy library will be disabled on Windows+Debug build)" OFF) +umf_option(UMF_USE_BUNDLED_HWLOC + "Use the prebuilt x86-64 static hwloc library in src/deps/hwloc" OFF) +if(UMF_USE_BUNDLED_HWLOC AND NOT UMF_LINK_HWLOC_STATICALLY) + message( + FATAL_ERROR + "UMF_USE_BUNDLED_HWLOC requires UMF_LINK_HWLOC_STATICALLY=ON") +endif() set(UMF_HWLOC_NAME "hwloc" CACHE STRING "Custom name for hwloc library w/o extension") @@ -295,7 +302,55 @@ if(NOT UMF_LINK_HWLOC_STATICALLY) endif() endif() -if(UMF_LINK_HWLOC_STATICALLY) +if(UMF_USE_BUNDLED_HWLOC) + if(NOT LINUX AND NOT WINDOWS) + message( + FATAL_ERROR "Bundled hwloc is only available on Linux and Windows") + endif() + set(UMF_BUNDLED_HWLOC_ARCH "${CMAKE_C_COMPILER_ARCHITECTURE_ID}") + if(NOT WINDOWS OR NOT UMF_BUNDLED_HWLOC_ARCH) + set(UMF_BUNDLED_HWLOC_ARCH "${CMAKE_SYSTEM_PROCESSOR}") + endif() + if(NOT UMF_BUNDLED_HWLOC_ARCH MATCHES "^(x86_64|AMD64|amd64|x64)$") + message( + FATAL_ERROR + "Bundled hwloc is available only for x86-64, but the target " + "architecture is '${UMF_BUNDLED_HWLOC_ARCH}' " + "Set UMF_USE_BUNDLED_HWLOC=OFF to build hwloc from sources.") + endif() + set(UMF_BUNDLED_HWLOC_DIR "${UMF_CMAKE_SOURCE_DIR}/src/deps/hwloc") + set(LIBHWLOC_LIBRARY_DIRS "${UMF_BUNDLED_HWLOC_DIR}/${OS_NAME}") + set(LIBHWLOC_INCLUDE_DIRS "${LIBHWLOC_LIBRARY_DIRS}/include" + "${UMF_BUNDLED_HWLOC_DIR}/include") + if(WINDOWS) + set(LIBHWLOC_LIBRARIES "${LIBHWLOC_LIBRARY_DIRS}/hwloc.lib") + else() + set(LIBHWLOC_LIBRARIES "${LIBHWLOC_LIBRARY_DIRS}/libhwloc.a") + endif() + + foreach( + HWLOC_REQUIRED_FILE IN + ITEMS "${LIBHWLOC_LIBRARIES}" + "${UMF_BUNDLED_HWLOC_DIR}/include/hwloc.h" + "${LIBHWLOC_LIBRARY_DIRS}/include/hwloc/autogen/config.h") + if(NOT EXISTS "${HWLOC_REQUIRED_FILE}") + message( + FATAL_ERROR + "Bundled hwloc file not found: ${HWLOC_REQUIRED_FILE}") + endif() + endforeach() + + message(STATUS "Using bundled hwloc from ${UMF_BUNDLED_HWLOC_DIR}") + + add_library(${UMF_HWLOC_NAME} INTERFACE) + target_link_libraries(${UMF_HWLOC_NAME} INTERFACE "${LIBHWLOC_LIBRARIES}") + target_include_directories(${UMF_HWLOC_NAME} + INTERFACE ${LIBHWLOC_INCLUDE_DIRS}) + set(LIBHWLOC_FOUND TRUE) +elseif(UMF_LINK_HWLOC_STATICALLY) + if(NOT DEFINED UMF_HWLOC_REPO) + set(UMF_HWLOC_REPO "https://github.com/open-mpi/hwloc.git") + endif() if(NOT DEFINED UMF_HWLOC_TAG) set(UMF_HWLOC_TAG hwloc-2.13.0) endif() @@ -398,6 +453,9 @@ if(UMF_LINK_HWLOC_STATICALLY) ) endif() + # All symbols defined in the hwloc library must have the 'umf_hwloc_' + # prefix, so that they do not conflict with other hwloc instances linked + # into the same application. ExternalProject_Add( hwloc_targ PREFIX ${hwloc_targ_PREFIX} @@ -412,9 +470,10 @@ if(UMF_LINK_HWLOC_STATICALLY) ${CMAKE_COMMAND} -E env "CC=${UMF_HWLOC_CC}" "CXX=${UMF_HWLOC_CXX}" /configure --prefix= --enable-static=yes --enable-shared=no - --disable-libxml2 --disable-pci --disable-levelzero - --disable-opencl --disable-cuda --disable-nvml --disable-libudev - --disable-rsmi CFLAGS=-fPIC CXXFLAGS=-fPIC + --with-hwloc-symbol-prefix=umf_hwloc_ --disable-libxml2 + --disable-pci --disable-levelzero --disable-opencl + --disable-cuda --disable-nvml --disable-libudev --disable-rsmi + "CFLAGS=-O2 -fPIC" "CXXFLAGS=-O2 -fPIC" BUILD_COMMAND make BUILD_IN_SOURCE TRUE INSTALL_COMMAND make install @@ -596,6 +655,7 @@ if(WINDOWS AND UMF_USE_DEBUG_POSTFIX) -DUMF_BUILD_EXAMPLES=OFF -DUMF_BUILD_GPU_EXAMPLES=OFF -DUMF_BUILD_FUZZTESTS=OFF -DUMF_LINK_HWLOC_STATICALLY=${UMF_LINK_HWLOC_STATICALLY} + -DUMF_USE_BUNDLED_HWLOC=${UMF_USE_BUNDLED_HWLOC} -DUMF_HWLOC_NAME=${UMF_HWLOC_NAME} -DUMF_HWLOC_SOURCE_DIR="${UMF_HWLOC_SOURCE_DIR}" -DUMF_HWLOC_REPO="${UMF_HWLOC_REPO}" @@ -921,6 +981,13 @@ if(UMF_FORMAT_CODE_STYLE) "${DIR}/**/*.cpp") endforeach() file(GLOB_RECURSE format_list ${format_clang_glob}) + # exclude files in the src/deps/ directory from formatting checks + list( + FILTER + format_list + EXCLUDE + REGEX + "/src/deps/") message( STATUS @@ -1087,7 +1154,7 @@ install(TARGETS umf_headers EXPORT ${PROJECT_NAME}-targets) # Add the list of installed targets to the install. This includes the namespace # which all installed targets will be prefixed with, e.g. for the headers target -# users will depend on ${PROJECT_NAME}::headers. +# users will depend on ${PROJECT_NAME}::umf_headers. install( EXPORT ${PROJECT_NAME}-targets FILE ${PROJECT_NAME}-targets.cmake diff --git a/README.md b/README.md index ff277e3f0..ebfd99866 100644 --- a/README.md +++ b/README.md @@ -143,6 +143,7 @@ List of options provided by CMake: | UMF_LINK_HWLOC_STATICALLY | Link UMF with HWLOC library statically (proxy library will be disabled on Windows+Debug build) | ON/OFF | OFF | | UMF_HWLOC_SOURCE_DIR | Path to local hwloc sources used instead of fetching them (with UMF_LINK_HWLOC_STATICALLY) | path | "" | | UMF_HWLOC_REPO | hwloc git repository URL or local mirror path (with UMF_LINK_HWLOC_STATICALLY) | URL/path | https://github.com/open-mpi/hwloc.git | +| UMF_USE_BUNDLED_HWLOC | Use prebuilt x86-64 hwloc from `src/deps/hwloc` (requires `UMF_LINK_HWLOC_STATICALLY=ON`) | ON/OFF | OFF | ## Architecture: memory pools and providers diff --git a/scripts/check_license/file-exceptions.sh b/scripts/check_license/file-exceptions.sh index d3580f33d..d085b300b 100755 --- a/scripts/check_license/file-exceptions.sh +++ b/scripts/check_license/file-exceptions.sh @@ -17,6 +17,7 @@ grep -v -E -e 'benchmark/ubench.h' \ -e 'licensing/third-party-programs.txt' \ -e 'scripts/assets/images/.*' \ -e 'scripts/qemu/requirements.txt' \ + -e '^src/deps/' \ -e 'src/uthash/.*' \ -e 'src/uthash/utlist.h' \ -e 'src/uthash/uthash.h' \ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a35abd31b..557bcdcd4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -137,6 +137,27 @@ if(UMF_BUILD_SHARED_LIBRARY) VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION_MAJOR}) else() + if(UMF_LINK_HWLOC_STATICALLY) + # hwloc fetched on Windows installs its own archive + if(UMF_USE_BUNDLED_HWLOC OR NOT WINDOWS) + # A UMF-specific name, so find_library(hwloc) never picks this copy + set(UMF_HWLOC_ARCHIVE_NAME + "${CMAKE_STATIC_LIBRARY_PREFIX}umf_hwloc${CMAKE_STATIC_LIBRARY_SUFFIX}" + ) + install( + FILES "${LIBHWLOC_LIBRARIES}" + DESTINATION ${CMAKE_INSTALL_LIBDIR} + RENAME ${UMF_HWLOC_ARCHIVE_NAME}) + else() + get_filename_component(UMF_HWLOC_ARCHIVE_NAME + "${LIBHWLOC_LIBRARIES}" NAME) + endif() + set(UMF_LIBS + ${UMF_LIBS} + "$/${CMAKE_INSTALL_LIBDIR}/${UMF_HWLOC_ARCHIVE_NAME}>" + ) + endif() + add_umf_library( NAME umf TYPE STATIC diff --git a/src/deps/hwloc/include/hwloc.h b/src/deps/hwloc/include/hwloc.h new file mode 100644 index 000000000..155e45f5b --- /dev/null +++ b/src/deps/hwloc/include/hwloc.h @@ -0,0 +1,2878 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * Copyright © 2009 CNRS + * Copyright © 2009-2025 Inria. All rights reserved. + * Copyright © 2009-2012 Université Bordeaux + * Copyright © 2009-2020 Cisco Systems, Inc. All rights reserved. + * See COPYING in top-level directory. + */ + +/*===================================================================== + * PLEASE GO READ THE DOCUMENTATION! + * ------------------------------------------------ + * $tarball_directory/doc/doxygen-doc/ + * or + * https://www.open-mpi.org/projects/hwloc/doc/ + *===================================================================== + * + * FAIR WARNING: Do NOT expect to be able to figure out all the + * subtleties of hwloc by simply reading function prototypes and + * constant descrptions here in this file. + * + * Hwloc has wonderful documentation in both PDF and HTML formats for + * your reading pleasure. The formal documentation explains a LOT of + * hwloc-specific concepts, provides definitions, and discusses the + * "big picture" for many of the things that you'll find here in this + * header file. + * + * The PDF/HTML documentation was generated via Doxygen; much of what + * you'll see in there is also here in this file. BUT THERE IS A LOT + * THAT IS IN THE PDF/HTML THAT IS ***NOT*** IN hwloc.h! + * + * There are entire paragraph-length descriptions, discussions, and + * pretty pictures to explain subtle corner cases, provide concrete + * examples, etc. + * + * Please, go read the documentation. :-) + * + * Moreover there are several examples of hwloc use under doc/examples + * in the source tree. + * + *=====================================================================*/ + +/** \file + * \brief The hwloc API. + * + * See hwloc/bitmap.h for bitmap specific macros. + * See hwloc/helper.h for high-level topology traversal helpers. + * See hwloc/inlines.h for the actual inline code of some functions below. + * See hwloc/export.h for exporting topologies to XML or to synthetic descriptions. + * See hwloc/distances.h for querying and modifying distances between objects. + * See hwloc/memattrs.h for querying and modifying memory attributes such as Bandwidth. + * See hwloc/cpukinds.h for querying and modifying kinds of CPU cores. + * See hwloc/diff.h for manipulating differences between similar topologies. + */ + +#ifndef HWLOC_H +#define HWLOC_H + +#include "hwloc/autogen/config.h" + +#include +#include +#include +#include + +/* + * Symbol transforms + */ +#include "hwloc/rename.h" + +/* + * Bitmap definitions + */ + +#include "hwloc/bitmap.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** \defgroup hwlocality_api_error_reporting Error reporting in the API + * @{ + * Most functions in the hwloc API return an integer value. + * Unless documentated differently, they return 0 on success + * and -1 on error. + * Functions that return a pointer type return \c NULL on error. + * + * \p errno will be set to a meaningful value whenever possible. + * This includes the usual \c EINVAL when invalid function parameters are passed + * or \c ENOMEM when an internal allocation fails. + * Some specific \c errno value are also used, for instance for binding + * errors as documented in \ref hwlocality_cpubinding. + * + * Some modules describe return values of their functions + * in their introduction, for instance in \ref hwlocality_bitmap. + * @} + */ + + +/** \defgroup hwlocality_api_version API version + * @{ + */ + +/** \brief Indicate at build time which hwloc API version is being used. + * + * This number is updated to (X<<16)+(Y<<8)+Z when a new release X.Y.Z + * actually modifies the API. + * + * Users may check for available features at build time using this number + * (see \ref faq_version_api). + * + * \note This should not be confused with HWLOC_VERSION, the library version. + * Two stable releases of the same series usually have the same ::HWLOC_API_VERSION + * even if their HWLOC_VERSION are different. + */ +#define HWLOC_API_VERSION 0x00020c00 + +/** \brief Indicate at runtime which hwloc API version was used at build time. + * + * Should be ::HWLOC_API_VERSION if running on the same version. + * + * \return the build-time version number. + */ +HWLOC_DECLSPEC unsigned hwloc_get_api_version(void); + +/** \brief Current component and plugin ABI version (see hwloc/plugins.h) */ +#define HWLOC_COMPONENT_ABI 7 + +/** @} */ + + + +/** \defgroup hwlocality_object_sets Object Sets (hwloc_cpuset_t and hwloc_nodeset_t) + * + * Hwloc uses bitmaps to represent two distinct kinds of object sets: + * CPU sets (::hwloc_cpuset_t) and NUMA node sets (::hwloc_nodeset_t). + * These types are both typedefs to a common back end type + * (::hwloc_bitmap_t), and therefore all the hwloc bitmap functions + * are applicable to both ::hwloc_cpuset_t and ::hwloc_nodeset_t (see + * \ref hwlocality_bitmap). + * + * The rationale for having two different types is that even though + * the actions one wants to perform on these types are the same (e.g., + * enable and disable individual items in the set/mask), they're used + * in very different contexts: one for specifying which processors to + * use and one for specifying which NUMA nodes to use. Hence, the + * name difference is really just to reflect the intent of where the + * type is used. + * + * @{ + */ + +/** \brief A CPU set is a bitmap whose bits are set according to CPU + * physical OS indexes. + * + * It may be consulted and modified with the bitmap API as any + * ::hwloc_bitmap_t (see hwloc/bitmap.h). + * + * Each bit may be converted into a PU object using + * hwloc_get_pu_obj_by_os_index(). + * \sa faq_indexes + */ +typedef hwloc_bitmap_t hwloc_cpuset_t; +/** \brief A non-modifiable ::hwloc_cpuset_t. */ +typedef hwloc_const_bitmap_t hwloc_const_cpuset_t; + +/** \brief A node set is a bitmap whose bits are set according to NUMA + * memory node physical OS indexes. + * + * It may be consulted and modified with the bitmap API as any + * ::hwloc_bitmap_t (see hwloc/bitmap.h). + * Each bit may be converted into a NUMA node object using + * hwloc_get_numanode_obj_by_os_index(). + * \sa faq_indexes + * + * When binding memory on a system without any NUMA node, + * the single main memory bank is considered as NUMA node #0. + * + * See also \ref hwlocality_helper_nodeset_convert. + */ +typedef hwloc_bitmap_t hwloc_nodeset_t; +/** \brief A non-modifiable ::hwloc_nodeset_t. + */ +typedef hwloc_const_bitmap_t hwloc_const_nodeset_t; + +/** @} */ + + + +/** \defgroup hwlocality_object_types Object Types + * @{ + */ + +/** \brief Type of topology object. + * + * \note Do not rely on the ordering or completeness of the values as new ones + * may be defined in the future! If you need to compare types, use + * hwloc_compare_types() instead. + */ +typedef enum { + +/** \cond */ +#define HWLOC_OBJ_TYPE_MIN HWLOC_OBJ_MACHINE /* Sentinel value */ +/** \endcond */ + + HWLOC_OBJ_MACHINE, /**< \brief Machine. + * A set of processors and memory with cache + * coherency. + * + * This type is always used for the root object of a topology, + * and never used anywhere else. + * Hence its parent is always \c NULL. + */ + + HWLOC_OBJ_PACKAGE, /**< \brief Physical package. + * The physical package that usually gets inserted + * into a socket on the motherboard. + * A processor package usually contains multiple cores, + * and possibly some dies. + */ + HWLOC_OBJ_CORE, /**< \brief Core. + * A computation unit (may be shared by several + * PUs, aka logical processors). + */ + HWLOC_OBJ_PU, /**< \brief Processing Unit, or (Logical) Processor. + * An execution unit (may share a core with some + * other logical processors, e.g. in the case of + * an SMT core). + * + * This is the smallest object representing CPU resources, + * it cannot have any child except Misc objects. + * + * Objects of this kind are always reported and can + * thus be used as fallback when others are not. + */ + + HWLOC_OBJ_L1CACHE, /**< \brief Level 1 Data (or Unified) Cache. */ + HWLOC_OBJ_L2CACHE, /**< \brief Level 2 Data (or Unified) Cache. */ + HWLOC_OBJ_L3CACHE, /**< \brief Level 3 Data (or Unified) Cache. */ + HWLOC_OBJ_L4CACHE, /**< \brief Level 4 Data (or Unified) Cache. */ + HWLOC_OBJ_L5CACHE, /**< \brief Level 5 Data (or Unified) Cache. */ + + HWLOC_OBJ_L1ICACHE, /**< \brief Level 1 instruction Cache (filtered out by default). */ + HWLOC_OBJ_L2ICACHE, /**< \brief Level 2 instruction Cache (filtered out by default). */ + HWLOC_OBJ_L3ICACHE, /**< \brief Level 3 instruction Cache (filtered out by default). */ + + HWLOC_OBJ_GROUP, /**< \brief Group objects. + * Objects which do not fit in the above but are + * detected by hwloc and are useful to take into + * account for affinity. For instance, some operating systems + * expose their arbitrary processors aggregation this + * way. And hwloc may insert such objects to group + * NUMA nodes according to their distances. + * See also \ref faq_groups. + * + * These objects are removed when they do not bring + * any structure (see ::HWLOC_TYPE_FILTER_KEEP_STRUCTURE). + */ + + HWLOC_OBJ_NUMANODE, /**< \brief NUMA node. + * An object that contains memory that is directly + * and byte-accessible to the host processors. + * It is usually close to some cores (the corresponding objects + * are descendants of the NUMA node object in the hwloc tree). + * + * This is the smallest object representing Memory resources, + * it cannot have any child except Misc objects. + * However it may have Memory-side cache parents. + * + * NUMA nodes may correspond to different kinds of memory + * (DRAM, HBM, CXL-DRAM, etc.). When hwloc is able to guess + * that kind, it is specified in the subtype field of the object. + * See also \ref attributes_normal in the main documentation. + * + * There is always at least one such object in the topology + * even if the machine is not NUMA. + * + * Memory objects are not listed in the main children list, + * but rather in the dedicated Memory children list. + * + * NUMA nodes have a special depth ::HWLOC_TYPE_DEPTH_NUMANODE + * instead of a normal depth just like other objects in the + * main tree. + */ + + HWLOC_OBJ_BRIDGE, /**< \brief Bridge (filtered out by default). + * Any bridge (or PCI switch) that connects the host or an I/O bus, + * to another I/O bus. + * + * Bridges are not added to the topology unless their + * filtering is changed (see hwloc_topology_set_type_filter() + * and hwloc_topology_set_io_types_filter()). + * + * I/O objects are not listed in the main children list, + * but rather in the dedicated io children list. + * I/O objects have NULL CPU and node sets. + */ + HWLOC_OBJ_PCI_DEVICE, /**< \brief PCI device (filtered out by default). + * + * PCI devices are not added to the topology unless their + * filtering is changed (see hwloc_topology_set_type_filter() + * and hwloc_topology_set_io_types_filter()). + * + * I/O objects are not listed in the main children list, + * but rather in the dedicated io children list. + * I/O objects have NULL CPU and node sets. + */ + HWLOC_OBJ_OS_DEVICE, /**< \brief Operating system device (filtered out by default). + * + * OS devices are not added to the topology unless their + * filtering is changed (see hwloc_topology_set_type_filter() + * and hwloc_topology_set_io_types_filter()). + * + * I/O objects are not listed in the main children list, + * but rather in the dedicated io children list. + * I/O objects have NULL CPU and node sets. + */ + + HWLOC_OBJ_MISC, /**< \brief Miscellaneous objects (filtered out by default). + * Objects without particular meaning, that can e.g. be + * added by the application for its own use, or by hwloc + * for miscellaneous objects such as MemoryModule (DIMMs). + * + * They are not added to the topology unless their filtering + * is changed (see hwloc_topology_set_type_filter()). + * + * These objects are not listed in the main children list, + * but rather in the dedicated misc children list. + * Misc objects may only have Misc objects as children, + * and those are in the dedicated misc children list as well. + * Misc objects have NULL CPU and node sets. + */ + + HWLOC_OBJ_MEMCACHE, /**< \brief Memory-side cache (filtered out by default). + * A cache in front of a specific NUMA node. + * + * This object always has at least one NUMA node as a memory child. + * + * Memory objects are not listed in the main children list, + * but rather in the dedicated Memory children list. + * + * Memory-side cache have a special depth ::HWLOC_TYPE_DEPTH_MEMCACHE + * instead of a normal depth just like other objects in the + * main tree. + */ + + HWLOC_OBJ_DIE, /**< \brief Die within a physical package. + * A subpart of the physical package, that contains multiple cores. + * + * Some operating systems (e.g. Linux) may expose a single die per package + * even if the hardware does not support dies at all. To avoid showing + * such non-existing dies, hwloc will filter them out if all of them are + * identical to packages. + * This is functionally equivalent to ::HWLOC_TYPE_FILTER_KEEP_STRUCTURE + * being enforced for Dies versus Packages. + */ + + HWLOC_OBJ_TYPE_MAX /**< \private Sentinel value */ +} hwloc_obj_type_t; + +/** \brief Cache type. */ +typedef enum hwloc_obj_cache_type_e { + HWLOC_OBJ_CACHE_UNIFIED, /**< \brief Unified cache. */ + HWLOC_OBJ_CACHE_DATA, /**< \brief Data cache. */ + HWLOC_OBJ_CACHE_INSTRUCTION /**< \brief Instruction cache (filtered out by default). */ +} hwloc_obj_cache_type_t; + +/** \brief Type of one side (upstream or downstream) of an I/O bridge. */ +typedef enum hwloc_obj_bridge_type_e { + HWLOC_OBJ_BRIDGE_HOST, /**< \brief Host-side of a bridge, only possible upstream. */ + HWLOC_OBJ_BRIDGE_PCI /**< \brief PCI-side of a bridge. */ +} hwloc_obj_bridge_type_t; + +/** \brief Type of a OS device. */ +typedef enum hwloc_obj_osdev_type_e { + HWLOC_OBJ_OSDEV_BLOCK, /**< \brief Operating system block device, or non-volatile memory device. + * For instance "sda" or "dax2.0" on Linux. */ + HWLOC_OBJ_OSDEV_GPU, /**< \brief Operating system GPU device. + * For instance ":0.0" for a GL display, + * "card0" for a Linux DRM device. */ + HWLOC_OBJ_OSDEV_NETWORK, /**< \brief Operating system network device. + * For instance the "eth0" interface on Linux. */ + HWLOC_OBJ_OSDEV_OPENFABRICS, /**< \brief Operating system openfabrics device. + * For instance the "mlx4_0" InfiniBand HCA, + * "hfi1_0" Omni-Path interface, + * or "bxi0" Atos/Bull BXI HCA on Linux. */ + HWLOC_OBJ_OSDEV_DMA, /**< \brief Operating system dma engine device. + * For instance the "dma0chan0" DMA channel on Linux. */ + HWLOC_OBJ_OSDEV_COPROC /**< \brief Operating system co-processor device. + * For instance "opencl0d0" for a OpenCL device, + * "cuda0" for a CUDA device. */ +} hwloc_obj_osdev_type_t; + +/** \brief Compare the depth of two object types + * + * Types shouldn't be compared as they are, since newer ones may be added in + * the future. + * + * \return A negative integer if \p type1 objects usually include \p type2 objects. + * \return A positive integer if \p type1 objects are usually included in \p type2 objects. + * \return 0 if \p type1 and \p type2 objects are the same. + * \return ::HWLOC_TYPE_UNORDERED if objects cannot be compared + * (because neither is usually contained in the other). + * + * \note Object types containing CPUs can always be compared + * (usually, a machine contains packages, which contain caches, + * which contain cores, which contain PUs). + * + * \note ::HWLOC_OBJ_PU will always be the deepest, + * while ::HWLOC_OBJ_MACHINE is always the highest. + * + * \note This does not mean that the actual topology will respect that order: + * e.g. as of today cores may also contain caches, and packages may also contain + * nodes. This is thus just to be seen as a fallback comparison method. + */ +HWLOC_DECLSPEC int hwloc_compare_types (hwloc_obj_type_t type1, hwloc_obj_type_t type2) __hwloc_attribute_const; + +/** \brief Value returned by hwloc_compare_types() when types can not be compared. \hideinitializer */ +#define HWLOC_TYPE_UNORDERED INT_MAX + +/** @} */ + + + +/** \defgroup hwlocality_objects Object Structure and Attributes + * @{ + */ + +union hwloc_obj_attr_u; + +/** \brief Structure of a topology object + * + * Applications must not modify any field except \p hwloc_obj.userdata. + */ +struct hwloc_obj { + /* physical information */ + hwloc_obj_type_t type; /**< \brief Type of object */ + char *subtype; /**< \brief Subtype string to better describe the type field. */ + + unsigned os_index; /**< \brief OS-provided physical index number. + * It is not guaranteed unique across the entire machine, + * except for PUs and NUMA nodes. + * Set to HWLOC_UNKNOWN_INDEX if unknown or irrelevant for this object. + */ +#define HWLOC_UNKNOWN_INDEX (unsigned)-1 + + char *name; /**< \brief Object-specific name if any. + * Mostly used for identifying OS devices and Misc objects where + * a name string is more useful than numerical indexes. + */ + + hwloc_uint64_t total_memory; /**< \brief Total memory (in bytes) in NUMA nodes below this object. */ + + union hwloc_obj_attr_u *attr; /**< \brief Object type-specific Attributes, + * may be \c NULL if no attribute value was found */ + + /* global position */ + int depth; /**< \brief Vertical index in the hierarchy. + * + * For normal objects, this is the depth of the horizontal level + * that contains this object and its cousins of the same type. + * If the topology is symmetric, this is equal to the parent depth + * plus one, and also equal to the number of parent/child links + * from the root object to here. + * + * For special objects (NUMA nodes, I/O and Misc) that are not + * in the main tree, this is a special negative value that + * corresponds to their dedicated level, + * see hwloc_get_type_depth() and ::hwloc_get_type_depth_e. + * Those special values can be passed to hwloc functions such + * hwloc_get_nbobjs_by_depth() as usual. + */ + unsigned logical_index; /**< \brief Horizontal index in the whole list of similar objects, + * hence guaranteed unique across the entire machine. + * Could be a "cousin_rank" since it's the rank within the "cousin" list below + * Note that this index may change when restricting the topology + * or when inserting a group. + */ + + /* cousins are all objects of the same type (and depth) across the entire topology */ + struct hwloc_obj *next_cousin; /**< \brief Next object of same type and depth */ + struct hwloc_obj *prev_cousin; /**< \brief Previous object of same type and depth */ + + /* children of the same parent are siblings, even if they may have different type and depth */ + struct hwloc_obj *parent; /**< \brief Parent, \c NULL if root (Machine object) */ + unsigned sibling_rank; /**< \brief Index in parent's \c children[] array. Or the index in parent's Memory, I/O or Misc children list. */ + struct hwloc_obj *next_sibling; /**< \brief Next object below the same parent (inside the same list of children). */ + struct hwloc_obj *prev_sibling; /**< \brief Previous object below the same parent (inside the same list of children). */ + /** @name List and array of normal children below this object (except Memory, I/O and Misc children). */ + /**@{*/ + unsigned arity; /**< \brief Number of normal children. + * Memory, Misc and I/O children are not listed here + * but rather in their dedicated children list. + */ + struct hwloc_obj **children; /**< \brief Normal children, \c children[0 .. arity -1] */ + struct hwloc_obj *first_child; /**< \brief First normal child */ + struct hwloc_obj *last_child; /**< \brief Last normal child */ + /**@}*/ + + int symmetric_subtree; /**< \brief Set if the subtree of normal objects below this object is symmetric, + * which means all normal children and their children have identical subtrees. + * + * Memory, I/O and Misc children are ignored. + * + * If set in the topology root object, lstopo may export the topology + * as a synthetic string. + */ + + /** @name List of Memory children below this object. */ + /**@{*/ + unsigned memory_arity; /**< \brief Number of Memory children. + * These children are listed in \p memory_first_child. + */ + struct hwloc_obj *memory_first_child; /**< \brief First Memory child. + * NUMA nodes and Memory-side caches are listed here + * (\p memory_arity and \p memory_first_child) + * instead of in the normal children list. + * See also hwloc_obj_type_is_memory(). + * + * A memory hierarchy starts from a normal CPU-side object + * (e.g. Package) and ends with NUMA nodes as leaves. + * There might exist some memory-side caches between them + * in the middle of the memory subtree. + */ + /**@}*/ + + /** @name List of I/O children below this object. */ + /**@{*/ + unsigned io_arity; /**< \brief Number of I/O children. + * These children are listed in \p io_first_child. + */ + struct hwloc_obj *io_first_child; /**< \brief First I/O child. + * Bridges, PCI and OS devices are listed here (\p io_arity and \p io_first_child) + * instead of in the normal children list. + * See also hwloc_obj_type_is_io(). + */ + /**@}*/ + + /** @name List of Misc children below this object. */ + /**@{*/ + unsigned misc_arity; /**< \brief Number of Misc children. + * These children are listed in \p misc_first_child. + */ + struct hwloc_obj *misc_first_child; /**< \brief First Misc child. + * Misc objects are listed here (\p misc_arity and \p misc_first_child) + * instead of in the normal children list. + */ + /**@}*/ + + /* cpusets and nodesets */ + hwloc_cpuset_t cpuset; /**< \brief CPUs covered by this object + * + * This is the set of CPUs for which there are PU objects in the topology + * under this object, i.e. which are known to be physically contained in this + * object and known how (the children path between this object and the PU + * objects). + * + * If the ::HWLOC_TOPOLOGY_FLAG_INCLUDE_DISALLOWED configuration flag is set, + * some of these CPUs may be online but not allowed for binding, + * see hwloc_topology_get_allowed_cpuset(). + * + * \note All objects have non-NULL CPU and node sets except Misc and I/O objects. + * + * \note Its value must not be changed, hwloc_bitmap_dup() must be used instead. + */ + hwloc_cpuset_t complete_cpuset; /**< \brief The complete CPU set of processors of this object, + * + * This may include not only the same as the cpuset field, but also some CPUs for + * which topology information is unknown or incomplete, some offlines CPUs, and + * the CPUs that are ignored when the ::HWLOC_TOPOLOGY_FLAG_INCLUDE_DISALLOWED flag + * is not set. + * Thus no corresponding PU object may be found in the topology, because the + * precise position is undefined. It is however known that it would be somewhere + * under this object. + * + * \note Its value must not be changed, hwloc_bitmap_dup() must be used instead. + */ + + hwloc_nodeset_t nodeset; /**< \brief NUMA nodes covered by this object or containing this object + * + * This is the set of NUMA nodes for which there are NUMA node objects in the + * topology under or above this object, i.e. which are known to be physically + * contained in this object or containing it and known how (the children path + * between this object and the NUMA node objects). + * + * In the end, these nodes are those that are close to the current object. + * Function hwloc_get_local_numanode_objs() may be used to list those NUMA + * nodes more precisely. + * + * If the ::HWLOC_TOPOLOGY_FLAG_INCLUDE_DISALLOWED configuration flag is set, + * some of these nodes may be online but not allowed for allocation, + * see hwloc_topology_get_allowed_nodeset(). + * + * If there are no NUMA nodes in the machine, all the memory is close to this + * object, so only the first bit may be set in \p nodeset. + * + * \note All objects have non-NULL CPU and node sets except Misc and I/O objects. + * + * \note Its value must not be changed, hwloc_bitmap_dup() must be used instead. + */ + hwloc_nodeset_t complete_nodeset; /**< \brief The complete NUMA node set of this object, + * + * This may include not only the same as the nodeset field, but also some NUMA + * nodes for which topology information is unknown or incomplete, some offlines + * nodes, and the nodes that are ignored when the ::HWLOC_TOPOLOGY_FLAG_INCLUDE_DISALLOWED + * flag is not set. + * Thus no corresponding NUMA node object may be found in the topology, because the + * precise position is undefined. It is however known that it would be + * somewhere under this object. + * + * If there are no NUMA nodes in the machine, all the memory is close to this + * object, so only the first bit is set in \p complete_nodeset. + * + * \note Its value must not be changed, hwloc_bitmap_dup() must be used instead. + */ + + struct hwloc_info_s *infos; /**< \brief Array of info attributes (name and value strings). */ + unsigned infos_count; /**< \brief Size of infos array. */ + + /* misc */ + void *userdata; /**< \brief Application-given private data pointer, + * initialized to \c NULL, use it as you wish. + * See hwloc_topology_set_userdata_export_callback() in hwloc/export.h + * if you wish to export this field to XML. */ + + hwloc_uint64_t gp_index; /**< \brief Global persistent index. + * Generated by hwloc, unique across the topology (contrary to os_index) + * and persistent across topology changes (contrary to logical_index). + * Mostly used internally, but could also be used by application to identify objects. + */ +}; +/** + * \brief Convenience typedef; a pointer to a struct hwloc_obj. + */ +typedef struct hwloc_obj * hwloc_obj_t; + +/** \brief Object type-specific Attributes */ +union hwloc_obj_attr_u { + /** \brief NUMA node-specific Object Attributes */ + struct hwloc_numanode_attr_s { + hwloc_uint64_t local_memory; /**< \brief Local memory (in bytes) */ + unsigned page_types_len; /**< \brief Size of array \p page_types */ + /** \brief Array of local memory page types, \c NULL if no local memory and \p page_types is 0. + * + * The array is sorted by increasing \p size fields. + * It contains \p page_types_len slots. + */ + struct hwloc_memory_page_type_s { + hwloc_uint64_t size; /**< \brief Size of pages */ + hwloc_uint64_t count; /**< \brief Number of pages of this size */ + } * page_types; + } numanode; + + /** \brief Cache-specific Object Attributes */ + struct hwloc_cache_attr_s { + hwloc_uint64_t size; /**< \brief Size of cache in bytes */ + unsigned depth; /**< \brief Depth of cache (e.g., L1, L2, ...etc.) */ + unsigned linesize; /**< \brief Cache-line size in bytes. 0 if unknown */ + int associativity; /**< \brief Ways of associativity, + * -1 if fully associative, 0 if unknown */ + hwloc_obj_cache_type_t type; /**< \brief Cache type */ + } cache; + /** \brief Group-specific Object Attributes */ + struct hwloc_group_attr_s { + unsigned depth; /**< \brief Depth of group object. + * It may change if intermediate Group objects are added. */ + unsigned kind; /**< \brief Internally-used kind of group. */ + unsigned subkind; /**< \brief Internally-used subkind to distinguish different levels of groups with same kind */ + unsigned char dont_merge; /**< \brief Flag preventing groups from being automatically merged with identical parent or children. */ + } group; + /** \brief PCI Device specific Object Attributes */ + struct hwloc_pcidev_attr_s { +#ifndef HWLOC_HAVE_32BITS_PCI_DOMAIN + unsigned short domain; /**< \brief Domain number (xxxx in the PCI BDF notation xxxx:yy:zz.t). + * Only 16bits PCI domains are supported by default. */ +#else + unsigned int domain; /**< \brief Domain number (xxxx in the PCI BDF notation xxxx:yy:zz.t). + * 32bits PCI domain support break the library ABI, hence it's disabled by default. */ +#endif + unsigned char bus; /**< \brief Bus number (yy in the PCI BDF notation xxxx:yy:zz.t). */ + unsigned char dev; /**< \brief Device number (zz in the PCI BDF notation xxxx:yy:zz.t). */ + unsigned char func; /**< \brief Function number (t in the PCI BDF notation xxxx:yy:zz.t). */ + unsigned short class_id; /**< \brief The class number (first two bytes, without the prog_if). */ + unsigned short vendor_id; /**< \brief Vendor ID (xxxx in [xxxx:yyyy]). */ + unsigned short device_id; /**< \brief Device ID (yyyy in [xxxx:yyyy]). */ + unsigned short subvendor_id; /**< \brief Sub-Vendor ID. */ + unsigned short subdevice_id; /**< \brief Sub-Device ID. */ + unsigned char revision; /**< \brief Revision number. */ + float linkspeed; /**< \brief Link speed in GB/s. + * This datarate is the currently configured speed of the entire PCI link + * (sum of the bandwidth of all PCI lanes in that link). + * It may change during execution since some devices are able to + * slow their PCI links down when idle. + */ + } pcidev; + /** \brief Bridge specific Object Attributes */ + struct hwloc_bridge_attr_s { + union { + struct hwloc_pcidev_attr_s pci; /**< \brief PCI attribute of the upstream part as a PCI device. */ + } upstream; + hwloc_obj_bridge_type_t upstream_type; /**< \brief Upstream Bridge type. */ + union { + struct { +#ifndef HWLOC_HAVE_32BITS_PCI_DOMAIN + unsigned short domain; /**< \brief Domain number the downstream PCI buses. + * Only 16bits PCI domains are supported by default. */ +#else + unsigned int domain; /**< \brief Domain number the downstream PCI buses. + * 32bits PCI domain support break the library ABI, hence it's disabled by default */ +#endif + unsigned char secondary_bus; /**< \brief First PCI bus number below the bridge. */ + unsigned char subordinate_bus; /**< \brief Highest PCI bus number below the bridge. */ + } pci; + } downstream; + hwloc_obj_bridge_type_t downstream_type; /**< \brief Downstream Bridge type. */ + unsigned depth; + } bridge; + /** \brief OS Device specific Object Attributes */ + struct hwloc_osdev_attr_s { + hwloc_obj_osdev_type_t type; + } osdev; +}; + +/** \brief Object info attribute (name and value strings) + * + * \sa hwlocality_info_attr + */ +struct hwloc_info_s { + char *name; /**< \brief Info name */ + char *value; /**< \brief Info value */ +}; + +/** @} */ + + + +/** \defgroup hwlocality_creation Topology Creation and Destruction + * @{ + */ + +struct hwloc_topology; +/** \brief Topology context + * + * To be initialized with hwloc_topology_init() and built with hwloc_topology_load(). + */ +typedef struct hwloc_topology * hwloc_topology_t; + +/** \brief Allocate a topology context. + * + * \param[out] topologyp is assigned a pointer to the new allocated context. + * + * \return 0 on success, -1 on error. + */ +HWLOC_DECLSPEC int hwloc_topology_init (hwloc_topology_t *topologyp); + +/** \brief Build the actual topology + * + * Build the actual topology once initialized with hwloc_topology_init() and + * tuned with \ref hwlocality_configuration and \ref hwlocality_setsource routines. + * No other routine may be called earlier using this topology context. + * + * \param topology is the topology to be loaded with objects. + * + * \return 0 on success, -1 on error. + * + * \note On failure, the topology is reinitialized. It should be either + * destroyed with hwloc_topology_destroy() or configured and loaded again. + * + * \note This function may be called only once per topology. + * + * \note The binding of the current thread or process may temporarily change + * during this call but it will be restored before it returns. + * + * \sa hwlocality_configuration and hwlocality_setsource + */ +HWLOC_DECLSPEC int hwloc_topology_load(hwloc_topology_t topology); + +/** \brief Terminate and free a topology context + * + * \param topology is the topology to be freed + */ +HWLOC_DECLSPEC void hwloc_topology_destroy (hwloc_topology_t topology); + +/** \brief Duplicate a topology. + * + * The entire topology structure as well as its objects + * are duplicated into a new one. + * + * This is useful for keeping a backup while modifying a topology. + * + * \return 0 on success, -1 on error. + * + * \note Object userdata is not duplicated since hwloc does not know what it point to. + * The objects of both old and new topologies will point to the same userdata. + */ +HWLOC_DECLSPEC int hwloc_topology_dup(hwloc_topology_t *newtopology, hwloc_topology_t oldtopology); + +/** \brief Verify that the topology is compatible with the current hwloc library. + * + * This is useful when using the same topology structure (in memory) + * in different libraries that may use different hwloc installations + * (for instance if one library embeds a specific version of hwloc, + * while another library uses a default system-wide hwloc installation). + * + * If all libraries/programs use the same hwloc installation, this function + * always returns success. + * + * \return \c 0 on success. + * + * \return \c -1 with \p errno set to \c EINVAL if incompatible. + * + * \note If sharing between processes with hwloc_shmem_topology_write(), + * the relevant check is already performed inside hwloc_shmem_topology_adopt(). + */ +HWLOC_DECLSPEC int hwloc_topology_abi_check(hwloc_topology_t topology); + +/** \brief Run internal checks on a topology structure + * + * The program aborts if an inconsistency is detected in the given topology. + * + * \param topology is the topology to be checked + * + * \note This routine is only useful to developers. + * + * \note The input topology should have been previously loaded with + * hwloc_topology_load(). + */ +HWLOC_DECLSPEC void hwloc_topology_check(hwloc_topology_t topology); + +/** @} */ + + + +/** \defgroup hwlocality_levels Object levels, depths and types + * @{ + * + * Be sure to see the figure in \ref termsanddefs that shows a + * complete topology tree, including depths, child/sibling/cousin + * relationships, and an example of an asymmetric topology where one + * package has fewer caches than its peers. + */ + +/** \brief Get the depth of the hierarchical tree of objects. + * + * This is the depth of ::HWLOC_OBJ_PU objects plus one. + * + * \return the depth of the object tree. + * + * \note NUMA nodes, I/O and Misc objects are ignored when computing + * the depth of the tree (they are placed on special levels). + */ +HWLOC_DECLSPEC int hwloc_topology_get_depth(hwloc_topology_t __hwloc_restrict topology) __hwloc_attribute_pure; + +/** \brief Returns the depth of objects of type \p type. + * + * \return The depth of objects of type \p type. + * + * \return A negative virtual depth if a NUMA node, I/O or Misc object type is given. + * These objects are stored in special levels that are not CPU-related. + * This virtual depth may be passed to other hwloc functions such as + * hwloc_get_obj_by_depth() but it should not be considered as an actual + * depth by the application. In particular, it should not be compared with + * any other object depth or with the entire topology depth. + * + * \return ::HWLOC_TYPE_DEPTH_UNKNOWN + * if no object of this type is present on the underlying architecture, + * or if the OS doesn't provide this kind of information. + * + * \return ::HWLOC_TYPE_DEPTH_MULTIPLE if type ::HWLOC_OBJ_GROUP is given + * and multiple levels of Groups exist. + * + * \note If the type is absent but a similar type is acceptable, see also + * hwloc_get_type_or_below_depth() and hwloc_get_type_or_above_depth(). + * + * \sa hwloc_get_memory_parents_depth() for managing the depth of memory objects. + * + * \sa hwloc_type_sscanf_as_depth() for returning the depth of objects + * whose type is given as a string. + */ +HWLOC_DECLSPEC int hwloc_get_type_depth (hwloc_topology_t topology, hwloc_obj_type_t type); + +enum hwloc_get_type_depth_e { + HWLOC_TYPE_DEPTH_UNKNOWN = -1, /**< \brief No object of given type exists in the topology. \hideinitializer */ + HWLOC_TYPE_DEPTH_MULTIPLE = -2, /**< \brief Objects of given type exist at different depth in the topology (only for Groups). \hideinitializer */ + HWLOC_TYPE_DEPTH_NUMANODE = -3, /**< \brief Virtual depth for NUMA nodes. \hideinitializer */ + HWLOC_TYPE_DEPTH_BRIDGE = -4, /**< \brief Virtual depth for bridge object level. \hideinitializer */ + HWLOC_TYPE_DEPTH_PCI_DEVICE = -5, /**< \brief Virtual depth for PCI device object level. \hideinitializer */ + HWLOC_TYPE_DEPTH_OS_DEVICE = -6, /**< \brief Virtual depth for software device object level. \hideinitializer */ + HWLOC_TYPE_DEPTH_MISC = -7, /**< \brief Virtual depth for Misc object. \hideinitializer */ + HWLOC_TYPE_DEPTH_MEMCACHE = -8 /**< \brief Virtual depth for MemCache object. \hideinitializer */ +}; + +/** \brief Return the depth of parents where memory objects are attached. + * + * Memory objects have virtual negative depths because they are not part of + * the main CPU-side hierarchy of objects. This depth should not be compared + * with other level depths. + * + * If all Memory objects are attached to Normal parents at the same depth, + * this parent depth may be compared to other as usual, for instance + * for knowing whether NUMA nodes is attached above or below Packages. + * + * \return The depth of Normal parents of all memory children + * if all these parents have the same depth. For instance the depth of + * the Package level if all NUMA nodes are attached to Package objects. + * + * \return ::HWLOC_TYPE_DEPTH_MULTIPLE if Normal parents of all + * memory children do not have the same depth. For instance if some + * NUMA nodes are attached to Packages while others are attached to + * Groups. + */ +HWLOC_DECLSPEC int hwloc_get_memory_parents_depth (hwloc_topology_t topology); + +/** \brief Returns the depth of objects of type \p type or below + * + * If no object of this type is present on the underlying architecture, the + * function returns the depth of the first "present" object typically found + * inside \p type. + * + * This function is only meaningful for normal object types. + * If a memory, I/O or Misc object type is given, the corresponding virtual + * depth is always returned (see hwloc_get_type_depth()). + * + * May return ::HWLOC_TYPE_DEPTH_MULTIPLE for ::HWLOC_OBJ_GROUP just like + * hwloc_get_type_depth(). + */ +static __hwloc_inline int +hwloc_get_type_or_below_depth (hwloc_topology_t topology, hwloc_obj_type_t type) __hwloc_attribute_pure; + +/** \brief Returns the depth of objects of type \p type or above + * + * If no object of this type is present on the underlying architecture, the + * function returns the depth of the first "present" object typically + * containing \p type. + * + * This function is only meaningful for normal object types. + * If a memory, I/O or Misc object type is given, the corresponding virtual + * depth is always returned (see hwloc_get_type_depth()). + * + * May return ::HWLOC_TYPE_DEPTH_MULTIPLE for ::HWLOC_OBJ_GROUP just like + * hwloc_get_type_depth(). + */ +static __hwloc_inline int +hwloc_get_type_or_above_depth (hwloc_topology_t topology, hwloc_obj_type_t type) __hwloc_attribute_pure; + +/** \brief Returns the type of objects at depth \p depth. + * + * \p depth should between 0 and hwloc_topology_get_depth()-1, + * or a virtual depth such as ::HWLOC_TYPE_DEPTH_NUMANODE. + * + * \return The type of objects at depth \p depth. + * \return (hwloc_obj_type_t)-1 if depth \p depth does not exist. + */ +HWLOC_DECLSPEC hwloc_obj_type_t hwloc_get_depth_type (hwloc_topology_t topology, int depth) __hwloc_attribute_pure; + +/** \brief Returns the width of level at depth \p depth. + * + * \return The number of objects at topology depth \p depth. + * \return 0 if there are no objects at depth \p depth. + */ +HWLOC_DECLSPEC unsigned hwloc_get_nbobjs_by_depth (hwloc_topology_t topology, int depth) __hwloc_attribute_pure; + +/** \brief Returns the width of level type \p type + * + * \return The number of objects of type \p type. + * \return -1 if there are multiple levels with objects of that type, e.g. ::HWLOC_OBJ_GROUP. + * \return 0 if there are no objects at depth \p depth. + */ +static __hwloc_inline int +hwloc_get_nbobjs_by_type (hwloc_topology_t topology, hwloc_obj_type_t type) __hwloc_attribute_pure; + +/** \brief Returns the top-object of the topology-tree. + * + * Its type is ::HWLOC_OBJ_MACHINE. + * + * This function cannot return \c NULL. + */ +static __hwloc_inline hwloc_obj_t +hwloc_get_root_obj (hwloc_topology_t topology) __hwloc_attribute_pure; + +/** \brief Returns the topology object at logical index \p idx from depth \p depth + * + * \return The object if it exists. + * \return \c NULL if there is no object with this index and depth. + */ +HWLOC_DECLSPEC hwloc_obj_t hwloc_get_obj_by_depth (hwloc_topology_t topology, int depth, unsigned idx) __hwloc_attribute_pure; + +/** \brief Returns the topology object at logical index \p idx with type \p type + * + * \return The object if it exists. + * \return \c NULL if there is no object with this index and type. + * \return \c NULL if there are multiple levels with objects of that type (e.g. ::HWLOC_OBJ_GROUP), + * the caller may fallback to hwloc_get_obj_by_depth(). + */ +static __hwloc_inline hwloc_obj_t +hwloc_get_obj_by_type (hwloc_topology_t topology, hwloc_obj_type_t type, unsigned idx) __hwloc_attribute_pure; + +/** \brief Returns the next object at depth \p depth. + * + * \return The first object at depth \p depth if \p prev is \c NULL. + * \return The object after \p prev at depth \p depth if \p prev is not \c NULL. + * \return \c NULL if there is no such object. + */ +static __hwloc_inline hwloc_obj_t +hwloc_get_next_obj_by_depth (hwloc_topology_t topology, int depth, hwloc_obj_t prev); + +/** \brief Returns the next object of type \p type. + * + * \return The first object of type \p type if \p prev is \c NULL. + * \return The object after \p prev of type \p type if \p prev is not \c NULL. + * \return \c NULL if there is no such object. + * \return \c NULL if there are multiple levels with objects of that type (e.g. ::HWLOC_OBJ_GROUP), + * the caller may fallback to hwloc_get_obj_by_depth(). + */ +static __hwloc_inline hwloc_obj_t +hwloc_get_next_obj_by_type (hwloc_topology_t topology, hwloc_obj_type_t type, + hwloc_obj_t prev); + +/** @} */ + + + +/** \defgroup hwlocality_object_strings Converting between Object Types and Attributes, and Strings + * @{ + */ + +/** \brief Return a constant stringified object type. + * + * This function is the basic way to convert a generic type into a string. + * The output string may be parsed back by hwloc_type_sscanf(). + * + * hwloc_obj_type_snprintf() may return a more precise output for a specific + * object, but it requires the caller to provide the output buffer. + * + * \return A constant string containing the object type name or \c "Unknown". + */ +HWLOC_DECLSPEC const char * hwloc_obj_type_string (hwloc_obj_type_t type) __hwloc_attribute_const; + +/** \brief Stringify the type of a given topology object into a human-readable form. + * + * Contrary to hwloc_obj_type_string(), this function includes object-specific + * attributes (such as the Group depth, the Bridge type, or OS device type) + * in the output, and it requires the caller to provide the output buffer. + * + * The output is guaranteed to be the same for all objects of a same topology level. + * + * If \p verbose is 1, longer type names are used, e.g. L1Cache instead of L1. + * + * The output string may be parsed back by hwloc_type_sscanf(). + * + * If \p size is 0, \p string may safely be \c NULL. + * + * \return the number of characters that were actually written if not truncating, + * or that would have been written (not including the ending \c \0). + */ +HWLOC_DECLSPEC int hwloc_obj_type_snprintf(char * __hwloc_restrict string, size_t size, + hwloc_obj_t obj, + int verbose); + +/** \brief Stringify the attributes of a given topology object into a human-readable form. + * + * Attribute values are separated by \p separator. + * + * Only the major attributes are printed in non-verbose mode. + * + * If \p size is 0, \p string may safely be \c NULL. + * + * \return the number of characters that were actually written if not truncating, + * or that would have been written (not including the ending \c \0). + */ +HWLOC_DECLSPEC int hwloc_obj_attr_snprintf(char * __hwloc_restrict string, size_t size, + hwloc_obj_t obj, const char * __hwloc_restrict separator, + int verbose); + +/** \brief Return an object type and attributes from a type string. + * + * Convert strings such as "Package" or "L1iCache" into the corresponding types. + * Matching is case-insensitive, and only the first letters are actually + * required to match. + * + * The matched object type is set in \p typep (which cannot be \c NULL). + * + * Type-specific attributes, for instance Cache type, Cache depth, Group depth, + * Bridge type or OS Device type may be returned in \p attrp. + * Attributes that are not specified in the string (for instance "Group" + * without a depth, or "L2Cache" without a cache type) are set to -1. + * + * \p attrp is only filled if not \c NULL and if its size specified in \p attrsize + * is large enough. It should be at least as large as union hwloc_obj_attr_u. + * + * \return 0 if a type was correctly identified, otherwise -1. + * + * \note This function is guaranteed to match any string returned by + * hwloc_obj_type_string() or hwloc_obj_type_snprintf(). + * + * \note This is an extended version of the now deprecated hwloc_obj_type_sscanf(). + */ +HWLOC_DECLSPEC int hwloc_type_sscanf(const char *string, + hwloc_obj_type_t *typep, + union hwloc_obj_attr_u *attrp, size_t attrsize); + +/** \brief Return an object type and its level depth from a type string. + * + * Convert strings such as "Package" or "L1iCache" into the corresponding types + * and return in \p depthp the depth of the corresponding level in the + * topology \p topology. + * + * If no object of this type is present on the underlying architecture, + * ::HWLOC_TYPE_DEPTH_UNKNOWN is returned. + * + * If multiple such levels exist (for instance if giving Group without any depth), + * the function may return ::HWLOC_TYPE_DEPTH_MULTIPLE instead. + * + * The matched object type is set in \p typep if \p typep is non \c NULL. + * + * \note This function is similar to hwloc_type_sscanf() followed + * by hwloc_get_type_depth() but it also automatically disambiguates + * multiple group levels etc. + * + * \note This function is guaranteed to match any string returned by + * hwloc_obj_type_string() or hwloc_obj_type_snprintf(). + */ +HWLOC_DECLSPEC int hwloc_type_sscanf_as_depth(const char *string, + hwloc_obj_type_t *typep, + hwloc_topology_t topology, int *depthp); + +/** @} */ + + + +/** \defgroup hwlocality_info_attr Consulting and Adding Info Attributes + * + * @{ + */ + +/** \brief Search the given name in object infos and return the corresponding value. + * + * If multiple info attributes match the given name, only the first one is returned. + * + * \return A pointer to the value string if it exists. + * \return \c NULL if no such info attribute exists. + * + * \note The string should not be freed by the caller, it belongs to the hwloc library. + */ +static __hwloc_inline const char * +hwloc_obj_get_info_by_name(hwloc_obj_t obj, const char *name) __hwloc_attribute_pure; + +/** \brief Add the given name and value pair to the given object info attributes. + * + * The info pair is appended to the existing info array even if another pair + * with the same name already exists. + * + * The input strings are copied before being added in the object infos. + * + * \return \c 0 on success, \c -1 on error. + * + * \note This function may be used to enforce object colors in the lstopo + * graphical output by adding "lstopoStyle" as a name and "Background=#rrggbb" + * as a value. See CUSTOM COLORS in the lstopo(1) manpage for details. + * + * \note If \p name or \p value contain some non-printable characters, they will + * be dropped when exporting to XML, see hwloc_topology_export_xml() in hwloc/export.h. + */ +HWLOC_DECLSPEC int hwloc_obj_add_info(hwloc_obj_t obj, const char *name, const char *value); + +/** \brief Set (or replace) the subtype of an object. + * + * The given \p subtype is copied internally, the caller is responsible + * for freeing the original \p subtype if needed. + * + * If another subtype already exists in \p object, it is replaced. + * The given \p subtype may be \c NULL to remove the existing subtype. + * + * \note This function is mostly meant to initialize the subtype of user-added + * objects such as groups with hwloc_topology_alloc_group_object(). + * + * \return \c 0 on success. + * \return \c -1 with \p errno set to \c ENOMEM on failure to allocate memory. + */ +HWLOC_DECLSPEC int hwloc_obj_set_subtype(hwloc_topology_t topology, hwloc_obj_t obj, const char *subtype); + +/** @} */ + + + +/** \defgroup hwlocality_cpubinding CPU binding + * + * Some operating systems only support binding threads or processes to a single PU. + * Others allow binding to larger sets such as entire Cores or Packages or + * even random sets of individual PUs. In such operating system, the scheduler + * is free to run the task on one of these PU, then migrate it to another PU, etc. + * It is often useful to call hwloc_bitmap_singlify() on the target CPU set before + * passing it to the binding function to avoid these expensive migrations. + * See the documentation of hwloc_bitmap_singlify() for details. + * + * Some operating systems do not provide all hwloc-supported + * mechanisms to bind processes, threads, etc. + * hwloc_topology_get_support() may be used to query about the actual CPU + * binding support in the currently used operating system. + * + * When the requested binding operation is not available and the + * ::HWLOC_CPUBIND_STRICT flag was passed, the function returns -1. + * \p errno is set to \c ENOSYS when it is not possible to bind the requested kind of object + * processes/threads. errno is set to \c EXDEV when the requested cpuset + * can not be enforced (e.g. some systems only allow one CPU, and some + * other systems only allow one NUMA node). + * + * If ::HWLOC_CPUBIND_STRICT was not passed, the function may fail as well, + * or the operating system may use a slightly different operation + * (with side-effects, smaller binding set, etc.) + * when the requested operation is not exactly supported. + * + * The most portable version that should be preferred over the others, + * whenever possible, is the following one which just binds the current program, + * assuming it is single-threaded: + * + * \code + * hwloc_set_cpubind(topology, set, 0), + * \endcode + * + * If the program may be multithreaded, the following one should be preferred + * to only bind the current thread: + * + * \code + * hwloc_set_cpubind(topology, set, HWLOC_CPUBIND_THREAD), + * \endcode + * + * \sa Some example codes are available under doc/examples/ in the source tree. + * + * \note To unbind, just call the binding function with either a full cpuset or + * a cpuset equal to the system cpuset. + * + * \note On some operating systems, CPU binding may have effects on memory binding, see + * ::HWLOC_CPUBIND_NOMEMBIND + * + * \note Running lstopo \--top or hwloc-ps can be a very convenient tool to check + * how binding actually happened. + * @{ + */ + +/** \brief Process/Thread binding flags. + * + * These bit flags can be used to refine the binding policy. + * + * The default (0) is to bind the current process, assumed to be + * single-threaded, in a non-strict way. This is the most portable + * way to bind as all operating systems usually provide it. + * + * \note Not all systems support all kinds of binding. See the + * "Detailed Description" section of \ref hwlocality_cpubinding for a + * description of errors that can occur. + */ +typedef enum { + /** \brief Bind all threads of the current (possibly) multithreaded process. + * \hideinitializer */ + HWLOC_CPUBIND_PROCESS = (1<<0), + + /** \brief Bind current thread of current process. + * \hideinitializer */ + HWLOC_CPUBIND_THREAD = (1<<1), + + /** \brief Request for strict binding from the OS. + * + * By default, when the designated CPUs are all busy while other + * CPUs are idle, operating systems may execute the thread/process + * on those other CPUs instead of the designated CPUs, to let them + * progress anyway. Strict binding means that the thread/process + * will _never_ execute on other CPUs than the designated CPUs, even + * when those are busy with other tasks and other CPUs are idle. + * + * \note Depending on the operating system, strict binding may not + * be possible (e.g., the OS does not implement it) or not allowed + * (e.g., for an administrative reasons), and the function will fail + * in that case. + * + * When retrieving the binding of a process, this flag checks + * whether all its threads actually have the same binding. If the + * flag is not given, the binding of each thread will be + * accumulated. + * + * \note This flag is meaningless when retrieving the binding of a + * thread. + * \hideinitializer + */ + HWLOC_CPUBIND_STRICT = (1<<2), + + /** \brief Avoid any effect on memory binding + * + * On some operating systems, some CPU binding function would also + * bind the memory on the corresponding NUMA node. It is often not + * a problem for the application, but if it is, setting this flag + * will make hwloc avoid using OS functions that would also bind + * memory. This will however reduce the support of CPU bindings, + * i.e. potentially return -1 with errno set to \c ENOSYS in some + * cases. + * + * This flag is only meaningful when used with functions that set + * the CPU binding. It is ignored when used with functions that get + * CPU binding information. + * \hideinitializer + */ + HWLOC_CPUBIND_NOMEMBIND = (1<<3) +} hwloc_cpubind_flags_t; + +/** \brief Bind current process or thread on CPUs given in physical bitmap \p set. + * + * \return 0 on success. + * \return -1 with errno set to \c ENOSYS if the action is not supported. + * \return -1 with errno set to \c EXDEV if the binding cannot be enforced. + */ +HWLOC_DECLSPEC int hwloc_set_cpubind(hwloc_topology_t topology, hwloc_const_cpuset_t set, int flags); + +/** \brief Get current process or thread binding. + * + * The CPU-set \p set (previously allocated by the caller) + * is filled with the list of PUs which the process or + * thread (according to \e flags) was last bound to. + * + * \return 0 on success, -1 on error. + */ +HWLOC_DECLSPEC int hwloc_get_cpubind(hwloc_topology_t topology, hwloc_cpuset_t set, int flags); + +/** \brief Bind a process \p pid on CPUs given in physical bitmap \p set. + * + * \return 0 on success, -1 on error. + * + * \note \p hwloc_pid_t is \p pid_t on Unix platforms, + * and \p HANDLE on native Windows platforms. + * + * \note As a special case on Linux, if a tid (thread ID) is supplied + * instead of a pid (process ID) and ::HWLOC_CPUBIND_THREAD is passed in flags, + * the binding is applied to that specific thread. + * + * \note On non-Linux systems, ::HWLOC_CPUBIND_THREAD can not be used in \p flags. + */ +HWLOC_DECLSPEC int hwloc_set_proc_cpubind(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_const_cpuset_t set, int flags); + +/** \brief Get the current physical binding of process \p pid. + * + * The CPU-set \p set (previously allocated by the caller) + * is filled with the list of PUs which the process + * was last bound to. + * + * \return 0 on success, -1 on error. + * + * \note \p hwloc_pid_t is \p pid_t on Unix platforms, + * and \p HANDLE on native Windows platforms. + * + * \note As a special case on Linux, if a tid (thread ID) is supplied + * instead of a pid (process ID) and HWLOC_CPUBIND_THREAD is passed in flags, + * the binding for that specific thread is returned. + * + * \note On non-Linux systems, HWLOC_CPUBIND_THREAD can not be used in \p flags. + */ +HWLOC_DECLSPEC int hwloc_get_proc_cpubind(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_cpuset_t set, int flags); + +#ifdef hwloc_thread_t +/** \brief Bind a thread \p thread on CPUs given in physical bitmap \p set. + * + * \return 0 on success, -1 on error. + * + * \note \p hwloc_thread_t is \p pthread_t on Unix platforms, + * and \p HANDLE on native Windows platforms. + * + * \note ::HWLOC_CPUBIND_PROCESS can not be used in \p flags. + */ +HWLOC_DECLSPEC int hwloc_set_thread_cpubind(hwloc_topology_t topology, hwloc_thread_t thread, hwloc_const_cpuset_t set, int flags); +#endif + +#ifdef hwloc_thread_t +/** \brief Get the current physical binding of thread \p tid. + * + * The CPU-set \p set (previously allocated by the caller) + * is filled with the list of PUs which the thread + * was last bound to. + * + * \return 0 on success, -1 on error. + * + * \note \p hwloc_thread_t is \p pthread_t on Unix platforms, + * and \p HANDLE on native Windows platforms. + * + * \note ::HWLOC_CPUBIND_PROCESS can not be used in \p flags. + */ +HWLOC_DECLSPEC int hwloc_get_thread_cpubind(hwloc_topology_t topology, hwloc_thread_t thread, hwloc_cpuset_t set, int flags); +#endif + +/** \brief Get the last physical CPU where the current process or thread ran. + * + * The CPU-set \p set (previously allocated by the caller) + * is filled with the list of PUs which the process or + * thread (according to \e flags) last ran on. + * + * The operating system may move some tasks from one processor + * to another at any time according to their binding, + * so this function may return something that is already + * outdated. + * + * \p flags can include either ::HWLOC_CPUBIND_PROCESS or ::HWLOC_CPUBIND_THREAD to + * specify whether the query should be for the whole process (union of all CPUs + * on which all threads are running), or only the current thread. If the + * process is single-threaded, flags can be set to zero to let hwloc use + * whichever method is available on the underlying OS. + * + * \return 0 on success, -1 on error. + */ +HWLOC_DECLSPEC int hwloc_get_last_cpu_location(hwloc_topology_t topology, hwloc_cpuset_t set, int flags); + +/** \brief Get the last physical CPU where a process ran. + * + * The CPU-set \p set (previously allocated by the caller) + * is filled with the list of PUs which the process + * last ran on. + * + * The operating system may move some tasks from one processor + * to another at any time according to their binding, + * so this function may return something that is already + * outdated. + * + * \return 0 on success, -1 on error. + * + * \note \p hwloc_pid_t is \p pid_t on Unix platforms, + * and \p HANDLE on native Windows platforms. + * + * \note As a special case on Linux, if a tid (thread ID) is supplied + * instead of a pid (process ID) and ::HWLOC_CPUBIND_THREAD is passed in flags, + * the last CPU location of that specific thread is returned. + * + * \note On non-Linux systems, ::HWLOC_CPUBIND_THREAD can not be used in \p flags. + */ +HWLOC_DECLSPEC int hwloc_get_proc_last_cpu_location(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_cpuset_t set, int flags); + +/** @} */ + + + +/** \defgroup hwlocality_membinding Memory binding + * + * Memory binding can be done three ways: + * + * - explicit memory allocation thanks to hwloc_alloc_membind() and friends: + * the binding will have effect on the memory allocated by these functions. + * - implicit memory binding through binding policy: hwloc_set_membind() and + * friends only define the current policy of the process, which will be + * applied to the subsequent calls to malloc() and friends. + * - migration of existing memory ranges, thanks to hwloc_set_area_membind() + * and friends, which move already-allocated data. + * + * Not all operating systems support all three ways. + * hwloc_topology_get_support() may be used to query about the actual memory + * binding support in the currently used operating system. + * + * When the requested binding operation is not available and the + * ::HWLOC_MEMBIND_STRICT flag was passed, the function returns -1. + * \p errno will be set to \c ENOSYS when the system does support + * the specified action or policy + * (e.g., some systems only allow binding memory on a per-thread + * basis, whereas other systems only allow binding memory for all + * threads in a process). + * \p errno will be set to \c EXDEV when the requested set can not be enforced + * (e.g., some systems only allow binding memory to a single NUMA node). + * + * If ::HWLOC_MEMBIND_STRICT was not passed, the function may fail as well, + * or the operating system may use a slightly different operation + * (with side-effects, smaller binding set, etc.) + * when the requested operation is not exactly supported. + * + * The most portable form that should be preferred over the others + * whenever possible is as follows. + * It allocates some memory hopefully bound to the specified set. + * To do so, hwloc will possibly have to change the current memory + * binding policy in order to actually get the memory bound, if the OS + * does not provide any other way to simply allocate bound memory + * without changing the policy for all allocations. That is the + * difference with hwloc_alloc_membind(), which will never change the + * current memory binding policy. + * + * \code + * hwloc_alloc_membind_policy(topology, size, set, + * HWLOC_MEMBIND_BIND, 0); + * \endcode + * + * Each hwloc memory binding function takes a bitmap argument that + * is a CPU set by default, or a NUMA memory node set if the flag + * ::HWLOC_MEMBIND_BYNODESET is specified. + * See \ref hwlocality_object_sets and \ref hwlocality_bitmap for a + * discussion of CPU sets and NUMA memory node sets. + * It is also possible to convert between CPU set and node set using + * hwloc_cpuset_to_nodeset() or hwloc_cpuset_from_nodeset(). + * + * Memory binding by CPU set cannot work for CPU-less NUMA memory nodes. + * Binding by nodeset should therefore be preferred whenever possible. + * + * \sa Some example codes are available under doc/examples/ in the source tree. + * + * \note On some operating systems, memory binding affects the CPU + * binding; see ::HWLOC_MEMBIND_NOCPUBIND + * @{ + */ + +/** \brief Memory binding policy. + * + * These constants can be used to choose the binding policy. Only one policy can + * be used at a time (i.e., the values cannot be OR'ed together). + * + * Not all systems support all kinds of binding. + * hwloc_topology_get_support() may be used to query about the actual memory + * binding policy support in the currently used operating system. + * See the "Detailed Description" section of \ref hwlocality_membinding + * for a description of errors that can occur. + */ +typedef enum { + /** \brief Reset the memory allocation policy to the system default. + * Depending on the operating system, this may correspond to + * ::HWLOC_MEMBIND_FIRSTTOUCH (Linux, FreeBSD), + * or ::HWLOC_MEMBIND_BIND (AIX, HP-UX, Solaris, Windows). + * This policy is never returned by get membind functions. + * The nodeset argument is ignored. + * \hideinitializer */ + HWLOC_MEMBIND_DEFAULT = 0, + + /** \brief Allocate each memory page individually on the local NUMA + * node of the thread that touches it. + * + * The given nodeset should usually be hwloc_topology_get_topology_nodeset() + * so that the touching thread may run and allocate on any node in the system. + * + * On AIX, if the nodeset is smaller, pages are allocated locally (if the local + * node is in the nodeset) or from a random non-local node (otherwise). + * \hideinitializer */ + HWLOC_MEMBIND_FIRSTTOUCH = 1, + + /** \brief Allocate memory on the specified nodes. + * + * The actual behavior may slightly vary between operating systems, + * especially when (some of) the requested nodes are full. + * On Linux, by default, the MPOL_PREFERRED_MANY (or MPOL_PREFERRED) policy + * is used. However, if the hwloc strict flag is also given, the Linux + * MPOL_BIND policy is rather used. + * \hideinitializer */ + HWLOC_MEMBIND_BIND = 2, + + /** \brief Allocate memory on the given nodes in an interleaved + * / round-robin manner. The precise layout of the memory across + * multiple NUMA nodes is OS/system specific. Interleaving can be + * useful when threads distributed across the specified NUMA nodes + * will all be accessing the whole memory range concurrently, since + * the interleave will then balance the memory references. + * \hideinitializer */ + HWLOC_MEMBIND_INTERLEAVE = 3, + + /** \brief Allocate memory on the given nodes in an interleaved + * / weighted manner. The precise layout of the memory across + * multiple NUMA nodes is OS/system specific. Weighted interleaving + * can be useful when threads distributed across the specified NUMA + * nodes with different bandwidth capabilities will all be accessing + * the whole memory range concurrently, since the interleave will then + * balance the memory references. + * \hideinitializer */ + HWLOC_MEMBIND_WEIGHTED_INTERLEAVE = 5, + + /** \brief For each page bound with this policy, by next time + * it is touched (and next time only), it is moved from its current + * location to the local NUMA node of the thread where the memory + * reference occurred (if it needs to be moved at all). + * \hideinitializer */ + HWLOC_MEMBIND_NEXTTOUCH = 4, + + /** \brief Returned by get_membind() functions when multiple + * threads or parts of a memory area have differing memory binding + * policies. + * Also returned when binding is unknown because binding hooks are empty + * when the topology is loaded from XML without HWLOC_THISSYSTEM=1, etc. + * \hideinitializer */ + HWLOC_MEMBIND_MIXED = -1 +} hwloc_membind_policy_t; + +/** \brief Memory binding flags. + * + * These flags can be used to refine the binding policy. + * All flags can be logically OR'ed together with the exception of + * ::HWLOC_MEMBIND_PROCESS and ::HWLOC_MEMBIND_THREAD; + * these two flags are mutually exclusive. + * + * Not all systems support all kinds of binding. + * hwloc_topology_get_support() may be used to query about the actual memory + * binding support in the currently used operating system. + * See the "Detailed Description" section of \ref hwlocality_membinding + * for a description of errors that can occur. + */ +typedef enum { + /** \brief Set policy for all threads of the specified (possibly + * multithreaded) process. This flag is mutually exclusive with + * ::HWLOC_MEMBIND_THREAD. + * \hideinitializer */ + HWLOC_MEMBIND_PROCESS = (1<<0), + + /** \brief Set policy for a specific thread of the current process. + * This flag is mutually exclusive with ::HWLOC_MEMBIND_PROCESS. + * \hideinitializer */ + HWLOC_MEMBIND_THREAD = (1<<1), + + /** Request strict binding from the OS. The function will fail if + * the binding can not be guaranteed / completely enforced. + * + * This flag has slightly different meanings depending on which + * function it is used with. + * \hideinitializer */ + HWLOC_MEMBIND_STRICT = (1<<2), + + /** \brief Migrate existing allocated memory. If the memory cannot + * be migrated and the ::HWLOC_MEMBIND_STRICT flag is passed, an error + * will be returned. + * \hideinitializer */ + HWLOC_MEMBIND_MIGRATE = (1<<3), + + /** \brief Avoid any effect on CPU binding. + * + * On some operating systems, some underlying memory binding + * functions also bind the application to the corresponding CPU(s). + * Using this flag will cause hwloc to avoid using OS functions that + * could potentially affect CPU bindings. Note, however, that using + * NOCPUBIND may reduce hwloc's overall memory binding + * support. Specifically: some of hwloc's memory binding functions + * may fail with errno set to \c ENOSYS when used with NOCPUBIND. + * \hideinitializer + */ + HWLOC_MEMBIND_NOCPUBIND = (1<<4), + + /** \brief Consider the bitmap argument as a nodeset. + * + * The bitmap argument is considered a nodeset if this flag is given, + * or a cpuset otherwise by default. + * + * Memory binding by CPU set cannot work for CPU-less NUMA memory nodes. + * Binding by nodeset should therefore be preferred whenever possible. + * \hideinitializer + */ + HWLOC_MEMBIND_BYNODESET = (1<<5) +} hwloc_membind_flags_t; + +/** \brief Set the default memory binding policy of the current + * process or thread to prefer the NUMA node(s) specified by \p set + * + * If neither ::HWLOC_MEMBIND_PROCESS nor ::HWLOC_MEMBIND_THREAD is + * specified, the current process is assumed to be single-threaded. + * This is the most portable form as it permits hwloc to use either + * process-based OS functions or thread-based OS functions, depending + * on which are available. + * + * If ::HWLOC_MEMBIND_BYNODESET is specified, set is considered a nodeset. + * Otherwise it's a cpuset. + * + * \return 0 on success. + * \return -1 with errno set to \c ENOSYS if the action is not supported. + * \return -1 with errno set to \c EXDEV if the binding cannot be enforced. + */ +HWLOC_DECLSPEC int hwloc_set_membind(hwloc_topology_t topology, hwloc_const_bitmap_t set, hwloc_membind_policy_t policy, int flags); + +/** \brief Query the default memory binding policy and physical locality of the + * current process or thread. + * + * The bitmap \p set (previously allocated by the caller) + * is filled with the process or thread memory binding. + * + * This function has two output parameters: \p set and \p policy. + * The values returned in these parameters depend on both the \p flags + * passed in and the current memory binding policies and nodesets in + * the queried target. + * + * Passing the ::HWLOC_MEMBIND_PROCESS flag specifies that the query + * target is the current policies and nodesets for all the threads in + * the current process. Passing ::HWLOC_MEMBIND_THREAD specifies that + * the query target is the current policy and nodeset for only the + * thread invoking this function. + * + * If neither of these flags are passed (which is the most portable + * method), the process is assumed to be single threaded. This allows + * hwloc to use either process-based OS functions or thread-based OS + * functions, depending on which are available. + * + * ::HWLOC_MEMBIND_STRICT is only meaningful when ::HWLOC_MEMBIND_PROCESS + * is also specified. In this case, hwloc will check the default + * memory policies and nodesets for all threads in the process. If + * they are not identical, -1 is returned and errno is set to \c EXDEV. + * If they are identical, the values are returned in \p set and \p + * policy. + * + * Otherwise, if ::HWLOC_MEMBIND_PROCESS is specified (and + * ::HWLOC_MEMBIND_STRICT is \em not specified), the default set + * from each thread is logically OR'ed together. + * If all threads' default policies are the same, \p policy is set to + * that policy. If they are different, \p policy is set to + * ::HWLOC_MEMBIND_MIXED. + * + * In the ::HWLOC_MEMBIND_THREAD case (or when neither + * ::HWLOC_MEMBIND_PROCESS or ::HWLOC_MEMBIND_THREAD is specified), there + * is only one set and policy; they are returned in \p set and + * \p policy, respectively. + * + * If ::HWLOC_MEMBIND_BYNODESET is specified, set is considered a nodeset. + * Otherwise it's a cpuset. + * + * If any other flags are specified, -1 is returned and errno is set + * to \c EINVAL. + * + * \return 0 on success, -1 on error. + */ +HWLOC_DECLSPEC int hwloc_get_membind(hwloc_topology_t topology, hwloc_bitmap_t set, hwloc_membind_policy_t * policy, int flags); + +/** \brief Set the default memory binding policy of the specified + * process to prefer the NUMA node(s) specified by \p set + * + * If ::HWLOC_MEMBIND_BYNODESET is specified, set is considered a nodeset. + * Otherwise it's a cpuset. + * + * \return 0 on success. + * \return -1 with errno set to \c ENOSYS if the action is not supported. + * \return -1 with errno set to \c EXDEV if the binding cannot be enforced. + * + * \note \p hwloc_pid_t is \p pid_t on Unix platforms, + * and \p HANDLE on native Windows platforms. + */ +HWLOC_DECLSPEC int hwloc_set_proc_membind(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_const_bitmap_t set, hwloc_membind_policy_t policy, int flags); + +/** \brief Query the default memory binding policy and physical locality of the + * specified process. + * + * The bitmap \p set (previously allocated by the caller) + * is filled with the process memory binding. + * + * This function has two output parameters: \p set and \p policy. + * The values returned in these parameters depend on both the \p flags + * passed in and the current memory binding policies and nodesets in + * the queried target. + * + * Passing the ::HWLOC_MEMBIND_PROCESS flag specifies that the query + * target is the current policies and nodesets for all the threads in + * the specified process. If ::HWLOC_MEMBIND_PROCESS is not specified + * (which is the most portable method), the process is assumed to be + * single threaded. This allows hwloc to use either process-based OS + * functions or thread-based OS functions, depending on which are + * available. + * + * Note that it does not make sense to pass ::HWLOC_MEMBIND_THREAD to + * this function. + * + * If ::HWLOC_MEMBIND_STRICT is specified, hwloc will check the default + * memory policies and nodesets for all threads in the specified + * process. If they are not identical, -1 is returned and errno is + * set to \c EXDEV. If they are identical, the values are returned in \p + * set and \p policy. + * + * Otherwise, \p set is set to the logical OR of all threads' + * default set. If all threads' default policies + * are the same, \p policy is set to that policy. If they are + * different, \p policy is set to ::HWLOC_MEMBIND_MIXED. + * + * If ::HWLOC_MEMBIND_BYNODESET is specified, set is considered a nodeset. + * Otherwise it's a cpuset. + * + * If any other flags are specified, -1 is returned and errno is set + * to \c EINVAL. + * + * \return 0 on success, -1 on error. + * + * \note \p hwloc_pid_t is \p pid_t on Unix platforms, + * and \p HANDLE on native Windows platforms. + */ +HWLOC_DECLSPEC int hwloc_get_proc_membind(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_bitmap_t set, hwloc_membind_policy_t * policy, int flags); + +/** \brief Bind the already-allocated memory identified by (addr, len) + * to the NUMA node(s) specified by \p set. + * + * If ::HWLOC_MEMBIND_BYNODESET is specified, set is considered a nodeset. + * Otherwise it's a cpuset. + * + * \return 0 on success or if \p len is 0. + * \return -1 with errno set to \c ENOSYS if the action is not supported. + * \return -1 with errno set to \c EXDEV if the binding cannot be enforced. + */ +HWLOC_DECLSPEC int hwloc_set_area_membind(hwloc_topology_t topology, const void *addr, size_t len, hwloc_const_bitmap_t set, hwloc_membind_policy_t policy, int flags); + +/** \brief Query the CPUs near the physical NUMA node(s) and binding policy of + * the memory identified by (\p addr, \p len ). + * + * The bitmap \p set (previously allocated by the caller) + * is filled with the memory area binding. + * + * This function has two output parameters: \p set and \p policy. + * The values returned in these parameters depend on both the \p flags + * passed in and the memory binding policies and nodesets of the pages + * in the address range. + * + * If ::HWLOC_MEMBIND_STRICT is specified, the target pages are first + * checked to see if they all have the same memory binding policy and + * nodeset. If they do not, -1 is returned and errno is set to \c EXDEV. + * If they are identical across all pages, the set and policy are + * returned in \p set and \p policy, respectively. + * + * If ::HWLOC_MEMBIND_STRICT is not specified, the union of all NUMA + * node(s) containing pages in the address range is calculated. + * If all pages in the target have the same policy, it is returned in + * \p policy. Otherwise, \p policy is set to ::HWLOC_MEMBIND_MIXED. + * + * If ::HWLOC_MEMBIND_BYNODESET is specified, set is considered a nodeset. + * Otherwise it's a cpuset. + * + * If any other flags are specified, -1 is returned and errno is set + * to \c EINVAL. + * + * \return 0 on success. + * \return -1 with errno set to \c EINVAL if \p len is 0. + */ +HWLOC_DECLSPEC int hwloc_get_area_membind(hwloc_topology_t topology, const void *addr, size_t len, hwloc_bitmap_t set, hwloc_membind_policy_t * policy, int flags); + +/** \brief Get the NUMA nodes where memory identified by (\p addr, \p len ) is physically allocated. + * + * The bitmap \p set (previously allocated by the caller) + * is filled according to the NUMA nodes where the memory area pages + * are physically allocated. If no page is actually allocated yet, + * \p set may be empty. + * + * If pages spread to multiple nodes, it is not specified whether they spread + * equitably, or whether most of them are on a single node, etc. + * + * The operating system may move memory pages from one processor + * to another at any time according to their binding, + * so this function may return something that is already + * outdated. + * + * If ::HWLOC_MEMBIND_BYNODESET is specified in \p flags, set is + * considered a nodeset. Otherwise it's a cpuset. + * + * If \p len is 0, \p set is emptied. + * + * \return 0 on success, -1 on error. + */ +HWLOC_DECLSPEC int hwloc_get_area_memlocation(hwloc_topology_t topology, const void *addr, size_t len, hwloc_bitmap_t set, int flags); + +/** \brief Allocate some memory + * + * This is equivalent to malloc(), except that it tries to allocate + * page-aligned memory from the OS. + * + * \return a pointer to the allocated area, or \c NULL on error. + * + * \note The allocated memory should be freed with hwloc_free(). + */ +HWLOC_DECLSPEC void *hwloc_alloc(hwloc_topology_t topology, size_t len); + +/** \brief Allocate some memory on NUMA memory nodes specified by \p set + * + * \return a pointer to the allocated area. + * \return NULL with errno set to \c ENOSYS if the action is not supported + * and ::HWLOC_MEMBIND_STRICT is given. + * \return NULL with errno set to \c EXDEV if the binding cannot be enforced + * and ::HWLOC_MEMBIND_STRICT is given. + * \return NULL with errno set to \c ENOMEM if the memory allocation failed + * even before trying to bind. + * + * If ::HWLOC_MEMBIND_BYNODESET is specified, set is considered a nodeset. + * Otherwise it's a cpuset. + * + * \note The allocated memory should be freed with hwloc_free(). + */ +HWLOC_DECLSPEC void *hwloc_alloc_membind(hwloc_topology_t topology, size_t len, hwloc_const_bitmap_t set, hwloc_membind_policy_t policy, int flags) __hwloc_attribute_malloc; + +/** \brief Allocate some memory on NUMA memory nodes specified by \p set + * + * First, try to allocate properly with hwloc_alloc_membind(). + * On failure, the current process or thread memory binding policy + * is changed with hwloc_set_membind() before allocating memory. + * Thus this function works in more cases, at the expense of changing + * the current state (possibly affecting future allocations that + * would not specify any policy). + * + * If ::HWLOC_MEMBIND_BYNODESET is specified, set is considered a nodeset. + * Otherwise it's a cpuset. + * + * \return a pointer to the allocated area, or \c NULL on error. + */ +static __hwloc_inline void * +hwloc_alloc_membind_policy(hwloc_topology_t topology, size_t len, hwloc_const_bitmap_t set, hwloc_membind_policy_t policy, int flags) __hwloc_attribute_malloc; + +/** \brief Free memory that was previously allocated by hwloc_alloc() + * or hwloc_alloc_membind(). + * + * \return 0 on success, -1 on error. + */ +HWLOC_DECLSPEC int hwloc_free(hwloc_topology_t topology, void *addr, size_t len); + +/** @} */ + + + +/** \defgroup hwlocality_setsource Changing the Source of Topology Discovery + * + * These functions must be called between hwloc_topology_init() and hwloc_topology_load(). + * Otherwise, they will return -1 with errno set to \c EBUSY. + * + * If none of the functions below is called, the default is to detect all the objects + * of the machine that the caller is allowed to access. + * + * This default behavior may also be modified through environment variables + * if the application did not modify it already. + * Setting HWLOC_XMLFILE in the environment enforces the discovery from a XML + * file as if hwloc_topology_set_xml() had been called. + * Setting HWLOC_SYNTHETIC enforces a synthetic topology as if + * hwloc_topology_set_synthetic() had been called. + * + * Finally, HWLOC_THISSYSTEM enforces the return value of + * hwloc_topology_is_thissystem(). + * + * @{ + */ + +/** \brief Change which process the topology is viewed from. + * + * On some systems, processes may have different views of the machine, for + * instance the set of allowed CPUs. By default, hwloc exposes the view from + * the current process. Calling hwloc_topology_set_pid() permits to make it + * expose the topology of the machine from the point of view of another + * process. + * + * \note \p hwloc_pid_t is \p pid_t on Unix platforms, + * and \p HANDLE on native Windows platforms. + * + * \note -1 is returned and errno is set to \c ENOSYS on platforms that do not + * support this feature. + * + * \note The PID will not actually be used until hwloc_topology_load(). + * If the corresponding process exits in the meantime, hwloc will ignore the PID. + * If another process reuses the PID, the view of that process will be used. + * + * \return 0 on success, -1 on error. + */ +HWLOC_DECLSPEC int hwloc_topology_set_pid(hwloc_topology_t __hwloc_restrict topology, hwloc_pid_t pid); + +/** \brief Enable synthetic topology. + * + * Gather topology information from the given \p description, + * a space-separated string of describing + * the object type and arity at each level. + * All types may be omitted (space-separated string of numbers) so that + * hwloc chooses all types according to usual topologies. + * See also the \ref synthetic. + * + * Setting the environment variable HWLOC_SYNTHETIC + * may also result in this behavior. + * + * If \p description was properly parsed and describes a valid topology + * configuration, this function returns 0. + * Otherwise -1 is returned and errno is set to \c EINVAL. + * + * Note that this function does not actually load topology + * information; it just tells hwloc where to load it from. You'll + * still need to invoke hwloc_topology_load() to actually load the + * topology information. + * + * \return 0 on success. + * \return -1 with errno set to \c EINVAL if the description was invalid. + * + * \note For convenience, this backend provides empty binding hooks which just + * return success. + * + * \note On success, the synthetic component replaces the previously enabled + * component (if any), but the topology is not actually modified until + * hwloc_topology_load(). + */ +HWLOC_DECLSPEC int hwloc_topology_set_synthetic(hwloc_topology_t __hwloc_restrict topology, const char * __hwloc_restrict description); + +/** \brief Enable XML-file based topology. + * + * Gather topology information from the XML file given at \p xmlpath. + * Setting the environment variable HWLOC_XMLFILE may also result in this behavior. + * This file may have been generated earlier with hwloc_topology_export_xml() in hwloc/export.h, + * or lstopo file.xml. + * + * Note that this function does not actually load topology + * information; it just tells hwloc where to load it from. You'll + * still need to invoke hwloc_topology_load() to actually load the + * topology information. + * + * \return 0 on success. + * \return -1 with errno set to \c EINVAL on failure to read the XML file. + * + * \note See also hwloc_topology_set_userdata_import_callback() + * for importing application-specific object userdata. + * + * \note For convenience, this backend provides empty binding hooks which just + * return success. To have hwloc still actually call OS-specific hooks, the + * ::HWLOC_TOPOLOGY_FLAG_IS_THISSYSTEM has to be set to assert that the loaded + * file is really the underlying system. + * + * \note On success, the XML component replaces the previously enabled + * component (if any), but the topology is not actually modified until + * hwloc_topology_load(). + * + * \note If an invalid XML input file is given, the error may be reported + * either here or later by hwloc_topology_load() depending on the XML library + * used by hwloc. + */ +HWLOC_DECLSPEC int hwloc_topology_set_xml(hwloc_topology_t __hwloc_restrict topology, const char * __hwloc_restrict xmlpath); + +/** \brief Enable XML based topology using a memory buffer (instead of + * a file, as with hwloc_topology_set_xml()). + * + * Gather topology information from the XML memory buffer given at + * \p buffer and of length \p size (including an ending \c \0). + * This buffer may have been filled earlier with + * hwloc_topology_export_xmlbuffer() in hwloc/export.h. + * + * Note that this function does not actually load topology + * information; it just tells hwloc where to load it from. You'll + * still need to invoke hwloc_topology_load() to actually load the + * topology information. + * + * \return 0 on success. + * \return -1 with errno set to \c EINVAL on failure to read the XML buffer. + * + * \note See also hwloc_topology_set_userdata_import_callback() + * for importing application-specific object userdata. + * + * \note For convenience, this backend provides empty binding hooks which just + * return success. To have hwloc still actually call OS-specific hooks, the + * ::HWLOC_TOPOLOGY_FLAG_IS_THISSYSTEM has to be set to assert that the loaded + * file is really the underlying system. + * + * \note On success, the XML component replaces the previously enabled + * component (if any), but the topology is not actually modified until + * hwloc_topology_load(). + * + * \note If an invalid XML input file is given, the error may be reported + * either here or later by hwloc_topology_load() depending on the XML library + * used by hwloc. + */ +HWLOC_DECLSPEC int hwloc_topology_set_xmlbuffer(hwloc_topology_t __hwloc_restrict topology, const char * __hwloc_restrict buffer, int size); + +/** \brief Flags to be passed to hwloc_topology_set_components() + */ +enum hwloc_topology_components_flag_e { + /** \brief Blacklist the target component from being used. + * \hideinitializer + */ + HWLOC_TOPOLOGY_COMPONENTS_FLAG_BLACKLIST = (1UL<<0) +}; + +/** \brief Prevent a discovery component from being used for a topology. + * + * \p name is the name of the discovery component that should not be used + * when loading topology \p topology. The name is a string such as "cuda". + * + * For components with multiple phases, it may also be suffixed with the name + * of a phase, for instance "linux:io". + * + * \p flags should be ::HWLOC_TOPOLOGY_COMPONENTS_FLAG_BLACKLIST. + * + * This may be used to avoid expensive parts of the discovery process. + * For instance, CUDA-specific discovery may be expensive and unneeded + * while generic I/O discovery could still be useful. + * + * \return 0 on success. + * \return -1 on error, for instance if flags are invalid. + */ +HWLOC_DECLSPEC int hwloc_topology_set_components(hwloc_topology_t __hwloc_restrict topology, unsigned long flags, const char * __hwloc_restrict name); + +/** @} */ + + + +/** \defgroup hwlocality_configuration Topology Detection Configuration and Query + * + * Several functions can optionally be called between hwloc_topology_init() and + * hwloc_topology_load() to configure how the detection should be performed, + * e.g. to ignore some objects types, define a synthetic topology, etc. + * + * @{ + */ + +/** \brief Flags to be set onto a topology context before load. + * + * Flags should be given to hwloc_topology_set_flags(). + * They may also be returned by hwloc_topology_get_flags(). + */ +enum hwloc_topology_flags_e { + /** \brief Detect the whole system, ignore reservations, include disallowed objects. + * + * Gather all online resources, even if some were disabled by the administrator. + * For instance, ignore Linux Cgroup/Cpusets and gather all processors and memory nodes. + * However offline PUs and NUMA nodes are still ignored. + * + * When this flag is not set, PUs and NUMA nodes that are disallowed are not added to the topology. + * Parent objects (package, core, cache, etc.) are added only if some of their children are allowed. + * All existing PUs and NUMA nodes in the topology are allowed. + * hwloc_topology_get_allowed_cpuset() and hwloc_topology_get_allowed_nodeset() + * are equal to the root object cpuset and nodeset. + * + * When this flag is set, the actual sets of allowed PUs and NUMA nodes are given + * by hwloc_topology_get_allowed_cpuset() and hwloc_topology_get_allowed_nodeset(). + * They may be smaller than the root object cpuset and nodeset. + * + * If the current topology is exported to XML and reimported later, this flag + * should be set again in the reimported topology so that disallowed resources + * are reimported as well. + * \hideinitializer + */ + HWLOC_TOPOLOGY_FLAG_INCLUDE_DISALLOWED = (1UL<<0), + + /** \brief Assume that the selected backend provides the topology for the + * system on which we are running. + * + * This forces hwloc_topology_is_thissystem() to return 1, i.e. makes hwloc assume that + * the selected backend provides the topology for the system on which we are running, + * even if it is not the OS-specific backend but the XML backend for instance. + * This means making the binding functions actually call the OS-specific + * system calls and really do binding, while the XML backend would otherwise + * provide empty hooks just returning success. + * + * Setting the environment variable HWLOC_THISSYSTEM may also result in the + * same behavior. + * + * This can be used for efficiency reasons to first detect the topology once, + * save it to an XML file, and quickly reload it later through the XML + * backend, but still having binding functions actually do bind. + * \hideinitializer + */ + HWLOC_TOPOLOGY_FLAG_IS_THISSYSTEM = (1UL<<1), + + /** \brief Get the set of allowed resources from the local operating system even if the topology was loaded from XML or synthetic description. + * + * If the topology was loaded from XML or from a synthetic string, + * restrict it by applying the current process restrictions such as + * Linux Cgroup/Cpuset. + * + * This is useful when the topology is not loaded directly from + * the local machine (e.g. for performance reason) and it comes + * with all resources, while the running process is restricted + * to only parts of the machine. + * + * This flag is ignored unless ::HWLOC_TOPOLOGY_FLAG_IS_THISSYSTEM is + * also set since the loaded topology must match the underlying machine + * where restrictions will be gathered from. + * + * Setting the environment variable HWLOC_THISSYSTEM_ALLOWED_RESOURCES + * would result in the same behavior. + * \hideinitializer + */ + HWLOC_TOPOLOGY_FLAG_THISSYSTEM_ALLOWED_RESOURCES = (1UL<<2), + + /** \brief Import support from the imported topology. + * + * When importing a XML topology from a remote machine, binding is + * disabled by default (see ::HWLOC_TOPOLOGY_FLAG_IS_THISSYSTEM). + * This disabling is also marked by putting zeroes in the corresponding + * supported feature bits reported by hwloc_topology_get_support(). + * + * The flag ::HWLOC_TOPOLOGY_FLAG_IMPORT_SUPPORT actually imports + * support bits from the remote machine. It also sets the flag + * \p imported_support in the struct hwloc_topology_misc_support array. + * If the imported XML did not contain any support information + * (exporter hwloc is too old), this flag is not set. + * + * Note that these supported features are only relevant for the hwloc + * installation that actually exported the XML topology + * (it may vary with the operating system, or with how hwloc was compiled). + * + * Note that setting this flag however does not enable binding for the + * locally imported hwloc topology, it only reports what the remote + * hwloc and machine support. + * + */ + HWLOC_TOPOLOGY_FLAG_IMPORT_SUPPORT = (1UL<<3), + + /** \brief Do not consider resources outside of the process CPU binding. + * + * If the binding of the process is limited to a subset of cores, + * ignore the other cores during discovery. + * + * The resulting topology is identical to what a call to hwloc_topology_restrict() + * would generate, but this flag also prevents hwloc from ever touching other + * resources during the discovery. + * + * This flag especially tells the x86 backend to never temporarily + * rebind a thread on any excluded core. This is useful on Windows + * because such temporary rebinding can change the process binding. + * Another use-case is to avoid cores that would not be able to + * perform the hwloc discovery anytime soon because they are busy + * executing some high-priority real-time tasks. + * + * If process CPU binding is not supported, + * the thread CPU binding is considered instead if supported, + * or the flag is ignored. + * + * This flag requires ::HWLOC_TOPOLOGY_FLAG_IS_THISSYSTEM as well + * since binding support is required. + */ + HWLOC_TOPOLOGY_FLAG_RESTRICT_TO_CPUBINDING = (1UL<<4), + + /** \brief Do not consider resources outside of the process memory binding. + * + * If the binding of the process is limited to a subset of NUMA nodes, + * ignore the other NUMA nodes during discovery. + * + * The resulting topology is identical to what a call to hwloc_topology_restrict() + * would generate, but this flag also prevents hwloc from ever touching other + * resources during the discovery. + * + * This flag is meant to be used together with + * ::HWLOC_TOPOLOGY_FLAG_RESTRICT_TO_CPUBINDING when both cores + * and NUMA nodes should be ignored outside of the process binding. + * + * If process memory binding is not supported, + * the thread memory binding is considered instead if supported, + * or the flag is ignored. + * + * This flag requires ::HWLOC_TOPOLOGY_FLAG_IS_THISSYSTEM as well + * since binding support is required. + */ + HWLOC_TOPOLOGY_FLAG_RESTRICT_TO_MEMBINDING = (1UL<<5), + + /** \brief Do not ever modify the process or thread binding during discovery. + * + * This flag disables all hwloc discovery steps that require a change of + * the process or thread binding. This currently only affects the x86 + * backend which gets entirely disabled. + * + * This is useful when hwloc_topology_load() is called while the + * application also creates additional threads or modifies the binding. + * + * This flag is also a strict way to make sure the process binding will + * not change to due thread binding changes on Windows + * (see ::HWLOC_TOPOLOGY_FLAG_RESTRICT_TO_CPUBINDING). + */ + HWLOC_TOPOLOGY_FLAG_DONT_CHANGE_BINDING = (1UL<<6), + + /** \brief Ignore distances. + * + * Ignore distance information from the operating systems (and from XML) + * and hence do not use distances for grouping. + */ + HWLOC_TOPOLOGY_FLAG_NO_DISTANCES = (1UL<<7), + + /** \brief Ignore memory attributes and tiers. + * + * Ignore memory attribues from the operating systems (and from XML) + * Hence also do not try to build memory tiers. + */ + HWLOC_TOPOLOGY_FLAG_NO_MEMATTRS = (1UL<<8), + + /** \brief Ignore CPU Kinds. + * + * Ignore CPU kind information from the operating systems (and from XML). + */ + HWLOC_TOPOLOGY_FLAG_NO_CPUKINDS = (1UL<<9) +}; + +/** \brief Set OR'ed flags to non-yet-loaded topology. + * + * Set a OR'ed set of ::hwloc_topology_flags_e onto a topology that was not yet loaded. + * + * If this function is called multiple times, the last invocation will erase + * and replace the set of flags that was previously set. + * + * By default, no flags are set (\c 0). + * + * The flags set in a topology may be retrieved with hwloc_topology_get_flags(). + * + * \return 0 on success. + * \return -1 on error, for instance if flags are invalid. + */ +HWLOC_DECLSPEC int hwloc_topology_set_flags (hwloc_topology_t topology, unsigned long flags); + +/** \brief Get OR'ed flags of a topology. + * + * Get the OR'ed set of ::hwloc_topology_flags_e of a topology. + * + * If hwloc_topology_set_flags() was not called earlier, + * no flags are set (\c 0 is returned). + * + * \return the flags previously set with hwloc_topology_set_flags(). + * + * \note This function may also be called after hwloc_topology_load(). + */ +HWLOC_DECLSPEC unsigned long hwloc_topology_get_flags (hwloc_topology_t topology); + +/** \brief Does the topology context come from this system? + * + * \return 1 if this topology context was built using the system + * running this program. + * \return 0 instead (for instance if using another file-system root, + * a XML topology file, or a synthetic topology). + * + * \note This function may also be called after hwloc_topology_load(). + */ +HWLOC_DECLSPEC int hwloc_topology_is_thissystem(hwloc_topology_t __hwloc_restrict topology) __hwloc_attribute_pure; + +/** \brief Flags describing actual discovery support for this topology. */ +struct hwloc_topology_discovery_support { + /** \brief Detecting the number of PU objects is supported. */ + unsigned char pu; + /** \brief Detecting the number of NUMA nodes is supported. */ + unsigned char numa; + /** \brief Detecting the amount of memory in NUMA nodes is supported. */ + unsigned char numa_memory; + /** \brief Detecting and identifying PU objects that are not available to the current process is supported. */ + unsigned char disallowed_pu; + /** \brief Detecting and identifying NUMA nodes that are not available to the current process is supported. */ + unsigned char disallowed_numa; + /** \brief Detecting the efficiency of CPU kinds is supported, see \ref hwlocality_cpukinds. */ + unsigned char cpukind_efficiency; +}; + +/** \brief Flags describing actual PU binding support for this topology. + * + * A flag may be set even if the feature isn't supported in all cases + * (e.g. binding to random sets of non-contiguous objects). + */ +struct hwloc_topology_cpubind_support { + /** Binding the whole current process is supported. */ + unsigned char set_thisproc_cpubind; + /** Getting the binding of the whole current process is supported. */ + unsigned char get_thisproc_cpubind; + /** Binding a whole given process is supported. */ + unsigned char set_proc_cpubind; + /** Getting the binding of a whole given process is supported. */ + unsigned char get_proc_cpubind; + /** Binding the current thread only is supported. */ + unsigned char set_thisthread_cpubind; + /** Getting the binding of the current thread only is supported. */ + unsigned char get_thisthread_cpubind; + /** Binding a given thread only is supported. */ + unsigned char set_thread_cpubind; + /** Getting the binding of a given thread only is supported. */ + unsigned char get_thread_cpubind; + /** Getting the last processors where the whole current process ran is supported */ + unsigned char get_thisproc_last_cpu_location; + /** Getting the last processors where a whole process ran is supported */ + unsigned char get_proc_last_cpu_location; + /** Getting the last processors where the current thread ran is supported */ + unsigned char get_thisthread_last_cpu_location; +}; + +/** \brief Flags describing actual memory binding support for this topology. + * + * A flag may be set even if the feature isn't supported in all cases + * (e.g. binding to random sets of non-contiguous objects). + */ +struct hwloc_topology_membind_support { + /** Binding the whole current process is supported. */ + unsigned char set_thisproc_membind; + /** Getting the binding of the whole current process is supported. */ + unsigned char get_thisproc_membind; + /** Binding a whole given process is supported. */ + unsigned char set_proc_membind; + /** Getting the binding of a whole given process is supported. */ + unsigned char get_proc_membind; + /** Binding the current thread only is supported. */ + unsigned char set_thisthread_membind; + /** Getting the binding of the current thread only is supported. */ + unsigned char get_thisthread_membind; + /** Binding a given memory area is supported. */ + unsigned char set_area_membind; + /** Getting the binding of a given memory area is supported. */ + unsigned char get_area_membind; + /** Allocating a bound memory area is supported. */ + unsigned char alloc_membind; + /** First-touch policy is supported. */ + unsigned char firsttouch_membind; + /** Bind policy is supported. */ + unsigned char bind_membind; + /** Interleave policy is supported. */ + unsigned char interleave_membind; + /** Next-touch migration policy is supported. */ + unsigned char nexttouch_membind; + /** Migration flags is supported. */ + unsigned char migrate_membind; + /** Getting the last NUMA nodes where a memory area was allocated is supported */ + unsigned char get_area_memlocation; + /** Weighted interleave policy is supported. */ + unsigned char weighted_interleave_membind; +}; + +/** \brief Flags describing miscellaneous features. + */ +struct hwloc_topology_misc_support { + /** Support was imported when importing another topology, see ::HWLOC_TOPOLOGY_FLAG_IMPORT_SUPPORT. */ + unsigned char imported_support; +}; + +/** \brief Set of flags describing actual support for this topology. + * + * This is retrieved with hwloc_topology_get_support() and will be valid until + * the topology object is destroyed. Note: the values are correct only after + * discovery. + */ +struct hwloc_topology_support { + struct hwloc_topology_discovery_support *discovery; + struct hwloc_topology_cpubind_support *cpubind; + struct hwloc_topology_membind_support *membind; + struct hwloc_topology_misc_support *misc; +}; + +/** \brief Retrieve the topology support. + * + * Each flag indicates whether a feature is supported. + * If set to 0, the feature is not supported. + * If set to 1, the feature is supported, but the corresponding + * call may still fail in some corner cases. + * + * These features are also listed by hwloc-info \--support + * + * The reported features are what the current topology supports + * on the current machine. If the topology was exported to XML + * from another machine and later imported here, support still + * describes what is supported for this imported topology after + * import. By default, binding will be reported as unsupported + * in this case (see ::HWLOC_TOPOLOGY_FLAG_IS_THISSYSTEM). + * + * Topology flag ::HWLOC_TOPOLOGY_FLAG_IMPORT_SUPPORT may be used + * to report the supported features of the original remote machine + * instead. If it was successfully imported, \p imported_support + * will be set in the struct hwloc_topology_misc_support array. + * + * \return A pointer to a support structure. + * + * \note The function cannot return \c NULL. + * \note The returned pointer should not be freed, it belongs to the hwloc library. + * + * \note This function may be called before or after hwloc_topology_load() + * but the support structure only contains valid information after. + */ +HWLOC_DECLSPEC const struct hwloc_topology_support *hwloc_topology_get_support(hwloc_topology_t __hwloc_restrict topology); + +/** \brief Type filtering flags. + * + * By default, most objects are kept (::HWLOC_TYPE_FILTER_KEEP_ALL). + * Instruction caches, memory-side caches, I/O and Misc objects are ignored by default (::HWLOC_TYPE_FILTER_KEEP_NONE). + * Group levels are ignored unless they bring structure (::HWLOC_TYPE_FILTER_KEEP_STRUCTURE). + * + * Note that group objects are also ignored individually (without the entire level) + * when they do not bring structure. + */ +enum hwloc_type_filter_e { + /** \brief Keep all objects of this type. + * + * Cannot be set for ::HWLOC_OBJ_GROUP (groups are designed only to add more structure to the topology). + * \hideinitializer + */ + HWLOC_TYPE_FILTER_KEEP_ALL = 0, + + /** \brief Ignore all objects of this type. + * + * The bottom-level type ::HWLOC_OBJ_PU, the ::HWLOC_OBJ_NUMANODE type, and + * the top-level type ::HWLOC_OBJ_MACHINE may not be ignored. + * \hideinitializer + */ + HWLOC_TYPE_FILTER_KEEP_NONE = 1, + + /** \brief Only ignore objects if their entire level does not bring any structure. + * + * Keep the entire level of objects if at least one of these objects adds + * structure to the topology. An object brings structure when it has multiple + * children and it is not the only child of its parent. + * + * If all objects in the level are the only child of their parent, and if none + * of them has multiple children, the entire level is removed. + * + * Cannot be set for I/O and Misc objects since the topology structure does not matter there. + * \hideinitializer + */ + HWLOC_TYPE_FILTER_KEEP_STRUCTURE = 2, + + /** \brief Only keep likely-important objects of the given type. + * + * It is only useful for I/O object types. + * For ::HWLOC_OBJ_PCI_DEVICE and ::HWLOC_OBJ_OS_DEVICE, it means that only objects + * of major/common kinds are kept (storage, network, OpenFabrics, CUDA, + * OpenCL, RSMI, NVML, and displays). + * Also, only OS devices directly attached on PCI (e.g. no USB) are reported. + * For ::HWLOC_OBJ_BRIDGE, it means that bridges are kept only if they have children. + * + * This flag equivalent to ::HWLOC_TYPE_FILTER_KEEP_ALL for Normal, Memory and Misc types + * since they are likely important. + * \hideinitializer + */ + HWLOC_TYPE_FILTER_KEEP_IMPORTANT = 3 +}; + +/** \brief Set the filtering for the given object type. + * + * \return 0 on success, -1 on error. + */ +HWLOC_DECLSPEC int hwloc_topology_set_type_filter(hwloc_topology_t topology, hwloc_obj_type_t type, enum hwloc_type_filter_e filter); + +/** \brief Get the current filtering for the given object type. + * + * \return 0 on success, -1 on error. + */ +HWLOC_DECLSPEC int hwloc_topology_get_type_filter(hwloc_topology_t topology, hwloc_obj_type_t type, enum hwloc_type_filter_e *filter); + +/** \brief Set the filtering for all object types. + * + * If some types do not support this filtering, they are silently ignored. + * + * \return 0 on success, -1 on error. + */ +HWLOC_DECLSPEC int hwloc_topology_set_all_types_filter(hwloc_topology_t topology, enum hwloc_type_filter_e filter); + +/** \brief Set the filtering for all CPU cache object types. + * + * Memory-side caches are not involved since they are not CPU caches. + * + * \return 0 on success, -1 on error. + */ +HWLOC_DECLSPEC int hwloc_topology_set_cache_types_filter(hwloc_topology_t topology, enum hwloc_type_filter_e filter); + +/** \brief Set the filtering for all CPU instruction cache object types. + * + * Memory-side caches are not involved since they are not CPU caches. + * + * \return 0 on success, -1 on error. + */ +HWLOC_DECLSPEC int hwloc_topology_set_icache_types_filter(hwloc_topology_t topology, enum hwloc_type_filter_e filter); + +/** \brief Set the filtering for all I/O object types. + * + * \return 0 on success, -1 on error. + */ +HWLOC_DECLSPEC int hwloc_topology_set_io_types_filter(hwloc_topology_t topology, enum hwloc_type_filter_e filter); + +/** \brief Set the topology-specific userdata pointer. + * + * Each topology may store one application-given private data pointer. + * It is initialized to \c NULL. + * hwloc will never modify it. + * + * Use it as you wish, after hwloc_topology_init() and until hwloc_topolog_destroy(). + * + * This pointer is not exported to XML. + */ +HWLOC_DECLSPEC void hwloc_topology_set_userdata(hwloc_topology_t topology, const void *userdata); + +/** \brief Retrieve the topology-specific userdata pointer. + * + * Retrieve the application-given private data pointer that was + * previously set with hwloc_topology_set_userdata(). + * + * \return A pointer to the private-data if any. + * \return \c NULL if no private-data was previoulsy set. + */ +HWLOC_DECLSPEC void * hwloc_topology_get_userdata(hwloc_topology_t topology); + +/** @} */ + + + +/** \defgroup hwlocality_tinker Modifying a loaded Topology + * @{ + */ + +/** \brief Flags to be given to hwloc_topology_restrict(). */ +enum hwloc_restrict_flags_e { + /** \brief Remove all objects that became CPU-less. + * By default, only objects that contain no PU and no memory are removed. + * This flag may not be used with ::HWLOC_RESTRICT_FLAG_BYNODESET. + * \hideinitializer + */ + HWLOC_RESTRICT_FLAG_REMOVE_CPULESS = (1UL<<0), + + /** \brief Restrict by nodeset instead of CPU set. + * Only keep objects whose nodeset is included or partially included in the given set. + * This flag may not be used with ::HWLOC_RESTRICT_FLAG_REMOVE_CPULESS. + */ + HWLOC_RESTRICT_FLAG_BYNODESET = (1UL<<3), + + /** \brief Remove all objects that became Memory-less. + * By default, only objects that contain no PU and no memory are removed. + * This flag may only be used with ::HWLOC_RESTRICT_FLAG_BYNODESET. + * \hideinitializer + */ + HWLOC_RESTRICT_FLAG_REMOVE_MEMLESS = (1UL<<4), + + /** \brief Move Misc objects to ancestors if their parents are removed during restriction. + * If this flag is not set, Misc objects are removed when their parents are removed. + * \hideinitializer + */ + HWLOC_RESTRICT_FLAG_ADAPT_MISC = (1UL<<1), + + /** \brief Move I/O objects to ancestors if their parents are removed during restriction. + * If this flag is not set, I/O devices and bridges are removed when their parents are removed. + * \hideinitializer + */ + HWLOC_RESTRICT_FLAG_ADAPT_IO = (1UL<<2) +}; + +/** \brief Restrict the topology to the given CPU set or nodeset. + * + * Topology \p topology is modified so as to remove all objects that + * are not included (or partially included) in the CPU set \p set. + * All objects CPU and node sets are restricted accordingly. + * + * By default, \p set is a CPU set. It means that the set of PUs in + * the topology is restricted. Once some PUs got removed, their parents + * may also get removed recursively if they became child-less. + * + * If ::HWLOC_RESTRICT_FLAG_BYNODESET is passed in \p flags, + * \p set is considered a nodeset instead of a CPU set. + * It means that the set of NUMA nodes in the topology is restricted + * (instead of PUs). Once some NUMA nodes got removed, their parents + * may also get removed recursively if they became child-less. + * + * \p flags is a OR'ed set of ::hwloc_restrict_flags_e. + * + * \note Restricting the topology removes some locality information, + * hence the remaining objects may get reordered (including PUs and NUMA nodes), + * and their logical indexes may change. + * + * \note This call may not be reverted by restricting back to a larger + * set. Once dropped during restriction, objects may not be brought + * back, except by loading another topology with hwloc_topology_load(). + * + * \return 0 on success. + * + * \return -1 with errno set to \c EINVAL if the input set is invalid. + * The topology is not modified in this case. + * + * \return -1 with errno set to \c ENOMEM on failure to allocate internal data. + * The topology is reinitialized in this case. It should be either + * destroyed with hwloc_topology_destroy() or configured and loaded again. + */ +HWLOC_DECLSPEC int hwloc_topology_restrict(hwloc_topology_t __hwloc_restrict topology, hwloc_const_bitmap_t set, unsigned long flags); + +/** \brief Flags to be given to hwloc_topology_allow(). */ +enum hwloc_allow_flags_e { + /** \brief Mark all objects as allowed in the topology. + * + * \p cpuset and \p nođeset given to hwloc_topology_allow() must be \c NULL. + * \hideinitializer */ + HWLOC_ALLOW_FLAG_ALL = (1UL<<0), + + /** \brief Only allow objects that are available to the current process. + * + * The topology must have ::HWLOC_TOPOLOGY_FLAG_IS_THISSYSTEM so that the set + * of available resources can actually be retrieved from the operating system. + * + * \p cpuset and \p nođeset given to hwloc_topology_allow() must be \c NULL. + * \hideinitializer */ + HWLOC_ALLOW_FLAG_LOCAL_RESTRICTIONS = (1UL<<1), + + /** \brief Allow a custom set of objects, given to hwloc_topology_allow() as \p cpuset and/or \p nodeset parameters. + * \hideinitializer */ + HWLOC_ALLOW_FLAG_CUSTOM = (1UL<<2) +}; + +/** \brief Change the sets of allowed PUs and NUMA nodes in the topology. + * + * This function only works if the ::HWLOC_TOPOLOGY_FLAG_INCLUDE_DISALLOWED + * was set on the topology. It does not modify any object, it only changes + * the sets returned by hwloc_topology_get_allowed_cpuset() and + * hwloc_topology_get_allowed_nodeset(). + * + * It is notably useful when importing a topology from another process + * running in a different Linux Cgroup. + * + * \p flags must be set to one flag among ::hwloc_allow_flags_e. + * + * \return 0 on success, -1 on error. + * + * \note Removing objects from a topology should rather be performed with + * hwloc_topology_restrict(). + */ +HWLOC_DECLSPEC int hwloc_topology_allow(hwloc_topology_t __hwloc_restrict topology, hwloc_const_cpuset_t cpuset, hwloc_const_nodeset_t nodeset, unsigned long flags); + +/** \brief Add a MISC object as a leaf of the topology + * + * A new MISC object will be created and inserted into the topology at the + * position given by parent. It is appended to the list of existing Misc children, + * without ever adding any intermediate hierarchy level. This is useful for + * annotating the topology without actually changing the hierarchy. + * + * \p name is supposed to be unique across all Misc objects in the topology. + * It will be duplicated to setup the new object attributes. + * + * The new leaf object will not have any \p cpuset. + * + * The \p subtype object attribute may be defined with hwloc_obj_set_subtype() + * after successful insertion. + * + * \return the newly-created object + * + * \return \c NULL on error. + * + * \return \c NULL if Misc objects are filtered-out of the topology (::HWLOC_TYPE_FILTER_KEEP_NONE). + * + * \note If \p name contains some non-printable characters, they will + * be dropped when exporting to XML, see hwloc_topology_export_xml() in hwloc/export.h. + */ +HWLOC_DECLSPEC hwloc_obj_t hwloc_topology_insert_misc_object(hwloc_topology_t topology, hwloc_obj_t parent, const char *name); + +/** \brief Allocate a Group object to insert later with hwloc_topology_insert_group_object(). + * + * This function returns a new Group object. + * + * The caller should (at least) initialize its sets before inserting + * the object in the topology, see hwloc_topology_insert_group_object(). + * Or it may decide not to insert and just free the group object + * by calling hwloc_topology_free_group_object(). + * + * \return The allocated object on success. + * \return \c NULL on error. + * + * \note If successfully inserted by hwloc_topology_insert_group_object(), + * the object will be freed when the entire topology is freed. + * If insertion failed (e.g. \c NULL or empty CPU and node-sets), + * it is freed before returning the error. + */ +HWLOC_DECLSPEC hwloc_obj_t hwloc_topology_alloc_group_object(hwloc_topology_t topology); + +/** \brief Free a group object allocated with hwloc_topology_alloc_group_object(). + * + * This function is only useful if the group object was not given + * to hwloc_topology_insert_group_object() as planned. + * + * \note \p topology must be the same as the one previously passed + * to hwloc_topology_alloc_group_object(). + * + * \return \c 0 on success. + * \return \c -1 on error, for instance if an invalid topology is given. + */ +HWLOC_DECLSPEC int hwloc_topology_free_group_object(hwloc_topology_t topology, hwloc_obj_t group); + +/** \brief Add more structure to the topology by adding an intermediate Group + * + * The caller should first allocate a new Group object with hwloc_topology_alloc_group_object(). + * Then it must setup at least one of its CPU or node sets to specify + * the final location of the Group in the topology. + * Then the object can be passed to this function for actual insertion in the topology. + * + * The main use case for this function is to group a subset of + * siblings among the list of children below a single parent. + * For instance, if grouping 4 cores out of a 8-core socket, + * the logical list of cores will be reordered so that the 4 grouped + * ones are consecutive. + * Then, if needed, a new depth is added between the parent and those + * children, and the Group is inserted there. + * At the end, the 4 grouped cores are now children of the Group, + * which replaces them as a child of the original parent. + * + * In practice, the grouped objects are specified through cpusets + * and/or nodesets, for instance using hwloc_obj_add_other_obj_sets() + * iteratively. + * Hence it is possible to group objects that are not children of the + * same parent, for instance some PUs below the 4 cores in example above. + * However this general case may fail if the expected Group conflicts + * with the existing hierarchy. + * For instance if each core has two PUs, it is not possible to insert + * a Group containing a single PU of each core. + * + * To specify the objects to group, either the cpuset or nodeset field + * (or both, if compatible) must be set to a non-empty bitmap. + * The complete_cpuset or complete_nodeset may be set instead if + * inserting with respect to the complete topology + * (including disallowed, offline or unknown objects). + * These sets cannot be larger than the current topology, or they would get + * restricted silently. + * The core will setup the other sets after actual insertion. + * + * The \p subtype object attribute may be defined with hwloc_obj_set_subtype() + * to display something else than "Group" as the type name for this object in lstopo. + * Custom name-value info pairs may be added with hwloc_obj_add_info() after + * insertion. + * + * The group \p dont_merge attribute may be set to \c 1 to prevent + * the hwloc core from ever merging this object with another + * hierarchically-identical object. + * This is useful when the Group itself describes an important feature + * that cannot be exposed anywhere else in the hierarchy. + * + * The group \p kind attribute may be set to a high value such + * as \c 0xffffffff to tell hwloc that this new Group should always + * be discarded in favor of any existing Group with the same locality. + * + * \note Inserting a group adds some locality information to the topology, + * hence the existing objects may get reordered (including PUs and NUMA nodes), + * and their logical indexes may change. + * + * \note If the insertion fails, the input group object is freed. + * + * \note If the group object should be discarded instead of inserted, + * it may be passed to hwloc_topology_free_group_object() instead. + * + * \note \p topology must be the same as the one previously passed + * to hwloc_topology_alloc_group_object(). + * + * \return The inserted object if it was properly inserted. + * + * \return An existing object if the Group was merged or discarded + * because the topology already contained an object at the same + * location (the Group did not add any hierarchy information). + * + * \return \c NULL if the insertion failed because of conflicting sets in topology tree. + * + * \return \c NULL if Group objects are filtered-out of the topology (::HWLOC_TYPE_FILTER_KEEP_NONE). + * + * \return \c NULL if the object was discarded because no set was + * initialized in the Group before insert, or all of them were empty. + */ +HWLOC_DECLSPEC hwloc_obj_t hwloc_topology_insert_group_object(hwloc_topology_t topology, hwloc_obj_t group); + +/** \brief Setup object cpusets/nodesets by OR'ing another object's sets. + * + * For each defined cpuset or nodeset in \p src, allocate the corresponding set + * in \p dst and add \p src to it by OR'ing sets. + * + * This function is convenient between hwloc_topology_alloc_group_object() + * and hwloc_topology_insert_group_object(). It builds the sets of the new Group + * that will be inserted as a new intermediate parent of several objects. + * + * \return 0 on success. + * \return -1 with errno set to \c ENOMEM if some internal reallocation failed. + */ +HWLOC_DECLSPEC int hwloc_obj_add_other_obj_sets(hwloc_obj_t dst, hwloc_obj_t src); + +/** \brief Refresh internal structures after topology modification. + * + * Modifying the topology (by restricting, adding objects, modifying structures + * such as distances or memory attributes, etc.) may cause some internal caches + * to become invalid. These caches are automatically refreshed when accessed + * but this refreshing is not thread-safe. + * + * This function is not thread-safe either, but it is a good way to end a + * non-thread-safe phase of topology modification. Once this refresh is done, + * multiple threads may concurrently consult the topology, objects, distances, + * attributes, etc. + * + * See also \ref threadsafety + * + * \return 0 on success. + * \return -1 on error, for instance if some internal reallocation failed. + */ +HWLOC_DECLSPEC int hwloc_topology_refresh(hwloc_topology_t topology); + +/** @} */ + + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +/* high-level helpers */ +#include "hwloc/helper.h" + +/* inline code of some functions above */ +#include "hwloc/inlines.h" + +/* memory attributes */ +#include "hwloc/memattrs.h" + +/* kinds of CPU cores */ +#include "hwloc/cpukinds.h" + +/* exporting to XML or synthetic */ +#include "hwloc/export.h" + +/* distances */ +#include "hwloc/distances.h" + +/* topology diffs */ +#include "hwloc/diff.h" + +/* deprecated headers */ +#include "hwloc/deprecated.h" + +#endif /* HWLOC_H */ diff --git a/src/deps/hwloc/include/hwloc/bitmap.h b/src/deps/hwloc/include/hwloc/bitmap.h new file mode 100644 index 000000000..7a39fab01 --- /dev/null +++ b/src/deps/hwloc/include/hwloc/bitmap.h @@ -0,0 +1,581 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * Copyright © 2009 CNRS + * Copyright © 2009-2025 Inria. All rights reserved. + * Copyright © 2009-2012 Université Bordeaux + * Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved. + * See COPYING in top-level directory. + */ + +/** \file + * \brief The bitmap API, for use in hwloc itself. + */ + +#ifndef HWLOC_BITMAP_H +#define HWLOC_BITMAP_H + +#include "hwloc/autogen/config.h" + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** \defgroup hwlocality_bitmap The bitmap API + * + * The ::hwloc_bitmap_t type represents a set of integers (positive or null). + * A bitmap may be of infinite size (all bits are set after some point). + * A bitmap may even be full if all bits are set. + * + * Bitmaps are used by hwloc for sets of OS processors + * (which may actually be hardware threads) as by ::hwloc_cpuset_t + * (a typedef for ::hwloc_bitmap_t), or sets of NUMA memory nodes + * as ::hwloc_nodeset_t (also a typedef for ::hwloc_bitmap_t). + * Those are used for cpuset and nodeset fields in the ::hwloc_obj structure, + * see \ref hwlocality_object_sets. + * + * Both CPU and node sets are always indexed by OS physical number. + * However users should usually not build CPU and node sets manually + * (e.g. with hwloc_bitmap_set()). + * One should rather use existing object sets and combine them with + * hwloc_bitmap_or(), etc. + * For instance, binding the current thread on a pair of cores may be performed with: + * \code + * hwloc_obj_t core1 = ... , core2 = ... ; + * hwloc_bitmap_t set = hwloc_bitmap_alloc(); + * hwloc_bitmap_or(set, core1->cpuset, core2->cpuset); + * hwloc_set_cpubind(topology, set, HWLOC_CPUBIND_THREAD); + * hwloc_bitmap_free(set); + * \endcode + * + * \note Most functions below return 0 on success and -1 on error. + * The usual error case would be an internal failure to realloc/extend + * the storage of the bitmap (\p errno would be set to \c ENOMEM). + * See also \ref hwlocality_api_error_reporting. + * + * \note Several examples of using the bitmap API are available under the + * doc/examples/ directory in the source tree. + * Regression tests such as tests/hwloc/hwloc_bitmap*.c also make intensive use + * of this API. + * @{ + */ + + +/** \brief + * Set of bits represented as an opaque pointer to an internal bitmap. + */ +typedef struct hwloc_bitmap_s * hwloc_bitmap_t; +/** \brief a non-modifiable ::hwloc_bitmap_t */ +typedef const struct hwloc_bitmap_s * hwloc_const_bitmap_t; + + +/* + * Bitmap allocation, freeing and copying. + */ + +/** \brief Allocate a new empty bitmap. + * + * \returns A valid bitmap or \c NULL. + * + * The bitmap should be freed by a corresponding call to + * hwloc_bitmap_free(). + */ +HWLOC_DECLSPEC hwloc_bitmap_t hwloc_bitmap_alloc(void) __hwloc_attribute_malloc; + +/** \brief Allocate a new full bitmap. + * + * \returns A valid bitmap or \c NULL. + * + * The bitmap should be freed by a corresponding call to + * hwloc_bitmap_free(). + */ +HWLOC_DECLSPEC hwloc_bitmap_t hwloc_bitmap_alloc_full(void) __hwloc_attribute_malloc; + +/** \brief Free bitmap \p bitmap. + * + * If \p bitmap is \c NULL, no operation is performed. + */ +HWLOC_DECLSPEC void hwloc_bitmap_free(hwloc_bitmap_t bitmap); + +/** \brief Duplicate bitmap \p bitmap by allocating a new bitmap and copying \p bitmap contents. + * + * If \p bitmap is \c NULL, \c NULL is returned. + */ +HWLOC_DECLSPEC hwloc_bitmap_t hwloc_bitmap_dup(hwloc_const_bitmap_t bitmap) __hwloc_attribute_malloc; + +/** \brief Copy the contents of bitmap \p src into the already allocated bitmap \p dst */ +HWLOC_DECLSPEC int hwloc_bitmap_copy(hwloc_bitmap_t dst, hwloc_const_bitmap_t src); + + +/* + * Bitmap/String Conversion + */ + +/** \brief Stringify a bitmap in the default hwloc format. + * + * Print the bits set inside a bitmap as a comma-separated list of hexadecimal 32-bit blocks. + * A bitmap containing bits 1, 33, 34, and all from 64 to 95 is printed as "0xffffffff,0x00000006,0x00000002". + * + * Up to \p buflen characters may be written in buffer \p buf. + * + * If \p buflen is 0, \p buf may safely be \c NULL. + * + * \return the number of characters that were actually written if not truncating, + * or that would have been written (not including the ending \c \0). + * \return -1 on error. + * + * \note If the bitmap is a CPU or nodeset, it contains physical indexes. + * This should be clearly indicated when displaying such bitmaps to end users. + * See also \ref faq_convert_indexes + */ +HWLOC_DECLSPEC int hwloc_bitmap_snprintf(char * __hwloc_restrict buf, size_t buflen, hwloc_const_bitmap_t bitmap); + +/** \brief Stringify a bitmap into a newly allocated string in the default hwloc format. + * + * Print the bits set inside a bitmap as a comma-separated list of hexadecimal 32-bit blocks. + * A bitmap containing bits 1, 33, 34, and all from 64 to 95 is printed as "0xffffffff,0x00000006,0x00000002". + * + * \return the number of characters that were written (not including the ending \c \0). + * \return -1 on error, for instance with \p errno set to \c ENOMEM on failure to allocate the output string. + * + * \note If the bitmap is a CPU or nodeset, it contains physical indexes. + * This should be clearly indicated when displaying such bitmaps to end users. + * See also \ref faq_convert_indexes + */ +HWLOC_DECLSPEC int hwloc_bitmap_asprintf(char ** strp, hwloc_const_bitmap_t bitmap); + +/** \brief Parse a bitmap string as the default hwloc format and stores it in bitmap \p bitmap. + * + * The input string should be a comma-separared list of hexadecimal 32-bit blocks. + * String "0xffffffff,0x6,0x2" is parsed as a bitmap containing all bits between 64 and 95, + * and bits 33, 34 and 1. + * + * \return 0 on success, -1 on error. + * + * \note If the bitmap is a CPU or nodeset, the input string must contain physical indexes. + */ +HWLOC_DECLSPEC int hwloc_bitmap_sscanf(hwloc_bitmap_t bitmap, const char * __hwloc_restrict string); + +/** \brief Stringify a bitmap in the list format. + * + * Lists are comma-separated indexes or ranges. + * Ranges are dash separated indexes. + * A bitmap containing bits 1, 33, 34, and all from 64 to 95 is printed as "1,33-34,64-95". + * The last range may not have an ending index if the bitmap is infinitely set. + * + * Up to \p buflen characters may be written in buffer \p buf. + * + * If \p buflen is 0, \p buf may safely be \c NULL. + * + * \return the number of characters that were actually written if not truncating, + * or that would have been written (not including the ending \c \0). + * \return -1 on error. + * + * \note If the bitmap is a CPU or nodeset, it contains physical indexes. + * This should be clearly indicated when displaying such bitmaps to end users. + * See also \ref faq_convert_indexes + */ +HWLOC_DECLSPEC int hwloc_bitmap_list_snprintf(char * __hwloc_restrict buf, size_t buflen, hwloc_const_bitmap_t bitmap); + +/** \brief Stringify a bitmap into a newly allocated list string. + * + * Lists are comma-separated indexes or ranges. + * Ranges are dash separated indexes. + * A bitmap containing bits 1, 33, 34, and all from 64 to 95 is printed as "1,33-34,64-95". + * The last range may not have an ending index if the bitmap is infinitely set. + * + * \return the number of characters that were written (not including the ending \c \0). + * \return -1 on error, for instance with \p errno set to \c ENOMEM on failure to allocate the output string. + * + * \note If the bitmap is a CPU or nodeset, it contains physical indexes. + * This should be clearly indicated when displaying such bitmaps to end users. + * See also \ref faq_convert_indexes + */ +HWLOC_DECLSPEC int hwloc_bitmap_list_asprintf(char ** strp, hwloc_const_bitmap_t bitmap); + +/** \brief Parse a list string and stores it in bitmap \p bitmap. + * + * Lists are comma-separated indexes or ranges. + * Ranges are dash separated indexes. + * String "1,33-34,64-95" is parsed as a bitmap containing bits 1, 33, 34, and all from 64 to 95. + * The last range may not have an ending index if the bitmap is infinitely set. + * + * \return 0 on success, -1 on error. + * + * \note If the bitmap is a CPU or nodeset, the input string must contain physical indexes. + */ +HWLOC_DECLSPEC int hwloc_bitmap_list_sscanf(hwloc_bitmap_t bitmap, const char * __hwloc_restrict string); + +/** \brief Stringify a bitmap in the taskset-specific format. + * + * The taskset program manipulates bitmap strings that contain a single + * (possible very long) hexadecimal number starting with 0x. + * A bitmap containing bits 1, 33, 34, and all from 64 to 95 is printed as "0xffffffff0000000600000002". + * + * Up to \p buflen characters may be written in buffer \p buf. + * + * If \p buflen is 0, \p buf may safely be \c NULL. + * + * \return the number of characters that were actually written if not truncating, + * or that would have been written (not including the ending \c \0). + * \return -1 on error. + * + * \note If the bitmap is a CPU or nodeset, it contains physical indexes. + * This should be clearly indicated when displaying such bitmaps to end users. + * See also \ref faq_convert_indexes + */ +HWLOC_DECLSPEC int hwloc_bitmap_taskset_snprintf(char * __hwloc_restrict buf, size_t buflen, hwloc_const_bitmap_t bitmap); + +/** \brief Stringify a bitmap into a newly allocated taskset-specific string. + * + * The taskset program manipulates bitmap strings that contain a single + * (possible very long) hexadecimal number starting with 0x. + * A bitmap containing bits 1, 33, 34, and all from 64 to 95 is printed as "0xffffffff0000000600000002". + * + * \return the number of characters that were written (not including the ending \c \0). + * \return -1 on error, for instance with \p errno set to \c ENOMEM on failure to allocate the output string. + * + * \note If the bitmap is a CPU or nodeset, it contains physical indexes. + * This should be clearly indicated when displaying such bitmaps to end users. + * See also \ref faq_convert_indexes + */ +HWLOC_DECLSPEC int hwloc_bitmap_taskset_asprintf(char ** strp, hwloc_const_bitmap_t bitmap); + +/** \brief Parse a taskset-specific bitmap string and stores it in bitmap \p bitmap. + * + * The taskset program manipulates bitmap strings that contain a single + * (possible very long) hexadecimal number starting with 0x. + * String "0xffffffff0000000600000002" is parsed as a bitmap containing all bits between 64 and 95, + * and bits 33, 34 and 1. + * + * \return 0 on success, -1 on error. + * + * \note If the bitmap is a CPU or nodeset, the input string must contain physical indexes. + */ +HWLOC_DECLSPEC int hwloc_bitmap_taskset_sscanf(hwloc_bitmap_t bitmap, const char * __hwloc_restrict string); + + +/* + * Building bitmaps. + */ + +/** \brief Empty the bitmap \p bitmap */ +HWLOC_DECLSPEC void hwloc_bitmap_zero(hwloc_bitmap_t bitmap); + +/** \brief Fill bitmap \p bitmap with all possible indexes (even if those objects don't exist or are otherwise unavailable) */ +HWLOC_DECLSPEC void hwloc_bitmap_fill(hwloc_bitmap_t bitmap); + +/** \brief Empty the bitmap \p bitmap and add bit \p id */ +HWLOC_DECLSPEC int hwloc_bitmap_only(hwloc_bitmap_t bitmap, unsigned id); + +/** \brief Fill the bitmap \p and clear the index \p id */ +HWLOC_DECLSPEC int hwloc_bitmap_allbut(hwloc_bitmap_t bitmap, unsigned id); + +/** \brief Setup bitmap \p bitmap from unsigned long \p mask */ +HWLOC_DECLSPEC int hwloc_bitmap_from_ulong(hwloc_bitmap_t bitmap, unsigned long mask); + +/** \brief Setup bitmap \p bitmap from unsigned long \p mask used as \p i -th subset */ +HWLOC_DECLSPEC int hwloc_bitmap_from_ith_ulong(hwloc_bitmap_t bitmap, unsigned i, unsigned long mask); + +/** \brief Setup bitmap \p bitmap from unsigned longs \p masks used as first \p nr subsets */ +HWLOC_DECLSPEC int hwloc_bitmap_from_ulongs(hwloc_bitmap_t bitmap, unsigned nr, const unsigned long *masks); + + +/* + * Modifying bitmaps. + */ + +/** \brief Add index \p id in bitmap \p bitmap */ +HWLOC_DECLSPEC int hwloc_bitmap_set(hwloc_bitmap_t bitmap, unsigned id); + +/** \brief Add indexes from \p begin to \p end in bitmap \p bitmap. + * + * If \p end is \c -1, the range is infinite. + */ +HWLOC_DECLSPEC int hwloc_bitmap_set_range(hwloc_bitmap_t bitmap, unsigned begin, int end); + +/** \brief Replace \p i -th subset of bitmap \p bitmap with unsigned long \p mask */ +HWLOC_DECLSPEC int hwloc_bitmap_set_ith_ulong(hwloc_bitmap_t bitmap, unsigned i, unsigned long mask); + +/** \brief Remove index \p id from bitmap \p bitmap */ +HWLOC_DECLSPEC int hwloc_bitmap_clr(hwloc_bitmap_t bitmap, unsigned id); + +/** \brief Remove indexes from \p begin to \p end in bitmap \p bitmap. + * + * If \p end is \c -1, the range is infinite. + */ +HWLOC_DECLSPEC int hwloc_bitmap_clr_range(hwloc_bitmap_t bitmap, unsigned begin, int end); + +/** \brief Keep a single index among those set in bitmap \p bitmap + * + * May be useful before binding so that the process does not + * have a chance of migrating between multiple processors + * in the original mask. + * Instead of running the task on any PU inside the given CPU set, + * the operating system scheduler will be forced to run it on a single + * of these PUs. + * It avoids a migration overhead and cache-line ping-pongs between PUs. + * + * \note This function is NOT meant to distribute multiple processes + * within a single CPU set. It always return the same single bit when + * called multiple times on the same input set. hwloc_distrib() may + * be used for generating CPU sets to distribute multiple tasks below + * a single multi-PU object. + * + * \note This function cannot be applied to an object set directly. It + * should be applied to a copy (which may be obtained with hwloc_bitmap_dup()). + */ +HWLOC_DECLSPEC int hwloc_bitmap_singlify(hwloc_bitmap_t bitmap); + + +/* + * Consulting bitmaps. + */ + +/** \brief Convert the beginning part of bitmap \p bitmap into unsigned long \p mask */ +HWLOC_DECLSPEC unsigned long hwloc_bitmap_to_ulong(hwloc_const_bitmap_t bitmap) __hwloc_attribute_pure; + +/** \brief Convert the \p i -th subset of bitmap \p bitmap into unsigned long mask */ +HWLOC_DECLSPEC unsigned long hwloc_bitmap_to_ith_ulong(hwloc_const_bitmap_t bitmap, unsigned i) __hwloc_attribute_pure; + +/** \brief Convert the first \p nr subsets of bitmap \p bitmap into the array of \p nr unsigned long \p masks + * + * \p nr may be determined earlier with hwloc_bitmap_nr_ulongs(). + * + * \return 0 + */ +HWLOC_DECLSPEC int hwloc_bitmap_to_ulongs(hwloc_const_bitmap_t bitmap, unsigned nr, unsigned long *masks); + +/** \brief Return the number of unsigned longs required for storing bitmap \p bitmap entirely + * + * This is the number of contiguous unsigned longs from the very first bit of the bitmap + * (even if unset) up to the last set bit. + * This is useful for knowing the \p nr parameter to pass to hwloc_bitmap_to_ulongs() + * (or which calls to hwloc_bitmap_to_ith_ulong() are needed) + * to entirely convert a bitmap into multiple unsigned longs. + * + * When called on the output of hwloc_topology_get_topology_cpuset(), + * the returned number is large enough for all cpusets of the topology. + * + * \return the number of unsigned longs required. + * \return -1 if \p bitmap is infinite. + */ +HWLOC_DECLSPEC int hwloc_bitmap_nr_ulongs(hwloc_const_bitmap_t bitmap) __hwloc_attribute_pure; + +/** \brief Test whether index \p id is part of bitmap \p bitmap. + * + * \return 1 if the bit at index \p id is set in bitmap \p bitmap, 0 otherwise. + */ +HWLOC_DECLSPEC int hwloc_bitmap_isset(hwloc_const_bitmap_t bitmap, unsigned id) __hwloc_attribute_pure; + +/** \brief Test whether bitmap \p bitmap is empty + * + * \return 1 if bitmap is empty, 0 otherwise. + */ +HWLOC_DECLSPEC int hwloc_bitmap_iszero(hwloc_const_bitmap_t bitmap) __hwloc_attribute_pure; + +/** \brief Test whether bitmap \p bitmap is completely full + * + * \return 1 if bitmap is full, 0 otherwise. + * + * \note A full bitmap is always infinitely set. + */ +HWLOC_DECLSPEC int hwloc_bitmap_isfull(hwloc_const_bitmap_t bitmap) __hwloc_attribute_pure; + +/** \brief Compute the first index (least significant bit) in bitmap \p bitmap + * + * \return the first index set in \p bitmap. + * \return -1 if \p bitmap is empty. + */ +HWLOC_DECLSPEC int hwloc_bitmap_first(hwloc_const_bitmap_t bitmap) __hwloc_attribute_pure; + +/** \brief Compute the next index in bitmap \p bitmap which is after index \p prev + * + * \return the first index set in \p bitmap if \p prev is \c -1. + * \return the next index set in \p bitmap if \p prev is not \c -1. + * \return -1 if no index with higher index is set in \p bitmap. + */ +HWLOC_DECLSPEC int hwloc_bitmap_next(hwloc_const_bitmap_t bitmap, int prev) __hwloc_attribute_pure; + +/** \brief Compute the last index (most significant bit) in bitmap \p bitmap + * + * \return the last index set in \p bitmap. + * \return -1 if \p bitmap is empty, or if \p bitmap is infinitely set. + */ +HWLOC_DECLSPEC int hwloc_bitmap_last(hwloc_const_bitmap_t bitmap) __hwloc_attribute_pure; + +/** \brief Compute the "weight" of bitmap \p bitmap (i.e., number of + * indexes that are in the bitmap). + * + * \return the number of indexes that are in the bitmap. + * \return -1 if \p bitmap is infinitely set. + */ +HWLOC_DECLSPEC int hwloc_bitmap_weight(hwloc_const_bitmap_t bitmap) __hwloc_attribute_pure; + +/** \brief Compute the first unset index (least significant bit) in bitmap \p bitmap + * + * \return the first unset index in \p bitmap. + * \return -1 if \p bitmap is full. + */ +HWLOC_DECLSPEC int hwloc_bitmap_first_unset(hwloc_const_bitmap_t bitmap) __hwloc_attribute_pure; + +/** \brief Compute the next unset index in bitmap \p bitmap which is after index \p prev + * + * \return the first index unset in \p bitmap if \p prev is \c -1. + * \return the next index unset in \p bitmap if \p prev is not \c -1. + * \return -1 if no index with higher index is unset in \p bitmap. + */ +HWLOC_DECLSPEC int hwloc_bitmap_next_unset(hwloc_const_bitmap_t bitmap, int prev) __hwloc_attribute_pure; + +/** \brief Compute the last unset index (most significant bit) in bitmap \p bitmap + * + * \return the last index unset in \p bitmap. + * \return -1 if \p bitmap is full, or if \p bitmap is not infinitely set. + */ +HWLOC_DECLSPEC int hwloc_bitmap_last_unset(hwloc_const_bitmap_t bitmap) __hwloc_attribute_pure; + +/** \brief Loop macro iterating on bitmap \p bitmap + * + * The loop must start with hwloc_bitmap_foreach_begin() and end + * with hwloc_bitmap_foreach_end() followed by a terminating ';'. + * + * \p id is the loop variable; it should be an unsigned int. The + * first iteration will set \p id to the lowest index in the bitmap. + * Successive iterations will iterate through, in order, all remaining + * indexes set in the bitmap. To be specific: each iteration will return a + * value for \p id such that hwloc_bitmap_isset(bitmap, id) is true. + * + * The assert prevents the loop from being infinite if the bitmap is infinitely set. + * + * \hideinitializer + */ +#define hwloc_bitmap_foreach_begin(id, bitmap) \ +do { \ + assert(hwloc_bitmap_weight(bitmap) != -1); \ + for (id = hwloc_bitmap_first(bitmap); \ + (unsigned) id != (unsigned) -1; \ + id = hwloc_bitmap_next(bitmap, id)) { + +/** \brief End of loop macro iterating on a bitmap. + * + * Needs a terminating ';'. + * + * \sa hwloc_bitmap_foreach_begin() + * \hideinitializer + */ +#define hwloc_bitmap_foreach_end() \ + } \ +} while (0) + + +/* + * Combining bitmaps. + */ + +/** \brief Or bitmaps \p bitmap1 and \p bitmap2 and store the result in bitmap \p res + * + * \p res can be the same as \p bitmap1 or \p bitmap2 + */ +HWLOC_DECLSPEC int hwloc_bitmap_or (hwloc_bitmap_t res, hwloc_const_bitmap_t bitmap1, hwloc_const_bitmap_t bitmap2); + +/** \brief And bitmaps \p bitmap1 and \p bitmap2 and store the result in bitmap \p res + * + * \p res can be the same as \p bitmap1 or \p bitmap2 + */ +HWLOC_DECLSPEC int hwloc_bitmap_and (hwloc_bitmap_t res, hwloc_const_bitmap_t bitmap1, hwloc_const_bitmap_t bitmap2); + +/** \brief And bitmap \p bitmap1 and the negation of \p bitmap2 and store the result in bitmap \p res + * + * \p res can be the same as \p bitmap1 or \p bitmap2 + */ +HWLOC_DECLSPEC int hwloc_bitmap_andnot (hwloc_bitmap_t res, hwloc_const_bitmap_t bitmap1, hwloc_const_bitmap_t bitmap2); + +/** \brief Xor bitmaps \p bitmap1 and \p bitmap2 and store the result in bitmap \p res + * + * \p res can be the same as \p bitmap1 or \p bitmap2 + */ +HWLOC_DECLSPEC int hwloc_bitmap_xor (hwloc_bitmap_t res, hwloc_const_bitmap_t bitmap1, hwloc_const_bitmap_t bitmap2); + +/** \brief Negate bitmap \p bitmap and store the result in bitmap \p res + * + * \p res can be the same as \p bitmap + */ +HWLOC_DECLSPEC int hwloc_bitmap_not (hwloc_bitmap_t res, hwloc_const_bitmap_t bitmap); + + +/* + * Comparing bitmaps. + */ + +/** \brief Test whether bitmaps \p bitmap1 and \p bitmap2 intersects. + * + * \return 1 if bitmaps intersect, 0 otherwise. + * + * \note The empty bitmap does not intersect any other bitmap. + */ +HWLOC_DECLSPEC int hwloc_bitmap_intersects (hwloc_const_bitmap_t bitmap1, hwloc_const_bitmap_t bitmap2) __hwloc_attribute_pure; + +/** \brief Test whether bitmap \p sub_bitmap is part of bitmap \p super_bitmap. + * + * \return 1 if \p sub_bitmap is included in \p super_bitmap, 0 otherwise. + * + * \note The empty bitmap is considered included in any other bitmap. + */ +HWLOC_DECLSPEC int hwloc_bitmap_isincluded (hwloc_const_bitmap_t sub_bitmap, hwloc_const_bitmap_t super_bitmap) __hwloc_attribute_pure; + +/** \brief Test whether bitmap \p bitmap1 is equal to bitmap \p bitmap2. + * + * \return 1 if bitmaps are equal, 0 otherwise. + */ +HWLOC_DECLSPEC int hwloc_bitmap_isequal (hwloc_const_bitmap_t bitmap1, hwloc_const_bitmap_t bitmap2) __hwloc_attribute_pure; + +/** \brief Compare bitmaps \p bitmap1 and \p bitmap2 using their lowest index. + * + * A bitmap is considered smaller if its least significant bit is smaller. + * The empty bitmap is considered higher than anything (because its least significant bit does not exist). + * + * \return -1 if \p bitmap1 is considered smaller than \p bitmap2. + * \return 1 if \p bitmap1 is considered larger than \p bitmap2. + * + * For instance comparing binary bitmaps 0011 and 0110 returns -1 + * (hence 0011 is considered smaller than 0110) + * because least significant bit of 0011 (0001) is smaller than least significant bit of 0110 (0010). + * Comparing 01001 and 00110 would also return -1 for the same reason. + * + * \return 0 if bitmaps are considered equal, even if they are not strictly equal. + * They just need to have the same least significant bit. + * For instance, comparing binary bitmaps 0010 and 0110 returns 0 because they have the same least significant bit. + */ +HWLOC_DECLSPEC int hwloc_bitmap_compare_first(hwloc_const_bitmap_t bitmap1, hwloc_const_bitmap_t bitmap2) __hwloc_attribute_pure; + +/** \brief Compare bitmaps \p bitmap1 and \p bitmap2 in lexicographic order. + * + * Lexicographic comparison of bitmaps, starting for their highest indexes. + * Compare last indexes first, then second, etc. + * The empty bitmap is considered lower than anything. + * + * \return -1 if \p bitmap1 is considered smaller than \p bitmap2. + * \return 1 if \p bitmap1 is considered larger than \p bitmap2. + * \return 0 if bitmaps are equal (contrary to hwloc_bitmap_compare_first()). + * + * For instance comparing binary bitmaps 0011 and 0110 returns -1 + * (hence 0011 is considered smaller than 0110). + * Comparing 00101 and 01010 returns -1 too. + * + * \note This is different from the non-existing hwloc_bitmap_compare_last() + * which would only compare the highest index of each bitmap. + */ +HWLOC_DECLSPEC int hwloc_bitmap_compare(hwloc_const_bitmap_t bitmap1, hwloc_const_bitmap_t bitmap2) __hwloc_attribute_pure; + +/** @} */ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* HWLOC_BITMAP_H */ diff --git a/src/deps/hwloc/include/hwloc/cpukinds.h b/src/deps/hwloc/include/hwloc/cpukinds.h new file mode 100644 index 000000000..b50050ab2 --- /dev/null +++ b/src/deps/hwloc/include/hwloc/cpukinds.h @@ -0,0 +1,194 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * Copyright © 2020-2021 Inria. All rights reserved. + * See COPYING in top-level directory. + */ + +/** \file + * \brief Kinds of CPU cores. + */ + +#ifndef HWLOC_CPUKINDS_H +#define HWLOC_CPUKINDS_H + +#include "hwloc.h" + +#ifdef __cplusplus +extern "C" { +#elif 0 +} +#endif + +/** \defgroup hwlocality_cpukinds Kinds of CPU cores + * + * Platforms with heterogeneous CPUs may have some cores with + * different features or frequencies. + * This API exposes identical PUs in sets called CPU kinds. + * Each PU of the topology may only be in a single kind. + * + * The number of kinds may be obtained with hwloc_cpukinds_get_nr(). + * If the platform is homogeneous, there may be a single kind + * with all PUs. + * If the platform or operating system does not expose any + * information about CPU cores, there may be no kind at all. + * + * The index of the kind that describes a given CPU set + * (if any, and not partially) + * may be obtained with hwloc_cpukinds_get_by_cpuset(). + * + * From the index of a kind, it is possible to retrieve information + * with hwloc_cpukinds_get_info(): + * an abstracted efficiency value, + * and an array of info attributes + * (for instance the "CoreType" and "FrequencyMaxMHz", + * see \ref topoattrs_cpukinds). + * + * A higher efficiency value means greater intrinsic performance + * (and possibly less performance/power efficiency). + * Kinds with lower efficiency values are ranked first: + * Passing 0 as \p kind_index to hwloc_cpukinds_get_info() will + * return information about the CPU kind with lower performance + * but higher energy-efficiency. + * Higher \p kind_index values would rather return information + * about power-hungry high-performance cores. + * + * When available, efficiency values are gathered from the operating system. + * If so, \p cpukind_efficiency is set in the struct hwloc_topology_discovery_support array. + * This is currently available on Windows 10, Mac OS X (Darwin), + * and on some Linux platforms where core "capacity" is exposed in sysfs. + * + * If the operating system does not expose core efficiencies natively, + * hwloc tries to compute efficiencies by comparing CPU kinds using + * frequencies (on ARM), or core types and frequencies (on other architectures). + * The environment variable HWLOC_CPUKINDS_RANKING may be used + * to change this heuristics, see \ref envvar_heuristics. + * + * If hwloc fails to rank any kind, for instance because the operating + * system does not expose efficiencies and core frequencies, + * all kinds will have an unknown efficiency (\c -1), + * and they are not indexed/ordered in any specific way. + * + * @{ + */ + +/** \brief Get the number of different kinds of CPU cores in the topology. + * + * \p flags must be \c 0 for now. + * + * \return The number of CPU kinds (positive integer) on success. + * \return \c 0 if no information about kinds was found. + * \return \c -1 with \p errno set to \c EINVAL if \p flags is invalid. + */ +HWLOC_DECLSPEC int +hwloc_cpukinds_get_nr(hwloc_topology_t topology, + unsigned long flags); + +/** \brief Get the index of the CPU kind that contains CPUs listed in \p cpuset. + * + * \p flags must be \c 0 for now. + * + * \return The index of the CPU kind (positive integer or 0) on success. + * \return \c -1 with \p errno set to \c EXDEV if \p cpuset is + * only partially included in the some kind. + * \return \c -1 with \p errno set to \c ENOENT if \p cpuset is + * not included in any kind, even partially. + * \return \c -1 with \p errno set to \c EINVAL if parameters are invalid. + */ +HWLOC_DECLSPEC int +hwloc_cpukinds_get_by_cpuset(hwloc_topology_t topology, + hwloc_const_bitmap_t cpuset, + unsigned long flags); + +/** \brief Get the CPU set and infos about a CPU kind in the topology. + * + * \p kind_index identifies one kind of CPU between 0 and the number + * of kinds returned by hwloc_cpukinds_get_nr() minus 1. + * + * If not \c NULL, the bitmap \p cpuset will be filled with + * the set of PUs of this kind. + * + * The integer pointed by \p efficiency, if not \c NULL will, be filled + * with the ranking of this kind of CPU in term of efficiency (see above). + * It ranges from \c 0 to the number of kinds + * (as reported by hwloc_cpukinds_get_nr()) minus 1. + * + * Kinds with lower efficiency are reported first. + * + * If there is a single kind in the topology, its efficiency \c 0. + * If the efficiency of some kinds of cores is unknown, + * the efficiency of all kinds is set to \c -1, + * and kinds are reported in no specific order. + * + * The array of info attributes (for instance the "CoreType", + * "FrequencyMaxMHz" or "FrequencyBaseMHz", see \ref topoattrs_cpukinds) + * and its length are returned in \p infos or \p nr_infos. + * The array belongs to the topology, it should not be freed or modified. + * + * If \p nr_infos or \p infos is \c NULL, no info is returned. + * + * \p flags must be \c 0 for now. + * + * \return \c 0 on success. + * \return \c -1 with \p errno set to \c ENOENT if \p kind_index does not match any CPU kind. + * \return \c -1 with \p errno set to \c EINVAL if parameters are invalid. + */ +HWLOC_DECLSPEC int +hwloc_cpukinds_get_info(hwloc_topology_t topology, + unsigned kind_index, + hwloc_bitmap_t cpuset, + int *efficiency, + unsigned *nr_infos, struct hwloc_info_s **infos, + unsigned long flags); + +/** \brief Register a kind of CPU in the topology. + * + * Mark the PUs listed in \p cpuset as being of the same kind + * with respect to the given attributes. + * + * \p forced_efficiency should be \c -1 if unknown. + * Otherwise it is an abstracted efficiency value to enforce + * the ranking of all kinds if all of them have valid (and + * different) efficiencies. + * + * The array \p infos of size \p nr_infos may be used to provide + * info names and values describing this kind of PUs. + * + * \p flags must be \c 0 for now. + * + * Parameters \p cpuset and \p infos will be duplicated internally, + * the caller is responsible for freeing them. + * + * If \p cpuset overlaps with some existing kinds, those might get + * modified or split. For instance if existing kind A contains + * PUs 0 and 1, and one registers another kind for PU 1 and 2, + * there will be 3 resulting kinds: + * existing kind A is restricted to only PU 0; + * new kind B contains only PU 1 and combines information from A + * and from the newly-registered kind; + * new kind C contains only PU 2 and only gets information from + * the newly-registered kind. + * + * \note The efficiency \p forced_efficiency provided to this function + * may be different from the one reported later by hwloc_cpukinds_get_info() + * because hwloc will scale efficiency values down to + * between 0 and the number of kinds minus 1. + * + * \return \c 0 on success. + * \return \c -1 with \p errno set to \c EINVAL if some parameters are invalid, + * for instance if \p cpuset is \c NULL or empty. + */ +HWLOC_DECLSPEC int +hwloc_cpukinds_register(hwloc_topology_t topology, + hwloc_bitmap_t cpuset, + int forced_efficiency, + unsigned nr_infos, struct hwloc_info_s *infos, + unsigned long flags); + +/** @} */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* HWLOC_CPUKINDS_H */ diff --git a/src/deps/hwloc/include/hwloc/cuda.h b/src/deps/hwloc/include/hwloc/cuda.h new file mode 100644 index 000000000..db9778e58 --- /dev/null +++ b/src/deps/hwloc/include/hwloc/cuda.h @@ -0,0 +1,227 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * Copyright © 2010-2023 Inria. All rights reserved. + * Copyright © 2010-2011 Université Bordeaux + * Copyright © 2011 Cisco Systems, Inc. All rights reserved. + * See COPYING in top-level directory. + */ + +/** \file + * \brief Macros to help interaction between hwloc and the CUDA Driver API. + * + * Applications that use both hwloc and the CUDA Driver API may want to + * include this file so as to get topology information for CUDA devices. + * + */ + +#ifndef HWLOC_CUDA_H +#define HWLOC_CUDA_H + +#include "hwloc.h" +#include "hwloc/autogen/config.h" +#include "hwloc/helper.h" +#ifdef HWLOC_LINUX_SYS +#include "hwloc/linux.h" +#endif + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** \defgroup hwlocality_cuda Interoperability with the CUDA Driver API + * + * This interface offers ways to retrieve topology information about + * CUDA devices when using the CUDA Driver API. + * + * @{ + */ + +/** \brief Return the domain, bus and device IDs of the CUDA device \p cudevice. + * + * Device \p cudevice must match the local machine. + * + * \return 0 on success. + * \return -1 on error, for instance if device information could not be found. + */ +static __hwloc_inline int +hwloc_cuda_get_device_pci_ids(hwloc_topology_t topology __hwloc_attribute_unused, + CUdevice cudevice, int *domain, int *bus, int *dev) +{ + CUresult cres; + +#if CUDA_VERSION >= 4000 + cres = cuDeviceGetAttribute(domain, CU_DEVICE_ATTRIBUTE_PCI_DOMAIN_ID, cudevice); + if (cres != CUDA_SUCCESS) { + errno = ENOSYS; + return -1; + } +#else + *domain = 0; +#endif + cres = cuDeviceGetAttribute(bus, CU_DEVICE_ATTRIBUTE_PCI_BUS_ID, cudevice); + if (cres != CUDA_SUCCESS) { + errno = ENOSYS; + return -1; + } + cres = cuDeviceGetAttribute(dev, CU_DEVICE_ATTRIBUTE_PCI_DEVICE_ID, cudevice); + if (cres != CUDA_SUCCESS) { + errno = ENOSYS; + return -1; + } + + return 0; +} + +/** \brief Get the CPU set of processors that are physically + * close to device \p cudevice. + * + * Store in \p set the CPU-set describing the locality of the CUDA device \p cudevice. + * + * Topology \p topology and device \p cudevice must match the local machine. + * I/O devices detection and the CUDA component are not needed in the topology. + * + * The function only returns the locality of the device. + * If more information about the device is needed, OS objects should + * be used instead, see hwloc_cuda_get_device_osdev() + * and hwloc_cuda_get_device_osdev_by_index(). + * + * This function is currently only implemented in a meaningful way for + * Linux; other systems will simply get a full cpuset. + * + * \return 0 on success. + * \return -1 on error, for instance if device information could not be found. + */ +static __hwloc_inline int +hwloc_cuda_get_device_cpuset(hwloc_topology_t topology __hwloc_attribute_unused, + CUdevice cudevice, hwloc_cpuset_t set) +{ +#ifdef HWLOC_LINUX_SYS + /* If we're on Linux, use the sysfs mechanism to get the local cpus */ +#define HWLOC_CUDA_DEVICE_SYSFS_PATH_MAX 128 + char path[HWLOC_CUDA_DEVICE_SYSFS_PATH_MAX]; + int domainid, busid, deviceid; + + if (hwloc_cuda_get_device_pci_ids(topology, cudevice, &domainid, &busid, &deviceid)) + return -1; + + if (!hwloc_topology_is_thissystem(topology)) { + errno = EINVAL; + return -1; + } + + sprintf(path, "/sys/bus/pci/devices/%04x:%02x:%02x.0/local_cpus", domainid, busid, deviceid); + if (hwloc_linux_read_path_as_cpumask(path, set) < 0 + || hwloc_bitmap_iszero(set)) + hwloc_bitmap_copy(set, hwloc_topology_get_complete_cpuset(topology)); +#else + /* Non-Linux systems simply get a full cpuset */ + hwloc_bitmap_copy(set, hwloc_topology_get_complete_cpuset(topology)); +#endif + return 0; +} + +/** \brief Get the hwloc PCI device object corresponding to the + * CUDA device \p cudevice. + * + * \return The hwloc PCI device object describing the CUDA device \p cudevice. + * \return \c NULL if none could be found. + * + * Topology \p topology and device \p cudevice must match the local machine. + * I/O devices detection must be enabled in topology \p topology. + * The CUDA component is not needed in the topology. + */ +static __hwloc_inline hwloc_obj_t +hwloc_cuda_get_device_pcidev(hwloc_topology_t topology, CUdevice cudevice) +{ + int domain, bus, dev; + + if (hwloc_cuda_get_device_pci_ids(topology, cudevice, &domain, &bus, &dev)) + return NULL; + + return hwloc_get_pcidev_by_busid(topology, domain, bus, dev, 0); +} + +/** \brief Get the hwloc OS device object corresponding to CUDA device \p cudevice. + * + * \return The hwloc OS device object that describes the given CUDA device \p cudevice. + * \return \c NULL if none could be found. + * + * Topology \p topology and device \p cudevice must match the local machine. + * I/O devices detection and the CUDA component must be enabled in the topology. + * If not, the locality of the object may still be found using + * hwloc_cuda_get_device_cpuset(). + * + * \note This function cannot work if PCI devices are filtered out. + * + * \note The corresponding hwloc PCI device may be found by looking + * at the result parent pointer (unless PCI devices are filtered out). + */ +static __hwloc_inline hwloc_obj_t +hwloc_cuda_get_device_osdev(hwloc_topology_t topology, CUdevice cudevice) +{ + hwloc_obj_t osdev = NULL; + int domain, bus, dev; + + if (hwloc_cuda_get_device_pci_ids(topology, cudevice, &domain, &bus, &dev)) + return NULL; + + osdev = NULL; + while ((osdev = hwloc_get_next_osdev(topology, osdev)) != NULL) { + hwloc_obj_t pcidev = osdev->parent; + if (strncmp(osdev->name, "cuda", 4)) + continue; + if (pcidev + && pcidev->type == HWLOC_OBJ_PCI_DEVICE + && (int) pcidev->attr->pcidev.domain == domain + && (int) pcidev->attr->pcidev.bus == bus + && (int) pcidev->attr->pcidev.dev == dev + && pcidev->attr->pcidev.func == 0) + return osdev; + /* if PCI are filtered out, we need a info attr to match on */ + } + + return NULL; +} + +/** \brief Get the hwloc OS device object corresponding to the + * CUDA device whose index is \p idx. + * + * \return The hwloc OS device object describing the CUDA device whose index is \p idx. + * \return \c NULL if none could be found. + * + * The topology \p topology does not necessarily have to match the current + * machine. For instance the topology may be an XML import of a remote host. + * I/O devices detection and the CUDA component must be enabled in the topology. + * + * \note The corresponding PCI device object can be obtained by looking + * at the OS device parent object (unless PCI devices are filtered out). + * + * \note This function is identical to hwloc_cudart_get_device_osdev_by_index(). + */ +static __hwloc_inline hwloc_obj_t +hwloc_cuda_get_device_osdev_by_index(hwloc_topology_t topology, unsigned idx) +{ + hwloc_obj_t osdev = NULL; + while ((osdev = hwloc_get_next_osdev(topology, osdev)) != NULL) { + if (HWLOC_OBJ_OSDEV_COPROC == osdev->attr->osdev.type + && osdev->name + && !strncmp("cuda", osdev->name, 4) + && atoi(osdev->name + 4) == (int) idx) + return osdev; + } + return NULL; +} + +/** @} */ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* HWLOC_CUDA_H */ diff --git a/src/deps/hwloc/include/hwloc/cudart.h b/src/deps/hwloc/include/hwloc/cudart.h new file mode 100644 index 000000000..25a92a098 --- /dev/null +++ b/src/deps/hwloc/include/hwloc/cudart.h @@ -0,0 +1,184 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * Copyright © 2010-2023 Inria. All rights reserved. + * Copyright © 2010-2011 Université Bordeaux + * Copyright © 2011 Cisco Systems, Inc. All rights reserved. + * See COPYING in top-level directory. + */ + +/** \file + * \brief Macros to help interaction between hwloc and the CUDA Runtime API. + * + * Applications that use both hwloc and the CUDA Runtime API may want to + * include this file so as to get topology information for CUDA devices. + * + */ + +#ifndef HWLOC_CUDART_H +#define HWLOC_CUDART_H + +#include "hwloc.h" +#include "hwloc/autogen/config.h" +#include "hwloc/helper.h" +#ifdef HWLOC_LINUX_SYS +#include "hwloc/linux.h" +#endif + +#include /* for CUDA_VERSION */ +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** \defgroup hwlocality_cudart Interoperability with the CUDA Runtime API + * + * This interface offers ways to retrieve topology information about + * CUDA devices when using the CUDA Runtime API. + * + * @{ + */ + +/** \brief Return the domain, bus and device IDs of the CUDA device whose index is \p idx. + * + * Device index \p idx must match the local machine. + * + * \return 0 on success. + * \return -1 on error, for instance if device information could not be found. + */ +static __hwloc_inline int +hwloc_cudart_get_device_pci_ids(hwloc_topology_t topology __hwloc_attribute_unused, + int idx, int *domain, int *bus, int *dev) +{ + cudaError_t cerr; + struct cudaDeviceProp prop; + + cerr = cudaGetDeviceProperties(&prop, idx); + if (cerr) { + errno = ENOSYS; + return -1; + } + +#if CUDA_VERSION >= 4000 + *domain = prop.pciDomainID; +#else + *domain = 0; +#endif + + *bus = prop.pciBusID; + *dev = prop.pciDeviceID; + + return 0; +} + +/** \brief Get the CPU set of processors that are physically + * close to device \p idx. + * + * Store in \p set the CPU-set describing the locality of the CUDA device + * whose index is \p idx. + * + * Topology \p topology and device \p idx must match the local machine. + * I/O devices detection and the CUDA component are not needed in the topology. + * + * The function only returns the locality of the device. + * If more information about the device is needed, OS objects should + * be used instead, see hwloc_cudart_get_device_osdev_by_index(). + * + * This function is currently only implemented in a meaningful way for + * Linux; other systems will simply get a full cpuset. + * + * \return 0 on success. + * \return -1 on error, for instance if device information could not be found. + */ +static __hwloc_inline int +hwloc_cudart_get_device_cpuset(hwloc_topology_t topology __hwloc_attribute_unused, + int idx, hwloc_cpuset_t set) +{ +#ifdef HWLOC_LINUX_SYS + /* If we're on Linux, use the sysfs mechanism to get the local cpus */ +#define HWLOC_CUDART_DEVICE_SYSFS_PATH_MAX 128 + char path[HWLOC_CUDART_DEVICE_SYSFS_PATH_MAX]; + int domain, bus, dev; + + if (hwloc_cudart_get_device_pci_ids(topology, idx, &domain, &bus, &dev)) + return -1; + + if (!hwloc_topology_is_thissystem(topology)) { + errno = EINVAL; + return -1; + } + + sprintf(path, "/sys/bus/pci/devices/%04x:%02x:%02x.0/local_cpus", (unsigned) domain, (unsigned) bus, (unsigned) dev); + if (hwloc_linux_read_path_as_cpumask(path, set) < 0 + || hwloc_bitmap_iszero(set)) + hwloc_bitmap_copy(set, hwloc_topology_get_complete_cpuset(topology)); +#else + /* Non-Linux systems simply get a full cpuset */ + hwloc_bitmap_copy(set, hwloc_topology_get_complete_cpuset(topology)); +#endif + return 0; +} + +/** \brief Get the hwloc PCI device object corresponding to the + * CUDA device whose index is \p idx. + * + * \return The hwloc PCI device object describing the CUDA device whose index is \p idx. + * \return \c NULL if none could be found. + * + * Topology \p topology and device \p idx must match the local machine. + * I/O devices detection must be enabled in topology \p topology. + * The CUDA component is not needed in the topology. + */ +static __hwloc_inline hwloc_obj_t +hwloc_cudart_get_device_pcidev(hwloc_topology_t topology, int idx) +{ + int domain, bus, dev; + + if (hwloc_cudart_get_device_pci_ids(topology, idx, &domain, &bus, &dev)) + return NULL; + + return hwloc_get_pcidev_by_busid(topology, domain, bus, dev, 0); +} + +/** \brief Get the hwloc OS device object corresponding to the + * CUDA device whose index is \p idx. + * + * \return The hwloc OS device object describing the CUDA device whose index is \p idx. + * \return \c NULL if none could be found. + * + * The topology \p topology does not necessarily have to match the current + * machine. For instance the topology may be an XML import of a remote host. + * I/O devices detection and the CUDA component must be enabled in the topology. + * If not, the locality of the object may still be found using + * hwloc_cudart_get_device_cpuset(). + * + * \note The corresponding PCI device object can be obtained by looking + * at the OS device parent object (unless PCI devices are filtered out). + * + * \note This function is identical to hwloc_cuda_get_device_osdev_by_index(). + */ +static __hwloc_inline hwloc_obj_t +hwloc_cudart_get_device_osdev_by_index(hwloc_topology_t topology, unsigned idx) +{ + hwloc_obj_t osdev = NULL; + while ((osdev = hwloc_get_next_osdev(topology, osdev)) != NULL) { + if (HWLOC_OBJ_OSDEV_COPROC == osdev->attr->osdev.type + && osdev->name + && !strncmp("cuda", osdev->name, 4) + && atoi(osdev->name + 4) == (int) idx) + return osdev; + } + return NULL; +} + +/** @} */ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* HWLOC_CUDART_H */ diff --git a/src/deps/hwloc/include/hwloc/deprecated.h b/src/deps/hwloc/include/hwloc/deprecated.h new file mode 100644 index 000000000..aef2716ae --- /dev/null +++ b/src/deps/hwloc/include/hwloc/deprecated.h @@ -0,0 +1,218 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * Copyright © 2009 CNRS + * Copyright © 2009-2022 Inria. All rights reserved. + * Copyright © 2009-2012 Université Bordeaux + * Copyright © 2009-2010 Cisco Systems, Inc. All rights reserved. + * See COPYING in top-level directory. + */ + +/** + * This file contains the inline code of functions declared in hwloc.h + */ + +#ifndef HWLOC_DEPRECATED_H +#define HWLOC_DEPRECATED_H + +#ifndef HWLOC_H +#error Please include the main hwloc.h instead +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* backward compat with v2.0 before WHOLE_SYSTEM renaming */ +#define HWLOC_TOPOLOGY_FLAG_WHOLE_SYSTEM HWLOC_TOPOLOGY_FLAG_INCLUDE_DISALLOWED +/* backward compat with v1.11 before System removal */ +#define HWLOC_OBJ_SYSTEM HWLOC_OBJ_MACHINE +/* backward compat with v1.10 before Socket->Package renaming */ +#define HWLOC_OBJ_SOCKET HWLOC_OBJ_PACKAGE +/* backward compat with v1.10 before Node->NUMANode clarification */ +#define HWLOC_OBJ_NODE HWLOC_OBJ_NUMANODE + +/** \brief Add a distances structure. + * + * Superseded by hwloc_distances_add_create()+hwloc_distances_add_values()+hwloc_distances_add_commit() + * in v2.5. + */ +HWLOC_DECLSPEC int hwloc_distances_add(hwloc_topology_t topology, + unsigned nbobjs, hwloc_obj_t *objs, hwloc_uint64_t *values, + unsigned long kind, unsigned long flags) __hwloc_attribute_deprecated; + +/** \brief Insert a misc object by parent. + * + * Identical to hwloc_topology_insert_misc_object(). + */ +static __hwloc_inline hwloc_obj_t +hwloc_topology_insert_misc_object_by_parent(hwloc_topology_t topology, hwloc_obj_t parent, const char *name) __hwloc_attribute_deprecated; +static __hwloc_inline hwloc_obj_t +hwloc_topology_insert_misc_object_by_parent(hwloc_topology_t topology, hwloc_obj_t parent, const char *name) +{ + return hwloc_topology_insert_misc_object(topology, parent, name); +} + +/** \brief Stringify the cpuset containing a set of objects. + * + * If \p size is 0, \p string may safely be \c NULL. + * + * \return the number of characters that were actually written if not truncating, + * or that would have been written (not including the ending \\0). + */ +static __hwloc_inline int +hwloc_obj_cpuset_snprintf(char *str, size_t size, size_t nobj, struct hwloc_obj * const *objs) __hwloc_attribute_deprecated; +static __hwloc_inline int +hwloc_obj_cpuset_snprintf(char *str, size_t size, size_t nobj, struct hwloc_obj * const *objs) +{ + hwloc_bitmap_t set = hwloc_bitmap_alloc(); + int res; + unsigned i; + + hwloc_bitmap_zero(set); + for(i=0; icpuset) + hwloc_bitmap_or(set, set, objs[i]->cpuset); + + res = hwloc_bitmap_snprintf(str, size, set); + hwloc_bitmap_free(set); + return res; +} + +/** \brief Convert a type string into a type and some attributes. + * + * Deprecated by hwloc_type_sscanf() + */ +static __hwloc_inline int +hwloc_obj_type_sscanf(const char *string, hwloc_obj_type_t *typep, int *depthattrp, void *typeattrp, size_t typeattrsize) __hwloc_attribute_deprecated; +static __hwloc_inline int +hwloc_obj_type_sscanf(const char *string, hwloc_obj_type_t *typep, int *depthattrp, void *typeattrp, size_t typeattrsize) +{ + union hwloc_obj_attr_u attr; + int err = hwloc_type_sscanf(string, typep, &attr, sizeof(attr)); + if (err < 0) + return err; + if (hwloc_obj_type_is_cache(*typep)) { + if (depthattrp) + *depthattrp = (int) attr.cache.depth; + if (typeattrp && typeattrsize >= sizeof(hwloc_obj_cache_type_t)) + memcpy(typeattrp, &attr.cache.type, sizeof(hwloc_obj_cache_type_t)); + } else if (*typep == HWLOC_OBJ_GROUP) { + if (depthattrp) + *depthattrp = (int) attr.group.depth; + } + return 0; +} + +/** \brief Set the default memory binding policy of the current + * process or thread to prefer the NUMA node(s) specified by physical \p nodeset + */ +static __hwloc_inline int +hwloc_set_membind_nodeset(hwloc_topology_t topology, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags) __hwloc_attribute_deprecated; +static __hwloc_inline int +hwloc_set_membind_nodeset(hwloc_topology_t topology, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags) +{ + return hwloc_set_membind(topology, nodeset, policy, flags | HWLOC_MEMBIND_BYNODESET); +} + +/** \brief Query the default memory binding policy and physical locality of the + * current process or thread. + */ +static __hwloc_inline int +hwloc_get_membind_nodeset(hwloc_topology_t topology, hwloc_nodeset_t nodeset, hwloc_membind_policy_t * policy, int flags) __hwloc_attribute_deprecated; +static __hwloc_inline int +hwloc_get_membind_nodeset(hwloc_topology_t topology, hwloc_nodeset_t nodeset, hwloc_membind_policy_t * policy, int flags) +{ + return hwloc_get_membind(topology, nodeset, policy, flags | HWLOC_MEMBIND_BYNODESET); +} + +/** \brief Set the default memory binding policy of the specified + * process to prefer the NUMA node(s) specified by physical \p nodeset + */ +static __hwloc_inline int +hwloc_set_proc_membind_nodeset(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags) __hwloc_attribute_deprecated; +static __hwloc_inline int +hwloc_set_proc_membind_nodeset(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags) +{ + return hwloc_set_proc_membind(topology, pid, nodeset, policy, flags | HWLOC_MEMBIND_BYNODESET); +} + +/** \brief Query the default memory binding policy and physical locality of the + * specified process. + */ +static __hwloc_inline int +hwloc_get_proc_membind_nodeset(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_nodeset_t nodeset, hwloc_membind_policy_t * policy, int flags) __hwloc_attribute_deprecated; +static __hwloc_inline int +hwloc_get_proc_membind_nodeset(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_nodeset_t nodeset, hwloc_membind_policy_t * policy, int flags) +{ + return hwloc_get_proc_membind(topology, pid, nodeset, policy, flags | HWLOC_MEMBIND_BYNODESET); +} + +/** \brief Bind the already-allocated memory identified by (addr, len) + * to the NUMA node(s) in physical \p nodeset. + */ +static __hwloc_inline int +hwloc_set_area_membind_nodeset(hwloc_topology_t topology, const void *addr, size_t len, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags) __hwloc_attribute_deprecated; +static __hwloc_inline int +hwloc_set_area_membind_nodeset(hwloc_topology_t topology, const void *addr, size_t len, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags) +{ + return hwloc_set_area_membind(topology, addr, len, nodeset, policy, flags | HWLOC_MEMBIND_BYNODESET); +} + +/** \brief Query the physical NUMA node(s) and binding policy of the memory + * identified by (\p addr, \p len ). + */ +static __hwloc_inline int +hwloc_get_area_membind_nodeset(hwloc_topology_t topology, const void *addr, size_t len, hwloc_nodeset_t nodeset, hwloc_membind_policy_t * policy, int flags) __hwloc_attribute_deprecated; +static __hwloc_inline int +hwloc_get_area_membind_nodeset(hwloc_topology_t topology, const void *addr, size_t len, hwloc_nodeset_t nodeset, hwloc_membind_policy_t * policy, int flags) +{ + return hwloc_get_area_membind(topology, addr, len, nodeset, policy, flags | HWLOC_MEMBIND_BYNODESET); +} + +/** \brief Allocate some memory on the given physical nodeset \p nodeset + */ +static __hwloc_inline void * +hwloc_alloc_membind_nodeset(hwloc_topology_t topology, size_t len, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags) __hwloc_attribute_malloc __hwloc_attribute_deprecated; +static __hwloc_inline void * +hwloc_alloc_membind_nodeset(hwloc_topology_t topology, size_t len, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags) +{ + return hwloc_alloc_membind(topology, len, nodeset, policy, flags | HWLOC_MEMBIND_BYNODESET); +} + +/** \brief Allocate some memory on the given nodeset \p nodeset. + */ +static __hwloc_inline void * +hwloc_alloc_membind_policy_nodeset(hwloc_topology_t topology, size_t len, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags) __hwloc_attribute_malloc __hwloc_attribute_deprecated; +static __hwloc_inline void * +hwloc_alloc_membind_policy_nodeset(hwloc_topology_t topology, size_t len, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags) +{ + return hwloc_alloc_membind_policy(topology, len, nodeset, policy, flags | HWLOC_MEMBIND_BYNODESET); +} + +/** \brief Convert a CPU set into a NUMA node set and handle non-NUMA cases + */ +static __hwloc_inline void +hwloc_cpuset_to_nodeset_strict(hwloc_topology_t topology, hwloc_const_cpuset_t _cpuset, hwloc_nodeset_t nodeset) __hwloc_attribute_deprecated; +static __hwloc_inline void +hwloc_cpuset_to_nodeset_strict(hwloc_topology_t topology, hwloc_const_cpuset_t _cpuset, hwloc_nodeset_t nodeset) +{ + hwloc_cpuset_to_nodeset(topology, _cpuset, nodeset); +} + +/** \brief Convert a NUMA node set into a CPU set and handle non-NUMA cases + */ +static __hwloc_inline void +hwloc_cpuset_from_nodeset_strict(hwloc_topology_t topology, hwloc_cpuset_t _cpuset, hwloc_const_nodeset_t nodeset) __hwloc_attribute_deprecated; +static __hwloc_inline void +hwloc_cpuset_from_nodeset_strict(hwloc_topology_t topology, hwloc_cpuset_t _cpuset, hwloc_const_nodeset_t nodeset) +{ + hwloc_cpuset_from_nodeset(topology, _cpuset, nodeset); +} + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* HWLOC_DEPRECATED_H */ diff --git a/src/deps/hwloc/include/hwloc/diff.h b/src/deps/hwloc/include/hwloc/diff.h new file mode 100644 index 000000000..d13025863 --- /dev/null +++ b/src/deps/hwloc/include/hwloc/diff.h @@ -0,0 +1,305 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * Copyright © 2013-2024 Inria. All rights reserved. + * See COPYING in top-level directory. + */ + +/** \file + * \brief Topology differences. + */ + +#ifndef HWLOC_DIFF_H +#define HWLOC_DIFF_H + +#ifndef HWLOC_H +#error Please include the main hwloc.h instead +#endif + + +#ifdef __cplusplus +extern "C" { +#elif 0 +} +#endif + + +/** \defgroup hwlocality_diff Topology differences + * + * Applications that manipulate many similar topologies, for instance + * one for each node of a homogeneous cluster, may want to compress + * topologies to reduce the memory footprint. + * + * This file offers a way to manipulate the difference between topologies + * and export/import it to/from XML. + * Compression may therefore be achieved by storing one topology + * entirely while the others are only described by their differences + * with the former. + * The actual topology can be reconstructed when actually needed by + * applying the precomputed difference to the reference topology. + * + * This interface targets very similar nodes. + * Only very simple differences between topologies are actually + * supported, for instance a change in the memory size, the name + * of the object, or some info attribute. + * More complex differences such as adding or removing objects cannot + * be represented in the difference structures and therefore return + * errors. + * Differences between object sets or topology-wide allowed sets, + * cannot be represented either. + * + * It means that there is no need to apply the difference when + * looking at the tree organization (how many levels, how many + * objects per level, what kind of objects, CPU and node sets, etc) + * and when binding to objects. + * However the difference must be applied when looking at object + * attributes such as the name, the memory size or info attributes. + * + * @{ + */ + + +/** \brief Type of one object attribute difference. + */ +typedef enum hwloc_topology_diff_obj_attr_type_e { + /** \brief The object local memory is modified. + * The union is a hwloc_topology_diff_obj_attr_u::hwloc_topology_diff_obj_attr_uint64_s + * (and the index field is ignored). + */ + HWLOC_TOPOLOGY_DIFF_OBJ_ATTR_SIZE, + + /** \brief The object name is modified. + * The union is a hwloc_topology_diff_obj_attr_u::hwloc_topology_diff_obj_attr_string_s + * (and the name field is ignored). + */ + + HWLOC_TOPOLOGY_DIFF_OBJ_ATTR_NAME, + /** \brief the value of an info attribute is modified. + * The union is a hwloc_topology_diff_obj_attr_u::hwloc_topology_diff_obj_attr_string_s. + */ + HWLOC_TOPOLOGY_DIFF_OBJ_ATTR_INFO +} hwloc_topology_diff_obj_attr_type_t; + +/** \brief One object attribute difference. + */ +union hwloc_topology_diff_obj_attr_u { + struct hwloc_topology_diff_obj_attr_generic_s { + /* each part of the union must start with these */ + hwloc_topology_diff_obj_attr_type_t type; + } generic; + + /** \brief Integer attribute modification with an optional index. */ + struct hwloc_topology_diff_obj_attr_uint64_s { + /* used for storing integer attributes */ + hwloc_topology_diff_obj_attr_type_t type; + hwloc_uint64_t index; /* not used for SIZE */ + hwloc_uint64_t oldvalue; + hwloc_uint64_t newvalue; + } uint64; + + /** \brief String attribute modification with an optional name */ + struct hwloc_topology_diff_obj_attr_string_s { + /* used for storing name and info pairs */ + hwloc_topology_diff_obj_attr_type_t type; + char *name; /* not used for NAME */ + char *oldvalue; + char *newvalue; + } string; +}; + + +/** \brief Type of one element of a difference list. + */ +typedef enum hwloc_topology_diff_type_e { + /** \brief An object attribute was changed. + * The union is a hwloc_topology_diff_u::hwloc_topology_diff_obj_attr_s. + */ + HWLOC_TOPOLOGY_DIFF_OBJ_ATTR, + + /** \brief The difference is too complex, + * it cannot be represented. The difference below + * this object has not been checked. + * hwloc_topology_diff_build() will return 1. + * + * The union is a hwloc_topology_diff_u::hwloc_topology_diff_too_complex_s. + */ + HWLOC_TOPOLOGY_DIFF_TOO_COMPLEX +} hwloc_topology_diff_type_t; + +/** \brief One element of a difference list between two topologies. + */ +typedef union hwloc_topology_diff_u { + struct hwloc_topology_diff_generic_s { + /* each part of the union must start with these */ + hwloc_topology_diff_type_t type; + union hwloc_topology_diff_u * next; /* pointer to the next element of the list, or NULL */ + } generic; + + /* A difference in an object attribute. */ + struct hwloc_topology_diff_obj_attr_s { + hwloc_topology_diff_type_t type; /* must be ::HWLOC_TOPOLOGY_DIFF_OBJ_ATTR */ + union hwloc_topology_diff_u * next; + /* List of attribute differences for a single object */ + int obj_depth; + unsigned obj_index; + union hwloc_topology_diff_obj_attr_u diff; + } obj_attr; + + /* A difference that is too complex. */ + struct hwloc_topology_diff_too_complex_s { + hwloc_topology_diff_type_t type; /* must be ::HWLOC_TOPOLOGY_DIFF_TOO_COMPLEX */ + union hwloc_topology_diff_u * next; + /* Where we had to stop computing the diff in the first topology */ + int obj_depth; + unsigned obj_index; + } too_complex; +} * hwloc_topology_diff_t; + + +/** \brief Compute the difference between 2 topologies. + * + * The difference is stored as a list of ::hwloc_topology_diff_t entries + * starting at \p diff. + * It is computed by doing a depth-first traversal of both topology trees + * simultaneously. + * + * If the difference between 2 objects is too complex to be represented + * (for instance if some objects have different types, or different numbers + * of children), a special diff entry of type ::HWLOC_TOPOLOGY_DIFF_TOO_COMPLEX + * is queued. + * The computation of the diff does not continue below these objects. + * So each such diff entry means that the difference between two subtrees + * could not be computed. + * + * \return 0 if the difference can be represented properly. + * + * \return 0 with \p diff pointing to NULL if there is no difference + * between the topologies. + * + * \return 1 if the difference is too complex (see above). Some entries in + * the list will be of type ::HWLOC_TOPOLOGY_DIFF_TOO_COMPLEX. + * + * \return -1 on any other error. + * + * \note \p flags is currently not used. It should be 0. + * + * \note The output diff has to be freed with hwloc_topology_diff_destroy(). + * + * \note The output diff can only be exported to XML or passed to + * hwloc_topology_diff_apply() if 0 was returned, i.e. if no entry of type + * ::HWLOC_TOPOLOGY_DIFF_TOO_COMPLEX is listed. + * + * \note The output diff may be modified by removing some entries from + * the list. The removed entries should be freed by passing them to + * to hwloc_topology_diff_destroy() (possible as another list). +*/ +HWLOC_DECLSPEC int hwloc_topology_diff_build(hwloc_topology_t topology, hwloc_topology_t newtopology, unsigned long flags, hwloc_topology_diff_t *diff); + +/** \brief Flags to be given to hwloc_topology_diff_apply(). + */ +enum hwloc_topology_diff_apply_flags_e { + /** \brief Apply topology diff in reverse direction. + * \hideinitializer + */ + HWLOC_TOPOLOGY_DIFF_APPLY_REVERSE = (1UL<<0) +}; + +/** \brief Apply a topology diff to an existing topology. + * + * \p flags is an OR'ed set of ::hwloc_topology_diff_apply_flags_e. + * + * The new topology is modified in place. hwloc_topology_dup() + * may be used to duplicate it before patching. + * + * If the difference cannot be applied entirely, all previous applied + * elements are unapplied before returning. + * + * \return 0 on success. + * + * \return -N if applying the difference failed while trying + * to apply the N-th part of the difference. For instance -1 + * is returned if the very first difference element could not + * be applied. + */ +HWLOC_DECLSPEC int hwloc_topology_diff_apply(hwloc_topology_t topology, hwloc_topology_diff_t diff, unsigned long flags); + +/** \brief Destroy a list of topology differences. + * + * \return 0. + */ +HWLOC_DECLSPEC int hwloc_topology_diff_destroy(hwloc_topology_diff_t diff); + +/** \brief Load a list of topology differences from a XML file. + * + * If not \c NULL, \p refname will be filled with the identifier + * string of the reference topology for the difference file, + * if any was specified in the XML file. + * This identifier is usually the name of the other XML file + * that contains the reference topology. + * + * \return 0 on success, -1 on error. + * + * \note the pointer returned in refname should later be freed + * by the caller. + */ +HWLOC_DECLSPEC int hwloc_topology_diff_load_xml(const char *xmlpath, hwloc_topology_diff_t *diff, char **refname); + +/** \brief Export a list of topology differences to a XML file. + * + * If not \c NULL, \p refname defines an identifier string + * for the reference topology which was used as a base when + * computing this difference. + * This identifier is usually the name of the other XML file + * that contains the reference topology. + * This attribute is given back when reading the diff from XML. + * + * \return 0 on success, -1 on error. + */ +HWLOC_DECLSPEC int hwloc_topology_diff_export_xml(hwloc_topology_diff_t diff, const char *refname, const char *xmlpath); + +/** \brief Load a list of topology differences from a XML buffer. + * + * Build a list of differences from the XML memory buffer given + * at \p xmlbuffer and of length \p buflen (including an ending \c \0). + * This buffer may have been filled earlier with + * hwloc_topology_diff_export_xmlbuffer(). + * + * If not \c NULL, \p refname will be filled with the identifier + * string of the reference topology for the difference file, + * if any was specified in the XML file. + * This identifier is usually the name of the other XML file + * that contains the reference topology. + * + * \return 0 on success, -1 on error. + * + * \note the pointer returned in refname should later be freed + * by the caller. + */ +HWLOC_DECLSPEC int hwloc_topology_diff_load_xmlbuffer(const char *xmlbuffer, int buflen, hwloc_topology_diff_t *diff, char **refname); + +/** \brief Export a list of topology differences to a XML buffer. + * + * If not \c NULL, \p refname defines an identifier string + * for the reference topology which was used as a base when + * computing this difference. + * This identifier is usually the name of the other XML file + * that contains the reference topology. + * This attribute is given back when reading the diff from XML. + * + * The returned buffer ends with a \c \0 that is included in the returned + * length. + * + * \return 0 on success, -1 on error. + * + * \note The XML buffer should later be freed with hwloc_free_xmlbuffer(). + */ +HWLOC_DECLSPEC int hwloc_topology_diff_export_xmlbuffer(hwloc_topology_diff_t diff, const char *refname, char **xmlbuffer, int *buflen); + +/** @} */ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* HWLOC_DIFF_H */ diff --git a/src/deps/hwloc/include/hwloc/distances.h b/src/deps/hwloc/include/hwloc/distances.h new file mode 100644 index 000000000..302460ac9 --- /dev/null +++ b/src/deps/hwloc/include/hwloc/distances.h @@ -0,0 +1,507 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * Copyright © 2010-2025 Inria. All rights reserved. + * See COPYING in top-level directory. + */ + +/** \file + * \brief Object distances. + */ + +#ifndef HWLOC_DISTANCES_H +#define HWLOC_DISTANCES_H + +#ifndef HWLOC_H +#error Please include the main hwloc.h instead +#endif + + +#ifdef __cplusplus +extern "C" { +#elif 0 +} +#endif + + +/** \defgroup hwlocality_distances_get Retrieve distances between objects + * @{ + */ + +/** \brief Matrix of distances between a set of objects. + * + * The most common matrix contains latencies between NUMA nodes + * (as reported in the System Locality Distance Information Table (SLIT) + * in the ACPI specification), which may or may not be physically accurate. + * It corresponds to the latency for accessing the memory of one node + * from a core in another node. + * The corresponding kind is ::HWLOC_DISTANCES_KIND_MEANS_LATENCY | ::HWLOC_DISTANCES_KIND_FROM_USER. + * The name of this distances structure is "NUMALatency". + * + * The matrix may also contain bandwidths between random sets of objects, + * possibly provided by the user, as specified in the \p kind attribute. + * Others common distance structures include and "XGMIBandwidth", "XGMIHops", + * "XeLinkBandwidth" and "NVLinkBandwidth". + * + * Pointers \p objs and \p values should not be replaced, reallocated, freed, etc. + * However callers are allowed to modify \p kind as well as the contents + * of \p objs and \p values arrays. + * For instance, if there is a single NUMA node per Package, + * hwloc_get_obj_with_same_locality() may be used to convert between them + * and replace NUMA nodes in the \p objs array with the corresponding Packages. + * See also hwloc_distances_transform() for applying some transformations + * to the structure. + */ +struct hwloc_distances_s { + unsigned nbobjs; /**< \brief Number of objects described by the distance matrix. */ + hwloc_obj_t *objs; /**< \brief Array of objects described by the distance matrix. + * These objects are not in any particular order, + * see hwloc_distances_obj_index() and hwloc_distances_obj_pair_values() + * for easy ways to find objects in this array and their corresponding values. + */ + unsigned long kind; /**< \brief OR'ed set of ::hwloc_distances_kind_e. */ + hwloc_uint64_t *values; /**< \brief Matrix of distances between objects, stored as a one-dimension array. + * + * Distance from i-th to j-th object is stored in slot i*nbobjs+j. + * The meaning of the value depends on the \p kind attribute. + */ +}; + +/** \brief Kinds of distance matrices. + * + * The \p kind attribute of struct hwloc_distances_s is a OR'ed set + * of kinds. + * + * Each distance matrix may have only one kind among HWLOC_DISTANCES_KIND_FROM_* + * specifying where distance information comes from, + * and one kind among HWLOC_DISTANCES_KIND_MEANS_* specifying + * whether values are latencies or bandwidths. + */ +enum hwloc_distances_kind_e { + /** \brief These distances were obtained from the operating system or hardware. + * \hideinitializer + */ + HWLOC_DISTANCES_KIND_FROM_OS = (1UL<<0), + /** \brief These distances were provided by the user. + * \hideinitializer + */ + HWLOC_DISTANCES_KIND_FROM_USER = (1UL<<1), + + /** \brief Distance values are similar to latencies between objects. + * Values are smaller for closer objects, hence minimal on the diagonal + * of the matrix (distance between an object and itself). + * It could also be the number of network hops between objects, etc. + * \hideinitializer + */ + HWLOC_DISTANCES_KIND_MEANS_LATENCY = (1UL<<2), + /** \brief Distance values are similar to bandwidths between objects. + * Values are higher for closer objects, hence maximal on the diagonal + * of the matrix (distance between an object and itself). + * Such values are currently ignored for distance-based grouping. + * \hideinitializer + */ + HWLOC_DISTANCES_KIND_MEANS_BANDWIDTH = (1UL<<3), + + /** \brief This distances structure covers objects of different types. + * This may apply to the "NVLinkBandwidth" structure in presence + * of a NVSwitch or POWER processor NVLink port. + * \hideinitializer + */ + HWLOC_DISTANCES_KIND_HETEROGENEOUS_TYPES = (1UL<<4) +}; + +/** \brief Retrieve distance matrices. + * + * Retrieve distance matrices from the topology into the \p distances array. + * + * \p flags is currently unused, should be \c 0. + * + * \p kind serves as a filter. If \c 0, all distance matrices are returned. + * If it contains some HWLOC_DISTANCES_KIND_FROM_*, only distance matrices + * whose kind matches one of these are returned. + * If it contains some HWLOC_DISTANCES_KIND_MEANS_*, only distance matrices + * whose kind matches one of these are returned. + * + * On input, \p nr points to the number of distance matrices that may be stored + * in \p distances. + * On output, \p nr points to the number of distance matrices that were actually + * found, even if some of them couldn't be stored in \p distances. + * Distance matrices that couldn't be stored are ignored, but the function still + * returns success (\c 0). The caller may find out by comparing the value pointed + * by \p nr before and after the function call. + * + * Each distance matrix returned in the \p distances array should be released + * by the caller using hwloc_distances_release(). + * + * \return 0 on success, -1 on error. + */ +HWLOC_DECLSPEC int +hwloc_distances_get(hwloc_topology_t topology, + unsigned *nr, struct hwloc_distances_s **distances, + unsigned long kind, unsigned long flags); + +/** \brief Retrieve distance matrices for object at a specific depth in the topology. + * + * Identical to hwloc_distances_get() with the additional \p depth filter. + * + * \return 0 on success, -1 on error. + */ +HWLOC_DECLSPEC int +hwloc_distances_get_by_depth(hwloc_topology_t topology, int depth, + unsigned *nr, struct hwloc_distances_s **distances, + unsigned long kind, unsigned long flags); + +/** \brief Retrieve distance matrices for object of a specific type. + * + * Identical to hwloc_distances_get() with the additional \p type filter. + * + * \return 0 on success, -1 on error. + */ +HWLOC_DECLSPEC int +hwloc_distances_get_by_type(hwloc_topology_t topology, hwloc_obj_type_t type, + unsigned *nr, struct hwloc_distances_s **distances, + unsigned long kind, unsigned long flags); + +/** \brief Retrieve a distance matrix with the given name. + * + * Usually only one distances structure may match a given name. + * + * The name of the most common structure is "NUMALatency". + * Others include "XGMIBandwidth", "XGMIHops", "XeLinkBandwidth", + * and "NVLinkBandwidth". + * + * \return 0 on success, -1 on error. + */ +HWLOC_DECLSPEC int +hwloc_distances_get_by_name(hwloc_topology_t topology, const char *name, + unsigned *nr, struct hwloc_distances_s **distances, + unsigned long flags); + +/** \brief Get a description of what a distances structure contains. + * + * For instance "NUMALatency" for hardware-provided NUMA distances (ACPI SLIT), + * or \c NULL if unknown. + * + * \return the constant string with the name of the distance structure. + * + * \note The returned name should not be freed by the caller, + * it belongs to the hwloc library. + */ +HWLOC_DECLSPEC const char * +hwloc_distances_get_name(hwloc_topology_t topology, struct hwloc_distances_s *distances); + +/** \brief Release a distance matrix structure previously returned by hwloc_distances_get(). + * + * \note This function is not required if the structure is removed with hwloc_distances_release_remove(). + */ +HWLOC_DECLSPEC void +hwloc_distances_release(hwloc_topology_t topology, struct hwloc_distances_s *distances); + +/** \brief Transformations of distances structures. */ +enum hwloc_distances_transform_e { + /** \brief Remove \c NULL objects from the distances structure. + * + * Every object that was replaced with \c NULL in the \p objs array + * is removed and the \p values array is updated accordingly. + * + * At least \c 2 objects must remain, otherwise hwloc_distances_transform() + * will return \c -1 with \p errno set to \c EINVAL. + * + * \p kind will be updated with or without ::HWLOC_DISTANCES_KIND_HETEROGENEOUS_TYPES + * according to the remaining objects. + * + * \hideinitializer + */ + HWLOC_DISTANCES_TRANSFORM_REMOVE_NULL = 0, + + /** \brief Replace bandwidth values with a number of links. + * + * Usually all values will be either \c 0 (no link) or \c 1 (one link). + * However some matrices could get larger values if some pairs of + * peers are connected by different numbers of links. + * + * Values on the diagonal are set to \c 0. + * + * This transformation only applies to bandwidth matrices. + * + * \hideinitializer + */ + HWLOC_DISTANCES_TRANSFORM_LINKS = 1, + + /** \brief Merge switches with multiple ports into a single object. + * + * This currently only applies to NVSwitches where GPUs seem connected + * to different switch ports. Switch ports must be objects with subtype + * "NVSwitch" as in the NVLinkBandwidth matrix. + * + * This transformation will replace all ports with only the first one, + * now connected to all GPUs. Other ports are removed by applying + * ::HWLOC_DISTANCES_TRANSFORM_REMOVE_NULL internally. + * \hideinitializer + */ + HWLOC_DISTANCES_TRANSFORM_MERGE_SWITCH_PORTS = 2, + + /** \brief Apply a transitive closure to the matrix to connect objects across switches. + * + * All pairs of GPUs will be reported as directly connected instead GPUs being + * only connected to switches. + * + * Switch ports must be objects with subtype "NVSwitch" as in the NVLinkBandwidth matrix. + * \hideinitializer + */ + HWLOC_DISTANCES_TRANSFORM_TRANSITIVE_CLOSURE = 3 +}; + +/** \brief Apply a transformation to a distances structure. + * + * Modify a distances structure that was previously obtained with + * hwloc_distances_get() or one of its variants. + * + * This modifies the local copy of the distances structures but does + * not modify the distances information stored inside the topology + * (retrieved by another call to hwloc_distances_get() or exported to XML). + * To do so, one should add a new distances structure with same + * name, kind, objects and values (see \ref hwlocality_distances_add) + * and then remove this old one with hwloc_distances_release_remove(). + * + * \p transform must be one of the transformations listed + * in ::hwloc_distances_transform_e. + * + * These transformations may modify the contents of the \p objs or \p values arrays. + * + * \p transform_attr must be \c NULL for now. + * + * \p flags must be \c 0 for now. + * + * \return 0 on success, -1 on error for instance if flags are invalid. + * + * \note Objects in distances array \p objs may be directly modified + * in place without using hwloc_distances_transform(). + * One may use hwloc_get_obj_with_same_locality() to easily convert + * between similar objects of different types. + */ +HWLOC_DECLSPEC int hwloc_distances_transform(hwloc_topology_t topology, struct hwloc_distances_s *distances, + enum hwloc_distances_transform_e transform, + void *transform_attr, + unsigned long flags); + +/** @} */ + + + +/** \defgroup hwlocality_distances_consult Helpers for consulting distance matrices + * @{ + */ + +/** \brief Find the index of an object in a distances structure. + * + * \return the index of the object in the distances structure if any. + * \return -1 if object \p obj is not involved in structure \p distances. + */ +static __hwloc_inline int +hwloc_distances_obj_index(struct hwloc_distances_s *distances, hwloc_obj_t obj) +{ + unsigned i; + for(i=0; inbobjs; i++) + if (distances->objs[i] == obj) + return (int)i; + return -1; +} + +/** \brief Find the values between two objects in a distance matrices. + * + * The distance from \p obj1 to \p obj2 is stored in the value pointed by + * \p value1to2 and reciprocally. + * + * \return 0 on success. + * \return -1 if object \p obj1 or \p obj2 is not involved in structure \p distances. + */ +static __hwloc_inline int +hwloc_distances_obj_pair_values(struct hwloc_distances_s *distances, + hwloc_obj_t obj1, hwloc_obj_t obj2, + hwloc_uint64_t *value1to2, hwloc_uint64_t *value2to1) +{ + int i1 = hwloc_distances_obj_index(distances, obj1); + int i2 = hwloc_distances_obj_index(distances, obj2); + if (i1 < 0 || i2 < 0) + return -1; + *value1to2 = distances->values[i1 * distances->nbobjs + i2]; + *value2to1 = distances->values[i2 * distances->nbobjs + i1]; + return 0; +} + +/** @} */ + + + +/** \defgroup hwlocality_distances_add Add distances between objects + * + * The usual way to add distances is: + * \code + * hwloc_distances_add_handle_t handle; + * int err = -1; + * handle = hwloc_distances_add_create(topology, "name", kind, 0); + * if (handle) { + * err = hwloc_distances_add_values(topology, handle, nbobjs, objs, values, 0); + * if (!err) + * err = hwloc_distances_add_commit(topology, handle, flags); + * } + * \endcode + * If \p err is \c 0 at the end, then addition was successful. + * + * @{ + */ + +/** \brief Handle to a new distances structure during its addition to the topology. */ +typedef void * hwloc_distances_add_handle_t; + +/** \brief Create a new empty distances structure. + * + * Create an empty distances structure + * to be filled with hwloc_distances_add_values() + * and then committed with hwloc_distances_add_commit(). + * + * Parameter \p name is optional, it may be \c NULL. + * Otherwise, it will be copied internally and may later be freed by the caller. + * + * \p kind specifies the kind of distance as a OR'ed set of ::hwloc_distances_kind_e. + * Only one kind of meaning and one kind of provenance may be given if appropriate + * (e.g. ::HWLOC_DISTANCES_KIND_MEANS_BANDWIDTH and ::HWLOC_DISTANCES_KIND_FROM_USER). + * Kind ::HWLOC_DISTANCES_KIND_HETEROGENEOUS_TYPES will be automatically set + * according to objects having different types in hwloc_distances_add_values(). + * + * \p flags must be \c 0 for now. + * + * \return A hwloc_distances_add_handle_t that should then be passed + * to hwloc_distances_add_values() and hwloc_distances_add_commit(). + * + * \return \c NULL on error. + */ +HWLOC_DECLSPEC hwloc_distances_add_handle_t +hwloc_distances_add_create(hwloc_topology_t topology, + const char *name, unsigned long kind, + unsigned long flags); + +/** \brief Specify the objects and values in a new empty distances structure. + * + * Specify the objects and values for a new distances structure + * that was returned as a handle by hwloc_distances_add_create(). + * The structure must then be committed with hwloc_distances_add_commit(). + * + * The number of objects is \p nbobjs and the array of objects is \p objs. + * Distance values are stored as a one-dimension array in \p values. + * The distance from object i to object j is in slot i*nbobjs+j. + * + * \p nbobjs must be at least 2. + * + * Arrays \p objs and \p values will be copied internally, + * they may later be freed by the caller. + * + * On error, the temporary distances structure and its content are destroyed. + * + * \p flags must be \c 0 for now. + * + * \return 0 on success. + * \return -1 on error. + */ +HWLOC_DECLSPEC int hwloc_distances_add_values(hwloc_topology_t topology, + hwloc_distances_add_handle_t handle, + unsigned nbobjs, hwloc_obj_t *objs, + hwloc_uint64_t *values, + unsigned long flags); + +/** \brief Flags for adding a new distances to a topology. */ +enum hwloc_distances_add_flag_e { + /** \brief Try to group objects based on the newly provided distance information. + * Grouping is only performed when the distances structure contains latencies, + * and when all objects are of the same type. + * \hideinitializer + */ + HWLOC_DISTANCES_ADD_FLAG_GROUP = (1UL<<0), + /** \brief If grouping, consider the distance values as inaccurate and relax the + * comparisons during the grouping algorithms. The actual accuracy may be modified + * through the HWLOC_GROUPING_ACCURACY environment variable (see \ref envvar_heuristics). + * \hideinitializer + */ + HWLOC_DISTANCES_ADD_FLAG_GROUP_INACCURATE = (1UL<<1) +}; + +/** \brief Commit a new distances structure. + * + * This function finalizes the distances structure and inserts in it the topology. + * + * Parameter \p handle was previously returned by hwloc_distances_add_create(). + * Then objects and values were specified with hwloc_distances_add_values(). + * + * \p flags configures the behavior of the function using an optional OR'ed set of + * ::hwloc_distances_add_flag_e. + * It may be used to request the grouping of existing objects based on distances. + * + * On error, the temporary distances structure and its content are destroyed. + * + * \return 0 on success. + * \return -1 on error. + */ +HWLOC_DECLSPEC int hwloc_distances_add_commit(hwloc_topology_t topology, + hwloc_distances_add_handle_t handle, + unsigned long flags); + +/** @} */ + + + +/** \defgroup hwlocality_distances_remove Remove distances between objects + * @{ + */ + +/** \brief Remove all distance matrices from a topology. + * + * Remove all distance matrices, either provided by the user or + * gathered through the OS. + * + * If these distances were used to group objects, these additional + * Group objects are not removed from the topology. + * + * \return 0 on success, -1 on error. + */ +HWLOC_DECLSPEC int hwloc_distances_remove(hwloc_topology_t topology); + +/** \brief Remove distance matrices for objects at a specific depth in the topology. + * + * Identical to hwloc_distances_remove() but only applies to one level of the topology. + * + * \return 0 on success, -1 on error. + */ +HWLOC_DECLSPEC int hwloc_distances_remove_by_depth(hwloc_topology_t topology, int depth); + +/** \brief Remove distance matrices for objects of a specific type in the topology. + * + * Identical to hwloc_distances_remove() but only applies to one level of the topology. + * + * \return 0 on success, -1 on error. + */ +static __hwloc_inline int +hwloc_distances_remove_by_type(hwloc_topology_t topology, hwloc_obj_type_t type) +{ + int depth = hwloc_get_type_depth(topology, type); + if (depth == HWLOC_TYPE_DEPTH_UNKNOWN || depth == HWLOC_TYPE_DEPTH_MULTIPLE) + return 0; + return hwloc_distances_remove_by_depth(topology, depth); +} + +/** \brief Release and remove the given distance matrice from the topology. + * + * This function includes a call to hwloc_distances_release(). + * + * \return 0 on success, -1 on error. + */ +HWLOC_DECLSPEC int hwloc_distances_release_remove(hwloc_topology_t topology, struct hwloc_distances_s *distances); + +/** @} */ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* HWLOC_DISTANCES_H */ diff --git a/src/deps/hwloc/include/hwloc/export.h b/src/deps/hwloc/include/hwloc/export.h new file mode 100644 index 000000000..908be2f95 --- /dev/null +++ b/src/deps/hwloc/include/hwloc/export.h @@ -0,0 +1,287 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * Copyright © 2009-2018 Inria. All rights reserved. + * Copyright © 2009-2012 Université Bordeaux + * Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved. + * See COPYING in top-level directory. + */ + +/** \file + * \brief Exporting Topologies to XML or to Synthetic strings. + */ + +#ifndef HWLOC_EXPORT_H +#define HWLOC_EXPORT_H + +#ifndef HWLOC_H +#error Please include the main hwloc.h instead +#endif + + +#ifdef __cplusplus +extern "C" { +#elif 0 +} +#endif + + +/** \defgroup hwlocality_xmlexport Exporting Topologies to XML + * @{ + */ + +/** \brief Flags for exporting XML topologies. + * + * Flags to be given as a OR'ed set to hwloc_topology_export_xml(). + */ +enum hwloc_topology_export_xml_flags_e { + /** \brief Export XML that is loadable by hwloc v1.x. + * However, the export may miss some details about the topology. + * \hideinitializer + */ + HWLOC_TOPOLOGY_EXPORT_XML_FLAG_V1 = (1UL<<0) +}; + +/** \brief Export the topology into an XML file. + * + * This file may be loaded later through hwloc_topology_set_xml(). + * + * By default, the latest export format is used, which means older hwloc + * releases (e.g. v1.x) will not be able to import it. + * Exporting to v1.x specific XML format is possible using flag + * ::HWLOC_TOPOLOGY_EXPORT_XML_FLAG_V1 but it may miss some details + * about the topology. + * If there is any chance that the exported file may ever be imported + * back by a process using hwloc 1.x, one should consider detecting + * it at runtime and using the corresponding export format. + * + * \p flags is a OR'ed set of ::hwloc_topology_export_xml_flags_e. + * + * \return 0 on success, or -1 on error. + * + * \note See also hwloc_topology_set_userdata_export_callback() + * for exporting application-specific object userdata. + * + * \note The topology-specific userdata pointer is ignored when exporting to XML. + * + * \note Only printable characters may be exported to XML string attributes. + * Any other character, especially any non-ASCII character, will be silently + * dropped. + * + * \note If \p name is "-", the XML output is sent to the standard output. + */ +HWLOC_DECLSPEC int hwloc_topology_export_xml(hwloc_topology_t topology, const char *xmlpath, unsigned long flags); + +/** \brief Export the topology into a newly-allocated XML memory buffer. + * + * \p xmlbuffer is allocated by the callee and should be freed with + * hwloc_free_xmlbuffer() later in the caller. + * + * This memory buffer may be loaded later through hwloc_topology_set_xmlbuffer(). + * + * By default, the latest export format is used, which means older hwloc + * releases (e.g. v1.x) will not be able to import it. + * Exporting to v1.x specific XML format is possible using flag + * ::HWLOC_TOPOLOGY_EXPORT_XML_FLAG_V1 but it may miss some details + * about the topology. + * If there is any chance that the exported buffer may ever be imported + * back by a process using hwloc 1.x, one should consider detecting + * it at runtime and using the corresponding export format. + * + * The returned buffer ends with a \0 that is included in the returned + * length. + * + * \p flags is a OR'ed set of ::hwloc_topology_export_xml_flags_e. + * + * \return 0 on success, or -1 on error. + * + * \note See also hwloc_topology_set_userdata_export_callback() + * for exporting application-specific object userdata. + * + * \note The topology-specific userdata pointer is ignored when exporting to XML. + * + * \note Only printable characters may be exported to XML string attributes. + * Any other character, especially any non-ASCII character, will be silently + * dropped. + */ +HWLOC_DECLSPEC int hwloc_topology_export_xmlbuffer(hwloc_topology_t topology, char **xmlbuffer, int *buflen, unsigned long flags); + +/** \brief Free a buffer allocated by hwloc_topology_export_xmlbuffer() */ +HWLOC_DECLSPEC void hwloc_free_xmlbuffer(hwloc_topology_t topology, char *xmlbuffer); + +/** \brief Set the application-specific callback for exporting object userdata + * + * The object userdata pointer is not exported to XML by default because hwloc + * does not know what it contains. + * + * This function lets applications set \p export_cb to a callback function + * that converts this opaque userdata into an exportable string. + * + * \p export_cb is invoked during XML export for each object whose + * \p userdata pointer is not \c NULL. + * The callback should use hwloc_export_obj_userdata() or + * hwloc_export_obj_userdata_base64() to actually export + * something to XML (possibly multiple times per object). + * + * \p export_cb may be set to \c NULL if userdata should not be exported to XML. + * + * \note The topology-specific userdata pointer is ignored when exporting to XML. + */ +HWLOC_DECLSPEC void hwloc_topology_set_userdata_export_callback(hwloc_topology_t topology, + void (*export_cb)(void *reserved, hwloc_topology_t topology, hwloc_obj_t obj)); + +/** \brief Export some object userdata to XML + * + * This function may only be called from within the export() callback passed + * to hwloc_topology_set_userdata_export_callback(). + * It may be invoked one of multiple times to export some userdata to XML. + * The \p buffer content of length \p length is stored with optional name + * \p name. + * + * When importing this XML file, the import() callback (if set) will be + * called exactly as many times as hwloc_export_obj_userdata() was called + * during export(). It will receive the corresponding \p name, \p buffer + * and \p length arguments. + * + * \p reserved, \p topology and \p obj must be the first three parameters + * that were given to the export callback. + * + * Only printable characters may be exported to XML string attributes. + * + * If exporting binary data, the application should first encode into + * printable characters only (or use hwloc_export_obj_userdata_base64()). + * It should also take care of portability issues if the export may + * be reimported on a different architecture. + * + * \return 0 on success. + * \return -1 with errno set to \c EINVAL if a non-printable character is + * passed in \p name or \b buffer. + */ +HWLOC_DECLSPEC int hwloc_export_obj_userdata(void *reserved, hwloc_topology_t topology, hwloc_obj_t obj, const char *name, const void *buffer, size_t length); + +/** \brief Encode and export some object userdata to XML + * + * This function is similar to hwloc_export_obj_userdata() but it encodes + * the input buffer into printable characters before exporting. + * On import, decoding is automatically performed before the data is given + * to the import() callback if any. + * + * This function may only be called from within the export() callback passed + * to hwloc_topology_set_userdata_export_callback(). + * + * The name must be made of printable characters for export to XML string attributes. + * + * The function does not take care of portability issues if the export + * may be reimported on a different architecture. + * + * \return 0 on success. + * \return -1 with errno set to \c EINVAL if a non-printable character is + * passed in \p name. + */ +HWLOC_DECLSPEC int hwloc_export_obj_userdata_base64(void *reserved, hwloc_topology_t topology, hwloc_obj_t obj, const char *name, const void *buffer, size_t length); + +/** \brief Set the application-specific callback for importing userdata + * + * On XML import, userdata is ignored by default because hwloc does not know + * how to store it in memory. + * + * This function lets applications set \p import_cb to a callback function + * that will get the XML-stored userdata and store it in the object as expected + * by the application. + * + * \p import_cb is called during hwloc_topology_load() as many times as + * hwloc_export_obj_userdata() was called during export. The topology + * is not entirely setup yet. Object attributes are ready to consult, + * but links between objects are not. + * + * \p import_cb may be \c NULL if userdata should be ignored during import. + * + * \note \p buffer contains \p length characters followed by a null byte ('\0'). + * + * \note This function should be called before hwloc_topology_load(). + * + * \note The topology-specific userdata pointer is ignored when importing from XML. + */ +HWLOC_DECLSPEC void hwloc_topology_set_userdata_import_callback(hwloc_topology_t topology, + void (*import_cb)(hwloc_topology_t topology, hwloc_obj_t obj, const char *name, const void *buffer, size_t length)); + +/** @} */ + + +/** \defgroup hwlocality_syntheticexport Exporting Topologies to Synthetic + * @{ + */ + +/** \brief Flags for exporting synthetic topologies. + * + * Flags to be given as a OR'ed set to hwloc_topology_export_synthetic(). + */ +enum hwloc_topology_export_synthetic_flags_e { + /** \brief Export extended types such as L2dcache as basic types such as Cache. + * + * This is required if loading the synthetic description with hwloc < 1.9. + * \hideinitializer + */ + HWLOC_TOPOLOGY_EXPORT_SYNTHETIC_FLAG_NO_EXTENDED_TYPES = (1UL<<0), + + /** \brief Do not export level attributes. + * + * Ignore level attributes such as memory/cache sizes or PU indexes. + * This is required if loading the synthetic description with hwloc < 1.10. + * \hideinitializer + */ + HWLOC_TOPOLOGY_EXPORT_SYNTHETIC_FLAG_NO_ATTRS = (1UL<<1), + + /** \brief Export the memory hierarchy as expected in hwloc 1.x. + * + * Instead of attaching memory children to levels, export single NUMA node child + * as normal intermediate levels, when possible. + * This is required if loading the synthetic description with hwloc 1.x. + * However this may fail if some objects have multiple local NUMA nodes. + * \hideinitializer + */ + HWLOC_TOPOLOGY_EXPORT_SYNTHETIC_FLAG_V1 = (1UL<<2), + + /** \brief Do not export memory information. + * + * Only export the actual hierarchy of normal CPU-side objects and ignore + * where memory is attached. + * This is useful for when the hierarchy of CPUs is what really matters, + * but it behaves as if there was a single machine-wide NUMA node. + * \hideinitializer + */ + HWLOC_TOPOLOGY_EXPORT_SYNTHETIC_FLAG_IGNORE_MEMORY = (1UL<<3) +}; + +/** \brief Export the topology as a synthetic string. + * + * At most \p buflen characters will be written in \p buffer, + * including the terminating \0. + * + * This exported string may be given back to hwloc_topology_set_synthetic(). + * + * \p flags is a OR'ed set of ::hwloc_topology_export_synthetic_flags_e. + * + * \return The number of characters that were written, + * not including the terminating \0. + * + * \return -1 if the topology could not be exported, + * for instance if it is not symmetric. + * + * \note I/O and Misc children are ignored, the synthetic string only + * describes normal children. + * + * \note A 1024-byte buffer should be large enough for exporting + * topologies in the vast majority of cases. + */ + HWLOC_DECLSPEC int hwloc_topology_export_synthetic(hwloc_topology_t topology, char *buffer, size_t buflen, unsigned long flags); + +/** @} */ + + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* HWLOC_EXPORT_H */ diff --git a/src/deps/hwloc/include/hwloc/gl.h b/src/deps/hwloc/include/hwloc/gl.h new file mode 100644 index 000000000..fc58377af --- /dev/null +++ b/src/deps/hwloc/include/hwloc/gl.h @@ -0,0 +1,138 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * Copyright © 2012 Blue Brain Project, EPFL. All rights reserved. + * Copyright © 2012-2023 Inria. All rights reserved. + * See COPYING in top-level directory. + */ + +/** \file + * \brief Macros to help interaction between hwloc and OpenGL displays. + * + * Applications that use both hwloc and OpenGL may want to include + * this file so as to get topology information for OpenGL displays. + */ + +#ifndef HWLOC_GL_H +#define HWLOC_GL_H + +#include "hwloc.h" + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** \defgroup hwlocality_gl Interoperability with OpenGL displays + * + * This interface offers ways to retrieve topology information about + * OpenGL displays. + * + * Only the NVIDIA display locality information is currently available, + * using the NV-CONTROL X11 extension and the NVCtrl library. + * + * @{ + */ + +/** \brief Get the hwloc OS device object corresponding to the + * OpenGL display given by port and device index. + * + * \return The hwloc OS device object describing the OpenGL display + * whose port (server) is \p port and device (screen) is \p device. + * \return \c NULL if none could be found. + * + * The topology \p topology does not necessarily have to match the current + * machine. For instance the topology may be an XML import of a remote host. + * I/O devices detection and the GL component must be enabled in the topology. + * + * \note The corresponding PCI device object can be obtained by looking + * at the OS device parent object (unless PCI devices are filtered out). + */ +static __hwloc_inline hwloc_obj_t +hwloc_gl_get_display_osdev_by_port_device(hwloc_topology_t topology, + unsigned port, unsigned device) +{ + unsigned x = (unsigned) -1, y = (unsigned) -1; + hwloc_obj_t osdev = NULL; + while ((osdev = hwloc_get_next_osdev(topology, osdev)) != NULL) { + if (HWLOC_OBJ_OSDEV_GPU == osdev->attr->osdev.type + && osdev->name + && sscanf(osdev->name, ":%u.%u", &x, &y) == 2 + && port == x && device == y) + return osdev; + } + errno = EINVAL; + return NULL; +} + +/** \brief Get the hwloc OS device object corresponding to the + * OpenGL display given by name. + * + * \return The hwloc OS device object describing the OpenGL display + * whose name is \p name, built as ":port.device" such as ":0.0" . + * \return \c NULL if none could be found. + * + * The topology \p topology does not necessarily have to match the current + * machine. For instance the topology may be an XML import of a remote host. + * I/O devices detection and the GL component must be enabled in the topology. + * + * \note The corresponding PCI device object can be obtained by looking + * at the OS device parent object (unless PCI devices are filtered out). + */ +static __hwloc_inline hwloc_obj_t +hwloc_gl_get_display_osdev_by_name(hwloc_topology_t topology, + const char *name) +{ + hwloc_obj_t osdev = NULL; + while ((osdev = hwloc_get_next_osdev(topology, osdev)) != NULL) { + if (HWLOC_OBJ_OSDEV_GPU == osdev->attr->osdev.type + && osdev->name + && !strcmp(name, osdev->name)) + return osdev; + } + errno = EINVAL; + return NULL; +} + +/** \brief Get the OpenGL display port and device corresponding + * to the given hwloc OS object. + * + * Retrieves the OpenGL display port (server) in \p port and device (screen) + * in \p screen that correspond to the given hwloc OS device object. + * + * \return 0 on success. + * \return -1 if none could be found. + * + * The topology \p topology does not necessarily have to match the current + * machine. For instance the topology may be an XML import of a remote host. + * I/O devices detection and the GL component must be enabled in the topology. + */ +static __hwloc_inline int +hwloc_gl_get_display_by_osdev(hwloc_topology_t topology __hwloc_attribute_unused, + hwloc_obj_t osdev, + unsigned *port, unsigned *device) +{ + unsigned x = -1, y = -1; + if (HWLOC_OBJ_OSDEV_GPU == osdev->attr->osdev.type + && sscanf(osdev->name, ":%u.%u", &x, &y) == 2) { + *port = x; + *device = y; + return 0; + } + errno = EINVAL; + return -1; +} + +/** @} */ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* HWLOC_GL_H */ + diff --git a/src/deps/hwloc/include/hwloc/glibc-sched.h b/src/deps/hwloc/include/hwloc/glibc-sched.h new file mode 100644 index 000000000..2d24a57d0 --- /dev/null +++ b/src/deps/hwloc/include/hwloc/glibc-sched.h @@ -0,0 +1,134 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * Copyright © 2009 CNRS + * Copyright © 2009-2023 Inria. All rights reserved. + * Copyright © 2009-2011 Université Bordeaux + * Copyright © 2011 Cisco Systems, Inc. All rights reserved. + * See COPYING in top-level directory. + */ + +/** \file + * \brief Macros to help interaction between hwloc and glibc scheduling routines. + * + * Applications that use both hwloc and glibc scheduling routines such as + * sched_getaffinity() or pthread_attr_setaffinity_np() may want to include + * this file so as to ease conversion between their respective types. + */ + +#ifndef HWLOC_GLIBC_SCHED_H +#define HWLOC_GLIBC_SCHED_H + +#include "hwloc.h" +#include "hwloc/helper.h" + +#include + +#if !defined _GNU_SOURCE || (!defined _SCHED_H && !defined _SCHED_H_) || (!defined CPU_SETSIZE && !defined sched_priority) +#error Please make sure to include sched.h before including glibc-sched.h, and define _GNU_SOURCE before any inclusion of sched.h +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + + +#ifdef HWLOC_HAVE_CPU_SET + + +/** \defgroup hwlocality_glibc_sched Interoperability with glibc sched affinity + * + * This interface offers ways to convert between hwloc cpusets and glibc cpusets + * such as those manipulated by sched_getaffinity() or pthread_attr_setaffinity_np(). + * + * \note Topology \p topology must match the current machine. + * + * @{ + */ + + +/** \brief Convert hwloc CPU set \p toposet into glibc sched affinity CPU set \p schedset + * + * This function may be used before calling sched_setaffinity or any other function + * that takes a cpu_set_t as input parameter. + * + * \p schedsetsize should be sizeof(cpu_set_t) unless \p schedset was dynamically allocated with CPU_ALLOC + * + * \return 0. + */ +static __hwloc_inline int +hwloc_cpuset_to_glibc_sched_affinity(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_const_cpuset_t hwlocset, + cpu_set_t *schedset, size_t schedsetsize) +{ +#ifdef CPU_ZERO_S + unsigned cpu; + CPU_ZERO_S(schedsetsize, schedset); + hwloc_bitmap_foreach_begin(cpu, hwlocset) + CPU_SET_S(cpu, schedsetsize, schedset); + hwloc_bitmap_foreach_end(); +#else /* !CPU_ZERO_S */ + unsigned cpu; + CPU_ZERO(schedset); + assert(schedsetsize == sizeof(cpu_set_t)); + hwloc_bitmap_foreach_begin(cpu, hwlocset) + CPU_SET(cpu, schedset); + hwloc_bitmap_foreach_end(); +#endif /* !CPU_ZERO_S */ + return 0; +} + +/** \brief Convert glibc sched affinity CPU set \p schedset into hwloc CPU set + * + * This function may be used before calling sched_setaffinity or any other function + * that takes a cpu_set_t as input parameter. + * + * \p schedsetsize should be sizeof(cpu_set_t) unless \p schedset was dynamically allocated with CPU_ALLOC + * + * \return 0 on success. + * \return -1 with errno set to \c ENOMEM if some internal reallocation failed. + */ +static __hwloc_inline int +hwloc_cpuset_from_glibc_sched_affinity(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_cpuset_t hwlocset, + const cpu_set_t *schedset, size_t schedsetsize) +{ + int cpu; +#ifdef CPU_ZERO_S + int count; +#endif + hwloc_bitmap_zero(hwlocset); +#ifdef CPU_ZERO_S + count = CPU_COUNT_S(schedsetsize, schedset); + cpu = 0; + while (count) { + if (CPU_ISSET_S(cpu, schedsetsize, schedset)) { + if (hwloc_bitmap_set(hwlocset, cpu) < 0) + return -1; + count--; + } + cpu++; + } +#else /* !CPU_ZERO_S */ + /* sched.h does not support dynamic cpu_set_t (introduced in glibc 2.7), + * assume we have a very old interface without CPU_COUNT (added in 2.6) + */ + assert(schedsetsize == sizeof(cpu_set_t)); + for(cpu=0; cpu +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** \defgroup hwlocality_helper_types Kinds of object Type + * @{ + * + * Each object type is + * either Normal (i.e. hwloc_obj_type_is_normal() returns 1), + * or Memory (i.e. hwloc_obj_type_is_memory() returns 1) + * or I/O (i.e. hwloc_obj_type_is_io() returns 1) + * or Misc (i.e. equal to ::HWLOC_OBJ_MISC). + * It cannot be of more than one of these kinds. + * + * See also Object Kind in \ref termsanddefs. + */ + +/** \brief Check whether an object type is Normal. + * + * Normal objects are objects of the main CPU hierarchy + * (Machine, Package, Core, PU, CPU caches, etc.), + * but they are not NUMA nodes, I/O devices or Misc objects. + * + * They are attached to parent as Normal children, + * not as Memory, I/O or Misc children. + * + * \return 1 if an object of type \p type is a Normal object, 0 otherwise. + */ +HWLOC_DECLSPEC int +hwloc_obj_type_is_normal(hwloc_obj_type_t type); + +/** \brief Check whether an object type is I/O. + * + * I/O objects are objects attached to their parents + * in the I/O children list. + * This current includes Bridges, PCI and OS devices. + * + * \return 1 if an object of type \p type is a I/O object, 0 otherwise. + */ +HWLOC_DECLSPEC int +hwloc_obj_type_is_io(hwloc_obj_type_t type); + +/** \brief Check whether an object type is Memory. + * + * Memory objects are objects attached to their parents + * in the Memory children list. + * This current includes NUMA nodes and Memory-side caches. + * + * \return 1 if an object of type \p type is a Memory object, 0 otherwise. + */ +HWLOC_DECLSPEC int +hwloc_obj_type_is_memory(hwloc_obj_type_t type); + +/** \brief Check whether an object type is a CPU Cache (Data, Unified or Instruction). + * + * Memory-side caches are not CPU caches. + * + * \return 1 if an object of type \p type is a Cache, 0 otherwise. + */ +HWLOC_DECLSPEC int +hwloc_obj_type_is_cache(hwloc_obj_type_t type); + +/** \brief Check whether an object type is a CPU Data or Unified Cache. + * + * Memory-side caches are not CPU caches. + * + * \return 1 if an object of type \p type is a CPU Data or Unified Cache, 0 otherwise. + */ +HWLOC_DECLSPEC int +hwloc_obj_type_is_dcache(hwloc_obj_type_t type); + +/** \brief Check whether an object type is a CPU Instruction Cache, + * + * Memory-side caches are not CPU caches. + * + * \return 1 if an object of type \p type is a CPU Instruction Cache, 0 otherwise. + */ +HWLOC_DECLSPEC int +hwloc_obj_type_is_icache(hwloc_obj_type_t type); + +/** @} */ + + + +/** \defgroup hwlocality_helper_find_inside Finding Objects inside a CPU set + * @{ + */ + +/** \brief Get the first largest object included in the given cpuset \p set. + * + * \return the first object that is included in \p set and whose parent is not. + * \return \c NULL if no such object exists. + * + * This is convenient for iterating over all largest objects within a CPU set + * by doing a loop getting the first largest object and clearing its CPU set + * from the remaining CPU set. + */ +static __hwloc_inline hwloc_obj_t +hwloc_get_first_largest_obj_inside_cpuset(hwloc_topology_t topology, hwloc_const_cpuset_t set) +{ + hwloc_obj_t obj = hwloc_get_root_obj(topology); + if (!hwloc_bitmap_intersects(obj->cpuset, set)) + return NULL; + while (!hwloc_bitmap_isincluded(obj->cpuset, set)) { + /* while the object intersects without being included, look at its children */ + hwloc_obj_t child = obj->first_child; + while (child) { + if (hwloc_bitmap_intersects(child->cpuset, set)) + break; + child = child->next_sibling; + } + if (!child) + /* no child intersects, return their father */ + return obj; + /* found one intersecting child, look at its children */ + obj = child; + } + /* obj is included, return it */ + return obj; +} + +/** \brief Get the set of largest objects covering exactly a given cpuset \p set + * + * \return the number of objects returned in \p objs. + * \return -1 if no set of objects may cover that cpuset. + */ +HWLOC_DECLSPEC int hwloc_get_largest_objs_inside_cpuset (hwloc_topology_t topology, hwloc_const_cpuset_t set, + hwloc_obj_t * __hwloc_restrict objs, int max); + +/** \brief Return the next object at depth \p depth included in CPU set \p set. + * + * The next invokation should pass the previous return value in \p prev + * so as to obtain the next object in \p set. + * + * \return the first object at depth \p depth included in \p set if \p prev is \c NULL. + * \return the next object at depth \p depth included in \p set if \p prev is not \c NULL. + * \return \c NULL if there is no next object. + * + * \note Objects with empty CPU sets are ignored + * (otherwise they would be considered included in any given set). + * + * \note This function cannot work if objects at the given depth do + * not have CPU sets (I/O or Misc objects). + */ +static __hwloc_inline hwloc_obj_t +hwloc_get_next_obj_inside_cpuset_by_depth (hwloc_topology_t topology, hwloc_const_cpuset_t set, + int depth, hwloc_obj_t prev) +{ + hwloc_obj_t next = hwloc_get_next_obj_by_depth(topology, depth, prev); + if (!next) + return NULL; + while (next && (hwloc_bitmap_iszero(next->cpuset) || !hwloc_bitmap_isincluded(next->cpuset, set))) + next = next->next_cousin; + return next; +} + +/** \brief Return the next object of type \p type included in CPU set \p set. + * + * The next invokation should pass the previous return value in \p prev + * so as to obtain the next object in \p set. + * + * \return the first object of type \p type included in \p set if \p prev is \c NULL. + * \return the next object of type \p type included in \p set if \p prev is not \c NULL. + * \return \c NULL if there is no next object. + * \return \c NULL if there is no depth for the given type. + * \return \c NULL if there are multiple depths for the given type, + * the caller should fallback to hwloc_get_next_obj_inside_cpuset_by_depth(). + * + * \note Objects with empty CPU sets are ignored + * (otherwise they would be considered included in any given set). + * + * \note This function cannot work if objects of the given type do + * not have CPU sets (I/O or Misc objects). + */ +static __hwloc_inline hwloc_obj_t +hwloc_get_next_obj_inside_cpuset_by_type (hwloc_topology_t topology, hwloc_const_cpuset_t set, + hwloc_obj_type_t type, hwloc_obj_t prev) +{ + int depth = hwloc_get_type_depth(topology, type); + if (depth == HWLOC_TYPE_DEPTH_UNKNOWN || depth == HWLOC_TYPE_DEPTH_MULTIPLE) + return NULL; + return hwloc_get_next_obj_inside_cpuset_by_depth(topology, set, depth, prev); +} + +/** \brief Return the (logically) \p idx -th object at depth \p depth included in CPU set \p set. + * + * \return the object if any, \c NULL otherwise. + * + * \note Objects with empty CPU sets are ignored + * (otherwise they would be considered included in any given set). + * + * \note This function cannot work if objects at the given depth do + * not have CPU sets (I/O or Misc objects). + */ +static __hwloc_inline hwloc_obj_t +hwloc_get_obj_inside_cpuset_by_depth (hwloc_topology_t topology, hwloc_const_cpuset_t set, + int depth, unsigned idx) __hwloc_attribute_pure; +static __hwloc_inline hwloc_obj_t +hwloc_get_obj_inside_cpuset_by_depth (hwloc_topology_t topology, hwloc_const_cpuset_t set, + int depth, unsigned idx) +{ + hwloc_obj_t obj = hwloc_get_obj_by_depth (topology, depth, 0); + unsigned count = 0; + if (!obj) + return NULL; + while (obj) { + if (!hwloc_bitmap_iszero(obj->cpuset) && hwloc_bitmap_isincluded(obj->cpuset, set)) { + if (count == idx) + return obj; + count++; + } + obj = obj->next_cousin; + } + return NULL; +} + +/** \brief Return the \p idx -th object of type \p type included in CPU set \p set. + * + * \return the object if any. + * \return \c NULL if there is no such object. + * \return \c NULL if there is no depth for given type. + * \return \c NULL if there are multiple depths for given type, + * the caller should fallback to hwloc_get_obj_inside_cpuset_by_depth(). + * + * \note Objects with empty CPU sets are ignored + * (otherwise they would be considered included in any given set). + * + * \note This function cannot work if objects of the given type do + * not have CPU sets (I/O or Misc objects). + */ +static __hwloc_inline hwloc_obj_t +hwloc_get_obj_inside_cpuset_by_type (hwloc_topology_t topology, hwloc_const_cpuset_t set, + hwloc_obj_type_t type, unsigned idx) __hwloc_attribute_pure; +static __hwloc_inline hwloc_obj_t +hwloc_get_obj_inside_cpuset_by_type (hwloc_topology_t topology, hwloc_const_cpuset_t set, + hwloc_obj_type_t type, unsigned idx) +{ + int depth = hwloc_get_type_depth(topology, type); + if (depth == HWLOC_TYPE_DEPTH_UNKNOWN || depth == HWLOC_TYPE_DEPTH_MULTIPLE) + return NULL; + return hwloc_get_obj_inside_cpuset_by_depth(topology, set, depth, idx); +} + +/** \brief Return the number of objects at depth \p depth included in CPU set \p set. + * + * \return the number of objects. + * \return 0 if the depth is invalid. + * + * \note Objects with empty CPU sets are ignored + * (otherwise they would be considered included in any given set). + * + * \note This function cannot work if objects at the given depth do + * not have CPU sets (I/O or Misc objects). + */ +static __hwloc_inline unsigned +hwloc_get_nbobjs_inside_cpuset_by_depth (hwloc_topology_t topology, hwloc_const_cpuset_t set, + int depth) __hwloc_attribute_pure; +static __hwloc_inline unsigned +hwloc_get_nbobjs_inside_cpuset_by_depth (hwloc_topology_t topology, hwloc_const_cpuset_t set, + int depth) +{ + hwloc_obj_t obj = hwloc_get_obj_by_depth (topology, depth, 0); + unsigned count = 0; + if (!obj) + return 0; + while (obj) { + if (!hwloc_bitmap_iszero(obj->cpuset) && hwloc_bitmap_isincluded(obj->cpuset, set)) + count++; + obj = obj->next_cousin; + } + return count; +} + +/** \brief Return the number of objects of type \p type included in CPU set \p set. + * + * \return the number of objects. + * \return 0 if there are no objects of that type in the topology. + * \return -1 if there are multiple levels of objects of that type, + * the caller should fallback to hwloc_get_nbobjs_inside_cpuset_by_depth(). + * + * \note Objects with empty CPU sets are ignored + * (otherwise they would be considered included in any given set). + * + * \note This function cannot work if objects of the given type do + * not have CPU sets (I/O objects). + */ +static __hwloc_inline int +hwloc_get_nbobjs_inside_cpuset_by_type (hwloc_topology_t topology, hwloc_const_cpuset_t set, + hwloc_obj_type_t type) __hwloc_attribute_pure; +static __hwloc_inline int +hwloc_get_nbobjs_inside_cpuset_by_type (hwloc_topology_t topology, hwloc_const_cpuset_t set, + hwloc_obj_type_t type) +{ + int depth = hwloc_get_type_depth(topology, type); + if (depth == HWLOC_TYPE_DEPTH_UNKNOWN) + return 0; + if (depth == HWLOC_TYPE_DEPTH_MULTIPLE) + return -1; /* FIXME: agregate nbobjs from different levels? */ + return (int) hwloc_get_nbobjs_inside_cpuset_by_depth(topology, set, depth); +} + +/** \brief Return the logical index among the objects included in CPU set \p set. + * + * Consult all objects in the same level as \p obj and inside CPU set \p set + * in the logical order, and return the index of \p obj within them. + * If \p set covers the entire topology, this is the logical index of \p obj. + * Otherwise, this is similar to a logical index within the part of the topology + * defined by CPU set \p set. + * + * \return the logical index among the objects included in the set if any. + * \return -1 if the object is not included in the set. + * + * \note Objects with empty CPU sets are ignored + * (otherwise they would be considered included in any given set). + * + * \note This function cannot work if obj does not have CPU sets (I/O objects). + */ +static __hwloc_inline int +hwloc_get_obj_index_inside_cpuset (hwloc_topology_t topology __hwloc_attribute_unused, hwloc_const_cpuset_t set, + hwloc_obj_t obj) __hwloc_attribute_pure; +static __hwloc_inline int +hwloc_get_obj_index_inside_cpuset (hwloc_topology_t topology __hwloc_attribute_unused, hwloc_const_cpuset_t set, + hwloc_obj_t obj) +{ + int idx = 0; + if (!hwloc_bitmap_isincluded(obj->cpuset, set)) + return -1; + /* count how many objects are inside the cpuset on the way from us to the beginning of the level */ + while ((obj = obj->prev_cousin) != NULL) + if (!hwloc_bitmap_iszero(obj->cpuset) && hwloc_bitmap_isincluded(obj->cpuset, set)) + idx++; + return idx; +} + +/** @} */ + + + +/** \defgroup hwlocality_helper_find_covering Finding Objects covering at least CPU set + * @{ + */ + +/** \brief Get the child covering at least CPU set \p set. + * + * \return the child that covers the set entirely. + * \return \c NULL if no child matches or if \p set is empty. + * + * \note This function cannot work if parent does not have a CPU set (I/O or Misc objects). + */ +static __hwloc_inline hwloc_obj_t +hwloc_get_child_covering_cpuset (hwloc_topology_t topology __hwloc_attribute_unused, hwloc_const_cpuset_t set, + hwloc_obj_t parent) __hwloc_attribute_pure; +static __hwloc_inline hwloc_obj_t +hwloc_get_child_covering_cpuset (hwloc_topology_t topology __hwloc_attribute_unused, hwloc_const_cpuset_t set, + hwloc_obj_t parent) +{ + hwloc_obj_t child; + if (hwloc_bitmap_iszero(set)) + return NULL; + child = parent->first_child; + while (child) { + if (child->cpuset && hwloc_bitmap_isincluded(set, child->cpuset)) + return child; + child = child->next_sibling; + } + return NULL; +} + +/** \brief Get the lowest object covering at least CPU set \p set + * + * \return the lowest object covering the set entirely. + * \return \c NULL if no object matches or if \p set is empty. + */ +static __hwloc_inline hwloc_obj_t +hwloc_get_obj_covering_cpuset (hwloc_topology_t topology, hwloc_const_cpuset_t set) __hwloc_attribute_pure; +static __hwloc_inline hwloc_obj_t +hwloc_get_obj_covering_cpuset (hwloc_topology_t topology, hwloc_const_cpuset_t set) +{ + struct hwloc_obj *current = hwloc_get_root_obj(topology); + if (hwloc_bitmap_iszero(set) || !hwloc_bitmap_isincluded(set, current->cpuset)) + return NULL; + while (1) { + hwloc_obj_t child = hwloc_get_child_covering_cpuset(topology, set, current); + if (!child) + return current; + current = child; + } +} + +/** \brief Iterate through same-depth objects covering at least CPU set \p set + * + * The next invokation should pass the previous return value in \p prev so as + * to obtain the next object covering at least another part of \p set. + * + * \return the first object at depth \p depth covering at least part of CPU set \p set + * if object \p prev is \c NULL. + * \return the next one if \p prev is not \c NULL. + * \return \c NULL if there is no next object. + * + * \note This function cannot work if objects at the given depth do + * not have CPU sets (I/O or Misc objects). + */ +static __hwloc_inline hwloc_obj_t +hwloc_get_next_obj_covering_cpuset_by_depth(hwloc_topology_t topology, hwloc_const_cpuset_t set, + int depth, hwloc_obj_t prev) +{ + hwloc_obj_t next = hwloc_get_next_obj_by_depth(topology, depth, prev); + if (!next) + return NULL; + while (next && !hwloc_bitmap_intersects(set, next->cpuset)) + next = next->next_cousin; + return next; +} + +/** \brief Iterate through same-type objects covering at least CPU set \p set + * + * The next invokation should pass the previous return value in \p prev so as to obtain + * the next object of type \p type covering at least another part of \p set. + * + * \return the first object of type \p type covering at least part of CPU set \p set + * if object \p prev is \c NULL. + * \return the next one if \p prev is not \c NULL. + * \return \c NULL if there is no next object. + * \return \c NULL if there is no depth for the given type. + * \return \c NULL if there are multiple depths for the given type, + * the caller should fallback to hwloc_get_next_obj_covering_cpuset_by_depth(). + * + * \note This function cannot work if objects of the given type do + * not have CPU sets (I/O or Misc objects). + */ +static __hwloc_inline hwloc_obj_t +hwloc_get_next_obj_covering_cpuset_by_type(hwloc_topology_t topology, hwloc_const_cpuset_t set, + hwloc_obj_type_t type, hwloc_obj_t prev) +{ + int depth = hwloc_get_type_depth(topology, type); + if (depth == HWLOC_TYPE_DEPTH_UNKNOWN || depth == HWLOC_TYPE_DEPTH_MULTIPLE) + return NULL; + return hwloc_get_next_obj_covering_cpuset_by_depth(topology, set, depth, prev); +} + +/** @} */ + + + +/** \defgroup hwlocality_helper_ancestors Looking at Ancestor and Child Objects + * @{ + * + * Be sure to see the figure in \ref termsanddefs that shows a + * complete topology tree, including depths, child/sibling/cousin + * relationships, and an example of an asymmetric topology where one + * package has fewer caches than its peers. + */ + +/** \brief Returns the ancestor object of \p obj at depth \p depth. + * + * \return the ancestor if any. + * \return \c NULL if no such ancestor exists. + * + * \note \p depth should not be the depth of PU or NUMA objects + * since they are ancestors of no objects (except Misc or I/O). + * This function rather expects an intermediate level depth, + * such as the depth of Packages, Cores, or Caches. + */ +static __hwloc_inline hwloc_obj_t +hwloc_get_ancestor_obj_by_depth (hwloc_topology_t topology __hwloc_attribute_unused, int depth, hwloc_obj_t obj) __hwloc_attribute_pure; +static __hwloc_inline hwloc_obj_t +hwloc_get_ancestor_obj_by_depth (hwloc_topology_t topology __hwloc_attribute_unused, int depth, hwloc_obj_t obj) +{ + hwloc_obj_t ancestor = obj; + if (obj->depth < depth) + return NULL; + while (ancestor && ancestor->depth > depth) + ancestor = ancestor->parent; + return ancestor; +} + +/** \brief Returns the ancestor object of \p obj with type \p type. + * + * \return the ancestor if any. + * \return \c NULL if no such ancestor exists. + * + * \note if multiple matching ancestors exist (e.g. multiple levels of ::HWLOC_OBJ_GROUP) + * the lowest one is returned. + * + * \note \p type should not be ::HWLOC_OBJ_PU or ::HWLOC_OBJ_NUMANODE + * since these objects are ancestors of no objects (except Misc or I/O). + * This function rather expects an intermediate object type, + * such as ::HWLOC_OBJ_PACKAGE, ::HWLOC_OBJ_CORE, etc. + */ +static __hwloc_inline hwloc_obj_t +hwloc_get_ancestor_obj_by_type (hwloc_topology_t topology __hwloc_attribute_unused, hwloc_obj_type_t type, hwloc_obj_t obj) __hwloc_attribute_pure; +static __hwloc_inline hwloc_obj_t +hwloc_get_ancestor_obj_by_type (hwloc_topology_t topology __hwloc_attribute_unused, hwloc_obj_type_t type, hwloc_obj_t obj) +{ + hwloc_obj_t ancestor = obj->parent; + while (ancestor && ancestor->type != type) + ancestor = ancestor->parent; + return ancestor; +} + +/** \brief Returns the common parent object to objects \p obj1 and \p obj2. + * + * \return the common ancestor. + * + * \note This function cannot return \c NULL. + */ +static __hwloc_inline hwloc_obj_t +hwloc_get_common_ancestor_obj (hwloc_topology_t topology __hwloc_attribute_unused, hwloc_obj_t obj1, hwloc_obj_t obj2) __hwloc_attribute_pure; +static __hwloc_inline hwloc_obj_t +hwloc_get_common_ancestor_obj (hwloc_topology_t topology __hwloc_attribute_unused, hwloc_obj_t obj1, hwloc_obj_t obj2) +{ + /* the loop isn't so easy since intermediate ancestors may have + * different depth, causing us to alternate between using obj1->parent + * and obj2->parent. Also, even if at some point we find ancestors of + * of the same depth, their ancestors may have different depth again. + */ + while (obj1 != obj2) { + while (obj1->depth > obj2->depth) + obj1 = obj1->parent; + while (obj2->depth > obj1->depth) + obj2 = obj2->parent; + if (obj1 != obj2 && obj1->depth == obj2->depth) { + obj1 = obj1->parent; + obj2 = obj2->parent; + } + } + return obj1; +} + +/** \brief Returns true if \p obj is inside the subtree beginning with ancestor object \p subtree_root. + * + * \return 1 is the object is in the subtree, 0 otherwise. + * + * \note This function cannot work if \p obj and \p subtree_root objects do + * not have CPU sets (I/O or Misc objects). + */ +static __hwloc_inline int +hwloc_obj_is_in_subtree (hwloc_topology_t topology __hwloc_attribute_unused, hwloc_obj_t obj, hwloc_obj_t subtree_root) __hwloc_attribute_pure; +static __hwloc_inline int +hwloc_obj_is_in_subtree (hwloc_topology_t topology __hwloc_attribute_unused, hwloc_obj_t obj, hwloc_obj_t subtree_root) +{ + return obj->cpuset && subtree_root->cpuset && hwloc_bitmap_isincluded(obj->cpuset, subtree_root->cpuset); +} + +/** \brief Return the next child. + * + * Return the next child among the normal children list, + * then among the memory children list, then among the I/O + * children list, then among the Misc children list. + * + * \return the first child if \p prev is \c NULL. + * \return the next child if \p prev is not \c NULL. + * \return \c NULL when there is no next child. + */ +static __hwloc_inline hwloc_obj_t +hwloc_get_next_child (hwloc_topology_t topology __hwloc_attribute_unused, hwloc_obj_t parent, hwloc_obj_t prev) +{ + hwloc_obj_t obj; + int state = 0; + if (prev) { + if (prev->type == HWLOC_OBJ_MISC) + state = 3; + else if (hwloc_obj_type_is_io(prev->type)) + state = 2; + else if (hwloc_obj_type_is_memory(prev->type)) + state = 1; + obj = prev->next_sibling; + } else { + obj = parent->first_child; + } + if (!obj && state == 0) { + obj = parent->memory_first_child; + state = 1; + } + if (!obj && state == 1) { + obj = parent->io_first_child; + state = 2; + } + if (!obj && state == 2) { + obj = parent->misc_first_child; + state = 3; + } + return obj; +} + +/** @} */ + + + +/** \defgroup hwlocality_helper_find_cache Looking at Cache Objects + * @{ + */ + +/** \brief Find the depth of cache objects matching cache level and type. + * + * Return the depth of the topology level that contains cache objects + * whose attributes match \p cachelevel and \p cachetype. + + * This function is identical to calling hwloc_get_type_depth() with the + * corresponding type such as ::HWLOC_OBJ_L1ICACHE, except that it may + * also return a Unified cache when looking for an instruction cache. + * + * \return the depth of the unique matching unified cache level is returned + * if \p cachetype is ::HWLOC_OBJ_CACHE_UNIFIED. + * + * \return the depth of either a matching cache level or a unified cache level + * if \p cachetype is ::HWLOC_OBJ_CACHE_DATA or ::HWLOC_OBJ_CACHE_INSTRUCTION. + * + * \return the depth of the matching level + * if \p cachetype is \c -1 but only one level matches. + * + * \return ::HWLOC_TYPE_DEPTH_MULTIPLE + * if \p cachetype is \c -1 but multiple levels match. + * + * \return ::HWLOC_TYPE_DEPTH_UNKNOWN if no cache level matches. + */ +static __hwloc_inline int +hwloc_get_cache_type_depth (hwloc_topology_t topology, + unsigned cachelevel, hwloc_obj_cache_type_t cachetype) +{ + int depth; + int found = HWLOC_TYPE_DEPTH_UNKNOWN; + for (depth=0; ; depth++) { + hwloc_obj_t obj = hwloc_get_obj_by_depth(topology, depth, 0); + if (!obj) + break; + if (!hwloc_obj_type_is_dcache(obj->type) || obj->attr->cache.depth != cachelevel) + /* doesn't match, try next depth */ + continue; + if (cachetype == (hwloc_obj_cache_type_t) -1) { + if (found != HWLOC_TYPE_DEPTH_UNKNOWN) { + /* second match, return MULTIPLE */ + return HWLOC_TYPE_DEPTH_MULTIPLE; + } + /* first match, mark it as found */ + found = depth; + continue; + } + if (obj->attr->cache.type == cachetype || obj->attr->cache.type == HWLOC_OBJ_CACHE_UNIFIED) + /* exact match (either unified is alone, or we match instruction or data), return immediately */ + return depth; + } + /* went to the bottom, return what we found */ + return found; +} + +/** \brief Get the first data (or unified) cache covering a cpuset \p set + * + * \return a covering cache, or \c NULL if no cache matches. + */ +static __hwloc_inline hwloc_obj_t +hwloc_get_cache_covering_cpuset (hwloc_topology_t topology, hwloc_const_cpuset_t set) __hwloc_attribute_pure; +static __hwloc_inline hwloc_obj_t +hwloc_get_cache_covering_cpuset (hwloc_topology_t topology, hwloc_const_cpuset_t set) +{ + hwloc_obj_t current = hwloc_get_obj_covering_cpuset(topology, set); + while (current) { + if (hwloc_obj_type_is_dcache(current->type)) + return current; + current = current->parent; + } + return NULL; +} + +/** \brief Get the first data (or unified) cache shared between an object and somebody else. + * + * \return a shared cache. + * \return \c NULL if no cache matches or if an invalid object is given (e.g. I/O object). + */ +static __hwloc_inline hwloc_obj_t +hwloc_get_shared_cache_covering_obj (hwloc_topology_t topology __hwloc_attribute_unused, hwloc_obj_t obj) __hwloc_attribute_pure; +static __hwloc_inline hwloc_obj_t +hwloc_get_shared_cache_covering_obj (hwloc_topology_t topology __hwloc_attribute_unused, hwloc_obj_t obj) +{ + hwloc_obj_t current = obj->parent; + if (!obj->cpuset) + return NULL; + while (current) { + if (!hwloc_bitmap_isequal(current->cpuset, obj->cpuset) + && hwloc_obj_type_is_dcache(current->type)) + return current; + current = current->parent; + } + return NULL; +} + +/** @} */ + + + +/** \defgroup hwlocality_helper_find_misc Finding objects, miscellaneous helpers + * @{ + * + * Be sure to see the figure in \ref termsanddefs that shows a + * complete topology tree, including depths, child/sibling/cousin + * relationships, and an example of an asymmetric topology where one + * package has fewer caches than its peers. + */ + +/** \brief Remove simultaneous multithreading PUs from a CPU set. + * + * For each core in \p topology, if \p cpuset contains some PUs of that core, + * modify \p cpuset to only keep a single PU for that core. + * + * \p which specifies which PU will be kept. + * PU are considered in physical index order. + * If 0, for each core, the function keeps the first PU that was originally set in \p cpuset. + * + * If \p which is larger than the number of PUs in a core there were originally set in \p cpuset, + * no PU is kept for that core. + * + * \return 0. + * + * \note PUs that are not below a Core object are ignored + * (for instance if the topology does not contain any Core object). + * None of them is removed from \p cpuset. + */ +HWLOC_DECLSPEC int hwloc_bitmap_singlify_per_core(hwloc_topology_t topology, hwloc_bitmap_t cpuset, unsigned which); + +/** \brief Returns the object of type ::HWLOC_OBJ_PU with \p os_index. + * + * This function is useful for converting a CPU set into the PU + * objects it contains. + * When retrieving the current binding (e.g. with hwloc_get_cpubind()), + * one may iterate over the bits of the resulting CPU set with + * hwloc_bitmap_foreach_begin(), and find the corresponding PUs + * with this function. + * + * \return the PU object, or \c NULL if none matches. + */ +static __hwloc_inline hwloc_obj_t +hwloc_get_pu_obj_by_os_index(hwloc_topology_t topology, unsigned os_index) __hwloc_attribute_pure; +static __hwloc_inline hwloc_obj_t +hwloc_get_pu_obj_by_os_index(hwloc_topology_t topology, unsigned os_index) +{ + hwloc_obj_t obj = NULL; + while ((obj = hwloc_get_next_obj_by_type(topology, HWLOC_OBJ_PU, obj)) != NULL) + if (obj->os_index == os_index) + return obj; + return NULL; +} + +/** \brief Returns the object of type ::HWLOC_OBJ_NUMANODE with \p os_index. + * + * This function is useful for converting a nodeset into the NUMA node + * objects it contains. + * When retrieving the current binding (e.g. with hwloc_get_membind() with HWLOC_MEMBIND_BYNODESET), + * one may iterate over the bits of the resulting nodeset with + * hwloc_bitmap_foreach_begin(), and find the corresponding NUMA nodes + * with this function. + * + * \return the NUMA node object, or \c NULL if none matches. + */ +static __hwloc_inline hwloc_obj_t +hwloc_get_numanode_obj_by_os_index(hwloc_topology_t topology, unsigned os_index) __hwloc_attribute_pure; +static __hwloc_inline hwloc_obj_t +hwloc_get_numanode_obj_by_os_index(hwloc_topology_t topology, unsigned os_index) +{ + hwloc_obj_t obj = NULL; + while ((obj = hwloc_get_next_obj_by_type(topology, HWLOC_OBJ_NUMANODE, obj)) != NULL) + if (obj->os_index == os_index) + return obj; + return NULL; +} + +/** \brief Do a depth-first traversal of the topology to find and sort + * + * all objects that are at the same depth than \p src. + * Report in \p objs up to \p max physically closest ones to \p src. + * + * \return the number of objects returned in \p objs. + * + * \return 0 if \p src is an I/O object. + * + * \note This function requires the \p src object to have a CPU set. + */ +/* TODO: rather provide an iterator? Provide a way to know how much should be allocated? By returning the total number of objects instead? */ +HWLOC_DECLSPEC unsigned hwloc_get_closest_objs (hwloc_topology_t topology, hwloc_obj_t src, hwloc_obj_t * __hwloc_restrict objs, unsigned max); + +/** \brief Find an object below another object, both specified by types and indexes. + * + * Start from the top system object and find object of type \p type1 + * and logical index \p idx1. Then look below this object and find another + * object of type \p type2 and logical index \p idx2. Indexes are specified + * within the parent, not withing the entire system. + * + * For instance, if type1 is PACKAGE, idx1 is 2, type2 is CORE and idx2 + * is 3, return the fourth core object below the third package. + * + * \return a matching object if any, \c NULL otherwise. + * + * \note This function requires these objects to have a CPU set. + */ +static __hwloc_inline hwloc_obj_t +hwloc_get_obj_below_by_type (hwloc_topology_t topology, + hwloc_obj_type_t type1, unsigned idx1, + hwloc_obj_type_t type2, unsigned idx2) __hwloc_attribute_pure; +static __hwloc_inline hwloc_obj_t +hwloc_get_obj_below_by_type (hwloc_topology_t topology, + hwloc_obj_type_t type1, unsigned idx1, + hwloc_obj_type_t type2, unsigned idx2) +{ + hwloc_obj_t obj; + obj = hwloc_get_obj_by_type (topology, type1, idx1); + if (!obj) + return NULL; + return hwloc_get_obj_inside_cpuset_by_type(topology, obj->cpuset, type2, idx2); +} + +/** \brief Find an object below a chain of objects specified by types and indexes. + * + * This is a generalized version of hwloc_get_obj_below_by_type(). + * + * Arrays \p typev and \p idxv must contain \p nr types and indexes. + * + * Start from the top system object and walk the arrays \p typev and \p idxv. + * For each type and logical index couple in the arrays, look under the previously found + * object to find the index-th object of the given type. + * Indexes are specified within the parent, not withing the entire system. + * + * For instance, if nr is 3, typev contains NODE, PACKAGE and CORE, + * and idxv contains 0, 1 and 2, return the third core object below + * the second package below the first NUMA node. + * + * \return a matching object if any, \c NULL otherwise. + * + * \note This function requires all these objects and the root object + * to have a CPU set. + */ +static __hwloc_inline hwloc_obj_t +hwloc_get_obj_below_array_by_type (hwloc_topology_t topology, int nr, hwloc_obj_type_t *typev, unsigned *idxv) __hwloc_attribute_pure; +static __hwloc_inline hwloc_obj_t +hwloc_get_obj_below_array_by_type (hwloc_topology_t topology, int nr, hwloc_obj_type_t *typev, unsigned *idxv) +{ + hwloc_obj_t obj = hwloc_get_root_obj(topology); + int i; + for(i=0; icpuset, typev[i], idxv[i]); + } + return obj; +} + +/** \brief Return an object of a different type with same locality. + * + * If the source object \p src is a normal or memory type, + * this function returns an object of type \p type with same + * CPU and node sets, either below or above in the hierarchy. + * + * If the source object \p src is a PCI or an OS device within a PCI + * device, the function may either return that PCI device, or another + * OS device in the same PCI parent. + * This may for instance be useful for converting between OS devices + * such as "nvml0" or "rsmi1" used in distance structures into the + * the PCI device, or the CUDA or OpenCL OS device that correspond + * to the same physical card. + * + * If not \c NULL, parameter \p subtype only select objects whose + * subtype attribute exists and is \p subtype (case-insensitively), + * for instance "OpenCL" or "CUDA". + * + * If not \c NULL, parameter \p nameprefix only selects objects whose + * name attribute exists and starts with \p nameprefix (case-insensitively), + * for instance "rsmi" for matching "rsmi0". + * + * If multiple objects match, the first one is returned. + * + * This function will not walk the hierarchy across bridges since + * the PCI locality may become different. + * This function cannot also convert between normal/memory objects + * and I/O or Misc objects. + * + * \p flags must be \c 0 for now. + * + * \return An object with identical locality, + * matching \p subtype and \p nameprefix if any. + * + * \return \c NULL if no matching object could be found, + * or if the source object and target type are incompatible, + * for instance if converting between CPU and I/O objects. + */ +HWLOC_DECLSPEC hwloc_obj_t +hwloc_get_obj_with_same_locality(hwloc_topology_t topology, hwloc_obj_t src, + hwloc_obj_type_t type, const char *subtype, const char *nameprefix, + unsigned long flags); + +/** @} */ + + + +/** \defgroup hwlocality_helper_distribute Distributing items over a topology + * @{ + */ + +/** \brief Flags to be given to hwloc_distrib(). + */ +enum hwloc_distrib_flags_e { + /** \brief Distrib in reverse order, starting from the last objects. + * \hideinitializer + */ + HWLOC_DISTRIB_FLAG_REVERSE = (1UL<<0) +}; + +/** \brief Distribute \p n items over the topology under \p roots + * + * Array \p set will be filled with \p n cpusets recursively distributed + * linearly over the topology under objects \p roots, down to depth \p until + * (which can be INT_MAX to distribute down to the finest level). + * + * \p n_roots is usually 1 and \p roots only contains the topology root object + * so as to distribute over the entire topology. + * + * This is typically useful when an application wants to distribute \p n + * threads over a machine, giving each of them as much private cache as + * possible and keeping them locally in number order. + * + * The caller may typically want to also call hwloc_bitmap_singlify() + * before binding a thread so that it does not move at all. + * + * \p flags should be 0 or a OR'ed set of ::hwloc_distrib_flags_e. + * + * \return 0 on success, -1 on error. + * + * \note On hybrid CPUs (or asymmetric platforms), distribution may be suboptimal + * since the number of cores or PUs inside packages or below caches may vary + * (the top-down recursive partitioning ignores these numbers until reaching their levels). + * Hence it is recommended to distribute only inside a single homogeneous domain. + * For instance on a CPU with energy-efficient E-cores and high-performance P-cores, + * one should distribute separately N tasks on E-cores and M tasks on P-cores + * instead of trying to distribute directly M+N tasks on the entire CPUs. + * + * \note This function requires the \p roots objects to have a CPU set. + */ +static __hwloc_inline int +hwloc_distrib(hwloc_topology_t topology, + hwloc_obj_t *roots, unsigned n_roots, + hwloc_cpuset_t *set, + unsigned n, + int until, unsigned long flags) +{ + unsigned i; + unsigned tot_weight; + unsigned given, givenweight; + hwloc_cpuset_t *cpusetp = set; + + if (!n || (flags & ~HWLOC_DISTRIB_FLAG_REVERSE)) { + errno = EINVAL; + return -1; + } + + tot_weight = 0; + for (i = 0; i < n_roots; i++) + tot_weight += (unsigned) hwloc_bitmap_weight(roots[i]->cpuset); + + for (i = 0, given = 0, givenweight = 0; i < n_roots; i++) { + unsigned chunk, weight; + hwloc_obj_t root = roots[flags & HWLOC_DISTRIB_FLAG_REVERSE ? n_roots-1-i : i]; + hwloc_cpuset_t cpuset = root->cpuset; + while (!hwloc_obj_type_is_normal(root->type)) + /* If memory/io/misc, walk up to normal parent */ + root = root->parent; + weight = (unsigned) hwloc_bitmap_weight(cpuset); + if (!weight) + continue; + /* Give to root a chunk proportional to its weight. + * If previous chunks got rounded-up, we may get a bit less. */ + chunk = (( (givenweight+weight) * n + tot_weight-1) / tot_weight) + - (( givenweight * n + tot_weight-1) / tot_weight); + if (!root->arity || chunk <= 1 || root->depth >= until) { + /* We can't split any more, put everything there. */ + if (chunk) { + /* Fill cpusets with ours */ + unsigned j; + for (j=0; j < chunk; j++) + cpusetp[j] = hwloc_bitmap_dup(cpuset); + } else { + /* We got no chunk, just merge our cpuset to a previous one + * (the first chunk cannot be empty) + * so that this root doesn't get ignored. + */ + assert(given); + hwloc_bitmap_or(cpusetp[-1], cpusetp[-1], cpuset); + } + } else { + /* Still more to distribute, recurse into children */ + hwloc_distrib(topology, root->children, root->arity, cpusetp, chunk, until, flags); + } + cpusetp += chunk; + given += chunk; + givenweight += weight; + } + + return 0; +} + +/** @} */ + + + +/** \defgroup hwlocality_helper_topology_sets CPU and node sets of entire topologies + * @{ + */ + +/** \brief Get complete CPU set + * + * \return the complete CPU set of processors of the system. + * + * \note This function cannot return \c NULL. + * + * \note The returned cpuset is not newly allocated and should thus not be + * changed or freed; hwloc_bitmap_dup() must be used to obtain a local copy. + * + * \note This is equivalent to retrieving the root object complete CPU-set. + */ +HWLOC_DECLSPEC hwloc_const_cpuset_t +hwloc_topology_get_complete_cpuset(hwloc_topology_t topology) __hwloc_attribute_pure; + +/** \brief Get topology CPU set + * + * \return the CPU set of processors of the system for which hwloc + * provides topology information. This is equivalent to the cpuset of the + * system object. + * + * \note This function cannot return \c NULL. + * + * \note The returned cpuset is not newly allocated and should thus not be + * changed or freed; hwloc_bitmap_dup() must be used to obtain a local copy. + * + * \note This is equivalent to retrieving the root object CPU-set. + */ +HWLOC_DECLSPEC hwloc_const_cpuset_t +hwloc_topology_get_topology_cpuset(hwloc_topology_t topology) __hwloc_attribute_pure; + +/** \brief Get allowed CPU set + * + * \return the CPU set of allowed processors of the system. + * + * \note This function cannot return \c NULL. + * + * \note If the topology flag ::HWLOC_TOPOLOGY_FLAG_INCLUDE_DISALLOWED was not set, + * this is identical to hwloc_topology_get_topology_cpuset(), which means + * all PUs are allowed. + * + * \note If ::HWLOC_TOPOLOGY_FLAG_INCLUDE_DISALLOWED was set, applying + * hwloc_bitmap_intersects() on the result of this function and on an object + * cpuset checks whether there are allowed PUs inside that object. + * Applying hwloc_bitmap_and() returns the list of these allowed PUs. + * + * \note The returned cpuset is not newly allocated and should thus not be + * changed or freed, hwloc_bitmap_dup() must be used to obtain a local copy. + */ +HWLOC_DECLSPEC hwloc_const_cpuset_t +hwloc_topology_get_allowed_cpuset(hwloc_topology_t topology) __hwloc_attribute_pure; + +/** \brief Get complete node set + * + * \return the complete node set of memory of the system. + * + * \note This function cannot return \c NULL. + * + * \note The returned nodeset is not newly allocated and should thus not be + * changed or freed; hwloc_bitmap_dup() must be used to obtain a local copy. + * + * \note This is equivalent to retrieving the root object complete nodeset. + */ +HWLOC_DECLSPEC hwloc_const_nodeset_t +hwloc_topology_get_complete_nodeset(hwloc_topology_t topology) __hwloc_attribute_pure; + +/** \brief Get topology node set + * + * \return the node set of memory of the system for which hwloc + * provides topology information. This is equivalent to the nodeset of the + * system object. + * + * \note This function cannot return \c NULL. + * + * \note The returned nodeset is not newly allocated and should thus not be + * changed or freed; hwloc_bitmap_dup() must be used to obtain a local copy. + * + * \note This is equivalent to retrieving the root object nodeset. + */ +HWLOC_DECLSPEC hwloc_const_nodeset_t +hwloc_topology_get_topology_nodeset(hwloc_topology_t topology) __hwloc_attribute_pure; + +/** \brief Get allowed node set + * + * \return the node set of allowed memory of the system. + * + * \note This function cannot return \c NULL. + * + * \note If the topology flag ::HWLOC_TOPOLOGY_FLAG_INCLUDE_DISALLOWED was not set, + * this is identical to hwloc_topology_get_topology_nodeset(), which means + * all NUMA nodes are allowed. + * + * \note If ::HWLOC_TOPOLOGY_FLAG_INCLUDE_DISALLOWED was set, applying + * hwloc_bitmap_intersects() on the result of this function and on an object + * nodeset checks whether there are allowed NUMA nodes inside that object. + * Applying hwloc_bitmap_and() returns the list of these allowed NUMA nodes. + * + * \note The returned nodeset is not newly allocated and should thus not be + * changed or freed, hwloc_bitmap_dup() must be used to obtain a local copy. + */ +HWLOC_DECLSPEC hwloc_const_nodeset_t +hwloc_topology_get_allowed_nodeset(hwloc_topology_t topology) __hwloc_attribute_pure; + +/** @} */ + + + +/** \defgroup hwlocality_helper_nodeset_convert Converting between CPU sets and node sets + * + * @{ + */ + +/** \brief Convert a CPU set into a NUMA node set + * + * For each PU included in the input \p _cpuset, set the corresponding + * local NUMA node(s) in the output \p nodeset. + * + * If some NUMA nodes have no CPUs at all, this function never sets their + * indexes in the output node set, even if a full CPU set is given in input. + * + * Hence the entire topology CPU set is converted into the set of all nodes + * that have some local CPUs. + * + * \return 0 on success. + * \return -1 with errno set to \c ENOMEM on internal reallocation failure. + */ +static __hwloc_inline int +hwloc_cpuset_to_nodeset(hwloc_topology_t topology, hwloc_const_cpuset_t _cpuset, hwloc_nodeset_t nodeset) +{ + int depth = hwloc_get_type_depth(topology, HWLOC_OBJ_NUMANODE); + hwloc_obj_t obj = NULL; + assert(depth != HWLOC_TYPE_DEPTH_UNKNOWN); + hwloc_bitmap_zero(nodeset); + while ((obj = hwloc_get_next_obj_covering_cpuset_by_depth(topology, _cpuset, depth, obj)) != NULL) + if (hwloc_bitmap_set(nodeset, obj->os_index) < 0) + return -1; + return 0; +} + +/** \brief Convert a NUMA node set into a CPU set + * + * For each NUMA node included in the input \p nodeset, set the corresponding + * local PUs in the output \p _cpuset. + * + * If some CPUs have no local NUMA nodes, this function never sets their + * indexes in the output CPU set, even if a full node set is given in input. + * + * Hence the entire topology node set is converted into the set of all CPUs + * that have some local NUMA nodes. + * + * \return 0 on success. + * \return -1 with errno set to \c ENOMEM on internal reallocation failure. + */ +static __hwloc_inline int +hwloc_cpuset_from_nodeset(hwloc_topology_t topology, hwloc_cpuset_t _cpuset, hwloc_const_nodeset_t nodeset) +{ + int depth = hwloc_get_type_depth(topology, HWLOC_OBJ_NUMANODE); + hwloc_obj_t obj = NULL; + assert(depth != HWLOC_TYPE_DEPTH_UNKNOWN); + hwloc_bitmap_zero(_cpuset); + while ((obj = hwloc_get_next_obj_by_depth(topology, depth, obj)) != NULL) { + if (hwloc_bitmap_isset(nodeset, obj->os_index)) + /* no need to check obj->cpuset because objects in levels always have a cpuset */ + if (hwloc_bitmap_or(_cpuset, _cpuset, obj->cpuset) < 0) + return -1; + } + return 0; +} + +/** @} */ + + + +/** \defgroup hwlocality_advanced_io Finding I/O objects + * @{ + */ + +/** \brief Get the first non-I/O ancestor object. + * + * Given the I/O object \p ioobj, find the smallest non-I/O ancestor + * object. This object (normal or memory) may then be used for binding + * because it has non-NULL CPU and node sets + * and because its locality is the same as \p ioobj. + * + * \return a non-I/O object. + * + * \note This function cannot return \c NULL. + * + * \note The resulting object is usually a normal object but it could also + * be a memory object (e.g. NUMA node) in future platforms if I/O objects + * ever get attached to memory instead of CPUs. + */ +static __hwloc_inline hwloc_obj_t +hwloc_get_non_io_ancestor_obj(hwloc_topology_t topology __hwloc_attribute_unused, + hwloc_obj_t ioobj) +{ + hwloc_obj_t obj = ioobj; + while (obj && !obj->cpuset) { + obj = obj->parent; + } + return obj; +} + +/** \brief Get the next PCI device in the system. + * + * \return the first PCI device if \p prev is \c NULL. + * \return the next PCI device if \p prev is not \c NULL. + * \return \c NULL if there is no next PCI device. + */ +static __hwloc_inline hwloc_obj_t +hwloc_get_next_pcidev(hwloc_topology_t topology, hwloc_obj_t prev) +{ + return hwloc_get_next_obj_by_type(topology, HWLOC_OBJ_PCI_DEVICE, prev); +} + +/** \brief Find the PCI device object matching the PCI bus id + * given domain, bus device and function PCI bus id. + * + * \return a matching PCI device object if any, \c NULL otherwise. + */ +static __hwloc_inline hwloc_obj_t +hwloc_get_pcidev_by_busid(hwloc_topology_t topology, + unsigned domain, unsigned bus, unsigned dev, unsigned func) +{ + hwloc_obj_t obj = NULL; + while ((obj = hwloc_get_next_pcidev(topology, obj)) != NULL) { + if (obj->attr->pcidev.domain == domain + && obj->attr->pcidev.bus == bus + && obj->attr->pcidev.dev == dev + && obj->attr->pcidev.func == func) + return obj; + } + return NULL; +} + +/** \brief Find the PCI device object matching the PCI bus id + * given as a string xxxx:yy:zz.t or yy:zz.t. + * + * \return a matching PCI device object if any, \c NULL otherwise. + */ +static __hwloc_inline hwloc_obj_t +hwloc_get_pcidev_by_busidstring(hwloc_topology_t topology, const char *busid) +{ + unsigned domain = 0; /* default */ + unsigned bus, dev, func; + + if (sscanf(busid, "%x:%x.%x", &bus, &dev, &func) != 3 + && sscanf(busid, "%x:%x:%x.%x", &domain, &bus, &dev, &func) != 4) { + errno = EINVAL; + return NULL; + } + + return hwloc_get_pcidev_by_busid(topology, domain, bus, dev, func); +} + +/** \brief Get the next OS device in the system. + * + * \return the first OS device if \p prev is \c NULL. + * \return the next OS device if \p prev is not \c NULL. + * \return \c NULL if there is no next OS device. + */ +static __hwloc_inline hwloc_obj_t +hwloc_get_next_osdev(hwloc_topology_t topology, hwloc_obj_t prev) +{ + return hwloc_get_next_obj_by_type(topology, HWLOC_OBJ_OS_DEVICE, prev); +} + +/** \brief Get the next bridge in the system. + * + * \return the first bridge if \p prev is \c NULL. + * \return the next bridge if \p prev is not \c NULL. + * \return \c NULL if there is no next bridge. + */ +static __hwloc_inline hwloc_obj_t +hwloc_get_next_bridge(hwloc_topology_t topology, hwloc_obj_t prev) +{ + return hwloc_get_next_obj_by_type(topology, HWLOC_OBJ_BRIDGE, prev); +} + +/* \brief Checks whether a given bridge covers a given PCI bus. + * + * \return 1 if it covers, 0 if not. + */ +static __hwloc_inline int +hwloc_bridge_covers_pcibus(hwloc_obj_t bridge, + unsigned domain, unsigned bus) +{ + return bridge->type == HWLOC_OBJ_BRIDGE + && bridge->attr->bridge.downstream_type == HWLOC_OBJ_BRIDGE_PCI + && bridge->attr->bridge.downstream.pci.domain == domain + && bridge->attr->bridge.downstream.pci.secondary_bus <= bus + && bridge->attr->bridge.downstream.pci.subordinate_bus >= bus; +} + +/** @} */ + + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* HWLOC_HELPER_H */ diff --git a/src/deps/hwloc/include/hwloc/inlines.h b/src/deps/hwloc/include/hwloc/inlines.h new file mode 100644 index 000000000..0391f73b4 --- /dev/null +++ b/src/deps/hwloc/include/hwloc/inlines.h @@ -0,0 +1,147 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * Copyright © 2009 CNRS + * Copyright © 2009-2018 Inria. All rights reserved. + * Copyright © 2009-2012 Université Bordeaux + * Copyright © 2009-2010 Cisco Systems, Inc. All rights reserved. + * See COPYING in top-level directory. + */ + +/** + * This file contains the inline code of functions declared in hwloc.h + */ + +#ifndef HWLOC_INLINES_H +#define HWLOC_INLINES_H + +#ifndef HWLOC_H +#error Please include the main hwloc.h instead +#endif + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +static __hwloc_inline int +hwloc_get_type_or_below_depth (hwloc_topology_t topology, hwloc_obj_type_t type) +{ + int depth = hwloc_get_type_depth(topology, type); + + if (depth != HWLOC_TYPE_DEPTH_UNKNOWN) + return depth; + + /* find the highest existing level with type order >= */ + for(depth = hwloc_get_type_depth(topology, HWLOC_OBJ_PU); ; depth--) + if (hwloc_compare_types(hwloc_get_depth_type(topology, depth), type) < 0) + return depth+1; + + /* Shouldn't ever happen, as there is always a Machine level with lower order and known depth. */ + /* abort(); */ +} + +static __hwloc_inline int +hwloc_get_type_or_above_depth (hwloc_topology_t topology, hwloc_obj_type_t type) +{ + int depth = hwloc_get_type_depth(topology, type); + + if (depth != HWLOC_TYPE_DEPTH_UNKNOWN) + return depth; + + /* find the lowest existing level with type order <= */ + for(depth = 0; ; depth++) + if (hwloc_compare_types(hwloc_get_depth_type(topology, depth), type) > 0) + return depth-1; + + /* Shouldn't ever happen, as there is always a PU level with higher order and known depth. */ + /* abort(); */ +} + +static __hwloc_inline int +hwloc_get_nbobjs_by_type (hwloc_topology_t topology, hwloc_obj_type_t type) +{ + int depth = hwloc_get_type_depth(topology, type); + if (depth == HWLOC_TYPE_DEPTH_UNKNOWN) + return 0; + if (depth == HWLOC_TYPE_DEPTH_MULTIPLE) + return -1; /* FIXME: agregate nbobjs from different levels? */ + return (int) hwloc_get_nbobjs_by_depth(topology, depth); +} + +static __hwloc_inline hwloc_obj_t +hwloc_get_obj_by_type (hwloc_topology_t topology, hwloc_obj_type_t type, unsigned idx) +{ + int depth = hwloc_get_type_depth(topology, type); + if (depth == HWLOC_TYPE_DEPTH_UNKNOWN) + return NULL; + if (depth == HWLOC_TYPE_DEPTH_MULTIPLE) + return NULL; + return hwloc_get_obj_by_depth(topology, depth, idx); +} + +static __hwloc_inline hwloc_obj_t +hwloc_get_next_obj_by_depth (hwloc_topology_t topology, int depth, hwloc_obj_t prev) +{ + if (!prev) + return hwloc_get_obj_by_depth (topology, depth, 0); + if (prev->depth != depth) + return NULL; + return prev->next_cousin; +} + +static __hwloc_inline hwloc_obj_t +hwloc_get_next_obj_by_type (hwloc_topology_t topology, hwloc_obj_type_t type, + hwloc_obj_t prev) +{ + int depth = hwloc_get_type_depth(topology, type); + if (depth == HWLOC_TYPE_DEPTH_UNKNOWN || depth == HWLOC_TYPE_DEPTH_MULTIPLE) + return NULL; + return hwloc_get_next_obj_by_depth (topology, depth, prev); +} + +static __hwloc_inline hwloc_obj_t +hwloc_get_root_obj (hwloc_topology_t topology) +{ + return hwloc_get_obj_by_depth (topology, 0, 0); +} + +static __hwloc_inline const char * +hwloc_obj_get_info_by_name(hwloc_obj_t obj, const char *name) +{ + unsigned i; + for(i=0; iinfos_count; i++) { + struct hwloc_info_s *info = &obj->infos[i]; + if (!strcmp(info->name, name)) + return info->value; + } + return NULL; +} + +static __hwloc_inline void * +hwloc_alloc_membind_policy(hwloc_topology_t topology, size_t len, hwloc_const_cpuset_t set, hwloc_membind_policy_t policy, int flags) +{ + void *p = hwloc_alloc_membind(topology, len, set, policy, flags); + if (p) + return p; + + if (hwloc_set_membind(topology, set, policy, flags) < 0) + /* hwloc_set_membind() takes care of ignoring errors if non-STRICT */ + return NULL; + + p = hwloc_alloc(topology, len); + if (p && policy != HWLOC_MEMBIND_FIRSTTOUCH) + /* Enforce the binding by touching the data */ + memset(p, 0, len); + return p; +} + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* HWLOC_INLINES_H */ diff --git a/src/deps/hwloc/include/hwloc/levelzero.h b/src/deps/hwloc/include/hwloc/levelzero.h new file mode 100644 index 000000000..1a3f976fc --- /dev/null +++ b/src/deps/hwloc/include/hwloc/levelzero.h @@ -0,0 +1,299 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * Copyright © 2021-2024 Inria. All rights reserved. + * See COPYING in top-level directory. + */ + +/** \file + * \brief Macros to help interaction between hwloc and the oneAPI Level Zero interface. + * + * Applications that use both hwloc and Level Zero may want to + * include this file so as to get topology information for L0 devices. + */ + +#ifndef HWLOC_LEVELZERO_H +#define HWLOC_LEVELZERO_H + +#include "hwloc.h" +#include "hwloc/autogen/config.h" +#include "hwloc/helper.h" +#ifdef HWLOC_LINUX_SYS +#include "hwloc/linux.h" +#endif + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** \defgroup hwlocality_levelzero Interoperability with the oneAPI Level Zero interface. + * + * This interface offers ways to retrieve topology information about + * devices managed by the Level Zero API, both for main Core devices (ZE API) + * and the Sysman devices (ZES API). + * + * @{ + */ + +/** \brief Get the CPU set of logical processors that are physically + * close to the Level Zero device \p device + * + * Store in \p set the CPU-set describing the locality of + * the Level Zero device \p device. + * + * Topology \p topology and device \p device must match the local machine. + * The Level Zero library must have been initialized with zeInit(). + * I/O devices detection and the Level Zero component are not needed in the + * topology. + * + * The function only returns the locality of the device. + * If more information about the device is needed, OS objects should + * be used instead, see hwloc_levelzero_get_device_osdev(). + * + * This function is currently only implemented in a meaningful way for + * Linux; other systems will simply get a full cpuset. + * + * \return 0 on success. + * \return -1 on error, for instance if device information could not be found. + * + * \note zeDevicePciGetPropertiesExt() must be supported, or the entire machine + * locality will be returned. + */ +static __hwloc_inline int +hwloc_levelzero_get_device_cpuset(hwloc_topology_t topology __hwloc_attribute_unused, + ze_device_handle_t device, hwloc_cpuset_t set) +{ +#ifdef HWLOC_LINUX_SYS + /* If we're on Linux, use the sysfs mechanism to get the local cpus */ +#define HWLOC_LEVELZERO_DEVICE_SYSFS_PATH_MAX 128 + char path[HWLOC_LEVELZERO_DEVICE_SYSFS_PATH_MAX]; + ze_pci_ext_properties_t pci; + ze_result_t res; + + if (!hwloc_topology_is_thissystem(topology)) { + errno = EINVAL; + return -1; + } + + pci.stype = ZE_STRUCTURE_TYPE_PCI_EXT_PROPERTIES; + pci.pNext = NULL; + res = zeDevicePciGetPropertiesExt(device, &pci); + if (res != ZE_RESULT_SUCCESS) { + errno = EINVAL; + return -1; + } + + sprintf(path, "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/local_cpus", + pci.address.domain, pci.address.bus, pci.address.device, pci.address.function); + if (hwloc_linux_read_path_as_cpumask(path, set) < 0 + || hwloc_bitmap_iszero(set)) + hwloc_bitmap_copy(set, hwloc_topology_get_complete_cpuset(topology)); +#else + /* Non-Linux systems simply get a full cpuset */ + hwloc_bitmap_copy(set, hwloc_topology_get_complete_cpuset(topology)); +#endif + return 0; +} + +/** \brief Get the CPU set of logical processors that are physically + * close to the Level Zero Sysman device \p device + * + * Store in \p set the CPU-set describing the locality of + * the Level Zero device \p device. + * + * Topology \p topology and device \p device must match the local machine. + * The Level Zero library must have been initialized with Sysman enabled + * with zesInit(). + * I/O devices detection and the Level Zero component are not needed in the + * topology. + * + * The function only returns the locality of the device. + * If more information about the device is needed, OS objects should + * be used instead, see hwloc_levelzero_get_device_osdev(). + * + * This function is currently only implemented in a meaningful way for + * Linux; other systems will simply get a full cpuset. + * + * \return 0 on success. + * \return -1 on error, for instance if device information could not be found. + */ +static __hwloc_inline int +hwloc_levelzero_get_sysman_device_cpuset(hwloc_topology_t topology __hwloc_attribute_unused, + zes_device_handle_t device, hwloc_cpuset_t set) +{ +#ifdef HWLOC_LINUX_SYS + /* If we're on Linux, use the sysfs mechanism to get the local cpus */ +#define HWLOC_LEVELZERO_DEVICE_SYSFS_PATH_MAX 128 + char path[HWLOC_LEVELZERO_DEVICE_SYSFS_PATH_MAX]; + zes_pci_properties_t pci; + ze_result_t res; + + if (!hwloc_topology_is_thissystem(topology)) { + errno = EINVAL; + return -1; + } + + res = zesDevicePciGetProperties(device, &pci); + if (res != ZE_RESULT_SUCCESS) { + errno = EINVAL; + return -1; + } + + sprintf(path, "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/local_cpus", + pci.address.domain, pci.address.bus, pci.address.device, pci.address.function); + if (hwloc_linux_read_path_as_cpumask(path, set) < 0 + || hwloc_bitmap_iszero(set)) + hwloc_bitmap_copy(set, hwloc_topology_get_complete_cpuset(topology)); +#else + /* Non-Linux systems simply get a full cpuset */ + hwloc_bitmap_copy(set, hwloc_topology_get_complete_cpuset(topology)); +#endif + return 0; +} + +/** \brief Get the hwloc OS device object corresponding to Level Zero device + * \p device. + * + * \return The hwloc OS device object that describes the given Level Zero device \p device. + * \return \c NULL if none could be found. + * + * Topology \p topology and device \p dv_ind must match the local machine. + * The Level Zero library must have been initialized with zeInit(). + * I/O devices detection and the Level Zero component must be enabled in the + * topology. If not, the locality of the object may still be found using + * hwloc_levelzero_get_device_cpuset(). + * + * \note If the input ZE device is actually a subdevice, then its parent + * (root device) is actually translated, i.e. the main hwloc OS device + * is returned instead of one of its children. + * + * \note The corresponding hwloc PCI device may be found by looking + * at the result parent pointer (unless PCI devices are filtered out). + * + * \note zeDevicePciGetPropertiesExt() must be supported. + */ +static __hwloc_inline hwloc_obj_t +hwloc_levelzero_get_device_osdev(hwloc_topology_t topology, ze_device_handle_t device) +{ + ze_pci_ext_properties_t pci; + ze_result_t res; + hwloc_obj_t osdev; + + if (!hwloc_topology_is_thissystem(topology)) { + errno = EINVAL; + return NULL; + } + + pci.stype = ZE_STRUCTURE_TYPE_PCI_EXT_PROPERTIES; + pci.pNext = NULL; + res = zeDevicePciGetPropertiesExt(device, &pci); + if (res != ZE_RESULT_SUCCESS) { + errno = EINVAL; + return NULL; + } + + osdev = NULL; + while ((osdev = hwloc_get_next_osdev(topology, osdev)) != NULL) { + hwloc_obj_t pcidev; + + if (strncmp(osdev->name, "ze", 2)) + continue; + + pcidev = osdev; + while (pcidev && pcidev->type != HWLOC_OBJ_PCI_DEVICE) + pcidev = pcidev->parent; + if (!pcidev) + continue; + + if (pcidev + && pcidev->type == HWLOC_OBJ_PCI_DEVICE + && pcidev->attr->pcidev.domain == pci.address.domain + && pcidev->attr->pcidev.bus == pci.address.bus + && pcidev->attr->pcidev.dev == pci.address.device + && pcidev->attr->pcidev.func == pci.address.function) + return osdev; + + /* FIXME: when we'll have serialnumber, try it in case PCI is filtered-out */ + } + + return NULL; +} + +/** \brief Get the hwloc OS device object corresponding to Level Zero Sysman device + * \p device. + * + * \return The hwloc OS device object that describes the given Level Zero device \p device. + * \return \c NULL if none could be found. + * + * Topology \p topology and device \p dv_ind must match the local machine. + * The Level Zero library must have been initialized with Sysman enabled + * with zesInit(). + * I/O devices detection and the Level Zero component must be enabled in the + * topology. If not, the locality of the object may still be found using + * hwloc_levelzero_get_device_cpuset(). + * + * \note If the input ZES device is actually a subdevice, then its parent + * (root device) is actually translated, i.e. the main hwloc OS device + * is returned instead of one of its children. + * + * \note The corresponding hwloc PCI device may be found by looking + * at the result parent pointer (unless PCI devices are filtered out). + */ +static __hwloc_inline hwloc_obj_t +hwloc_levelzero_get_sysman_device_osdev(hwloc_topology_t topology, zes_device_handle_t device) +{ + zes_pci_properties_t pci; + ze_result_t res; + hwloc_obj_t osdev; + + if (!hwloc_topology_is_thissystem(topology)) { + errno = EINVAL; + return NULL; + } + + res = zesDevicePciGetProperties(device, &pci); + if (res != ZE_RESULT_SUCCESS) { + errno = EINVAL; + return NULL; + } + + osdev = NULL; + while ((osdev = hwloc_get_next_osdev(topology, osdev)) != NULL) { + hwloc_obj_t pcidev; + + if (strncmp(osdev->name, "ze", 2)) + continue; + + pcidev = osdev; + while (pcidev && pcidev->type != HWLOC_OBJ_PCI_DEVICE) + pcidev = pcidev->parent; + if (!pcidev) + continue; + + if (pcidev + && pcidev->type == HWLOC_OBJ_PCI_DEVICE + && pcidev->attr->pcidev.domain == pci.address.domain + && pcidev->attr->pcidev.bus == pci.address.bus + && pcidev->attr->pcidev.dev == pci.address.device + && pcidev->attr->pcidev.func == pci.address.function) + return osdev; + + /* FIXME: when we'll have serialnumber, try it in case PCI is filtered-out */ + } + + return NULL; +} + +/** @} */ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* HWLOC_LEVELZERO_H */ diff --git a/src/deps/hwloc/include/hwloc/linux-libnuma.h b/src/deps/hwloc/include/hwloc/linux-libnuma.h new file mode 100644 index 000000000..c470a6d1f --- /dev/null +++ b/src/deps/hwloc/include/hwloc/linux-libnuma.h @@ -0,0 +1,301 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * Copyright © 2009 CNRS + * Copyright © 2009-2023 Inria. All rights reserved. + * Copyright © 2009-2010, 2012 Université Bordeaux + * See COPYING in top-level directory. + */ + +/** \file + * \brief Macros to help interaction between hwloc and Linux libnuma. + * + * Applications that use both Linux libnuma and hwloc may want to + * include this file so as to ease conversion between their respective types. +*/ + +#ifndef HWLOC_LINUX_LIBNUMA_H +#define HWLOC_LINUX_LIBNUMA_H + +#include "hwloc.h" + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** \defgroup hwlocality_linux_libnuma_ulongs Interoperability with Linux libnuma unsigned long masks + * + * This interface helps converting between Linux libnuma unsigned long masks + * and hwloc cpusets and nodesets. + * + * \note Topology \p topology must match the current machine. + * + * \note The behavior of libnuma is undefined if the kernel is not NUMA-aware. + * (when CONFIG_NUMA is not set in the kernel configuration). + * This helper and libnuma may thus not be strictly compatible in this case, + * which may be detected by checking whether numa_available() returns -1. + * + * @{ + */ + + +/** \brief Convert hwloc CPU set \p cpuset into the array of unsigned long \p mask + * + * \p mask is the array of unsigned long that will be filled. + * \p maxnode contains the maximal node number that may be stored in \p mask. + * \p maxnode will be set to the maximal node number that was found, plus one. + * + * This function may be used before calling set_mempolicy, mbind, migrate_pages + * or any other function that takes an array of unsigned long and a maximal + * node number as input parameter. + * + * \return 0. + * + * \note On heterogeneous memory platforms, we may return multiple local NUMA nodes + * even if libnuma reports only one (usually the first one). + */ +static __hwloc_inline int +hwloc_cpuset_to_linux_libnuma_ulongs(hwloc_topology_t topology, hwloc_const_cpuset_t cpuset, + unsigned long *mask, unsigned long *maxnode) +{ + int depth = hwloc_get_type_depth(topology, HWLOC_OBJ_NUMANODE); + unsigned long outmaxnode = -1; + hwloc_obj_t node = NULL; + + /* round-up to the next ulong and clear all bytes */ + *maxnode = (*maxnode + 8*sizeof(*mask) - 1) & ~(8*sizeof(*mask) - 1); + memset(mask, 0, *maxnode/8); + + while ((node = hwloc_get_next_obj_covering_cpuset_by_depth(topology, cpuset, depth, node)) != NULL) { + if (node->os_index >= *maxnode) + continue; + mask[node->os_index/sizeof(*mask)/8] |= 1UL << (node->os_index % (sizeof(*mask)*8)); + if (outmaxnode == (unsigned long) -1 || outmaxnode < node->os_index) + outmaxnode = node->os_index; + } + + *maxnode = outmaxnode+1; + return 0; +} + +/** \brief Convert hwloc NUMA node set \p nodeset into the array of unsigned long \p mask + * + * \p mask is the array of unsigned long that will be filled. + * \p maxnode contains the maximal node number that may be stored in \p mask. + * \p maxnode will be set to the maximal node number that was found, plus one. + * + * This function may be used before calling set_mempolicy, mbind, migrate_pages + * or any other function that takes an array of unsigned long and a maximal + * node number as input parameter. + * + * \return 0. + */ +static __hwloc_inline int +hwloc_nodeset_to_linux_libnuma_ulongs(hwloc_topology_t topology, hwloc_const_nodeset_t nodeset, + unsigned long *mask, unsigned long *maxnode) +{ + int depth = hwloc_get_type_depth(topology, HWLOC_OBJ_NUMANODE); + unsigned long outmaxnode = -1; + hwloc_obj_t node = NULL; + + /* round-up to the next ulong and clear all bytes */ + *maxnode = (*maxnode + 8*sizeof(*mask) - 1) & ~(8*sizeof(*mask) - 1); + memset(mask, 0, *maxnode/8); + + while ((node = hwloc_get_next_obj_by_depth(topology, depth, node)) != NULL) { + if (node->os_index >= *maxnode) + continue; + if (!hwloc_bitmap_isset(nodeset, node->os_index)) + continue; + mask[node->os_index/sizeof(*mask)/8] |= 1UL << (node->os_index % (sizeof(*mask)*8)); + if (outmaxnode == (unsigned long) -1 || outmaxnode < node->os_index) + outmaxnode = node->os_index; + } + + *maxnode = outmaxnode+1; + return 0; +} + +/** \brief Convert the array of unsigned long \p mask into hwloc CPU set + * + * \p mask is a array of unsigned long that will be read. + * \p maxnode contains the maximal node number that may be read in \p mask. + * + * This function may be used after calling get_mempolicy or any other function + * that takes an array of unsigned long as output parameter (and possibly + * a maximal node number as input parameter). + * + * \return 0 on success. + * \return -1 on error, for instance if failing an internal reallocation. + */ +static __hwloc_inline int +hwloc_cpuset_from_linux_libnuma_ulongs(hwloc_topology_t topology, hwloc_cpuset_t cpuset, + const unsigned long *mask, unsigned long maxnode) +{ + int depth = hwloc_get_type_depth(topology, HWLOC_OBJ_NUMANODE); + hwloc_obj_t node = NULL; + hwloc_bitmap_zero(cpuset); + while ((node = hwloc_get_next_obj_by_depth(topology, depth, node)) != NULL) + if (node->os_index < maxnode + && (mask[node->os_index/sizeof(*mask)/8] & (1UL << (node->os_index % (sizeof(*mask)*8))))) + if (hwloc_bitmap_or(cpuset, cpuset, node->cpuset) < 0) + return -1; + return 0; +} + +/** \brief Convert the array of unsigned long \p mask into hwloc NUMA node set + * + * \p mask is a array of unsigned long that will be read. + * \p maxnode contains the maximal node number that may be read in \p mask. + * + * This function may be used after calling get_mempolicy or any other function + * that takes an array of unsigned long as output parameter (and possibly + * a maximal node number as input parameter). + * + * \return 0 on success. + * \return -1 with errno set to \c ENOMEM if some internal reallocation failed. + */ +static __hwloc_inline int +hwloc_nodeset_from_linux_libnuma_ulongs(hwloc_topology_t topology, hwloc_nodeset_t nodeset, + const unsigned long *mask, unsigned long maxnode) +{ + int depth = hwloc_get_type_depth(topology, HWLOC_OBJ_NUMANODE); + hwloc_obj_t node = NULL; + hwloc_bitmap_zero(nodeset); + while ((node = hwloc_get_next_obj_by_depth(topology, depth, node)) != NULL) + if (node->os_index < maxnode + && (mask[node->os_index/sizeof(*mask)/8] & (1UL << (node->os_index % (sizeof(*mask)*8))))) + if (hwloc_bitmap_set(nodeset, node->os_index) < 0) + return -1; + return 0; +} + +/** @} */ + + + +/** \defgroup hwlocality_linux_libnuma_bitmask Interoperability with Linux libnuma bitmask + * + * This interface helps converting between Linux libnuma bitmasks + * and hwloc cpusets and nodesets. + * + * \note Topology \p topology must match the current machine. + * + * \note The behavior of libnuma is undefined if the kernel is not NUMA-aware. + * (when CONFIG_NUMA is not set in the kernel configuration). + * This helper and libnuma may thus not be strictly compatible in this case, + * which may be detected by checking whether numa_available() returns -1. + * + * @{ + */ + + +/** \brief Convert hwloc CPU set \p cpuset into the returned libnuma bitmask + * + * The returned bitmask should later be freed with numa_bitmask_free. + * + * This function may be used before calling many numa_ functions + * that use a struct bitmask as an input parameter. + * + * \return newly allocated struct bitmask, or \c NULL on error. + * + * \note On heterogeneous memory platforms, we may return multiple local NUMA nodes + * even if libnuma reports only one (usually the first one). + */ +static __hwloc_inline struct bitmask * +hwloc_cpuset_to_linux_libnuma_bitmask(hwloc_topology_t topology, hwloc_const_cpuset_t cpuset) __hwloc_attribute_malloc; +static __hwloc_inline struct bitmask * +hwloc_cpuset_to_linux_libnuma_bitmask(hwloc_topology_t topology, hwloc_const_cpuset_t cpuset) +{ + int depth = hwloc_get_type_depth(topology, HWLOC_OBJ_NUMANODE); + hwloc_obj_t node = NULL; + struct bitmask *bitmask = numa_allocate_cpumask(); + if (!bitmask) + return NULL; + while ((node = hwloc_get_next_obj_covering_cpuset_by_depth(topology, cpuset, depth, node)) != NULL) + if (node->attr->numanode.local_memory) + numa_bitmask_setbit(bitmask, node->os_index); + return bitmask; +} + +/** \brief Convert hwloc NUMA node set \p nodeset into the returned libnuma bitmask + * + * The returned bitmask should later be freed with numa_bitmask_free. + * + * This function may be used before calling many numa_ functions + * that use a struct bitmask as an input parameter. + * + * \return newly allocated struct bitmask, or \c NULL on error. + */ +static __hwloc_inline struct bitmask * +hwloc_nodeset_to_linux_libnuma_bitmask(hwloc_topology_t topology, hwloc_const_nodeset_t nodeset) __hwloc_attribute_malloc; +static __hwloc_inline struct bitmask * +hwloc_nodeset_to_linux_libnuma_bitmask(hwloc_topology_t topology, hwloc_const_nodeset_t nodeset) +{ + int depth = hwloc_get_type_depth(topology, HWLOC_OBJ_NUMANODE); + hwloc_obj_t node = NULL; + struct bitmask *bitmask = numa_allocate_cpumask(); + if (!bitmask) + return NULL; + while ((node = hwloc_get_next_obj_by_depth(topology, depth, node)) != NULL) + if (hwloc_bitmap_isset(nodeset, node->os_index) && node->attr->numanode.local_memory) + numa_bitmask_setbit(bitmask, node->os_index); + return bitmask; +} + +/** \brief Convert libnuma bitmask \p bitmask into hwloc CPU set \p cpuset + * + * This function may be used after calling many numa_ functions + * that use a struct bitmask as an output parameter. + * + * \return 0 on success. + * \return -1 with errno set to \c ENOMEM if some internal reallocation failed. + */ +static __hwloc_inline int +hwloc_cpuset_from_linux_libnuma_bitmask(hwloc_topology_t topology, hwloc_cpuset_t cpuset, + const struct bitmask *bitmask) +{ + int depth = hwloc_get_type_depth(topology, HWLOC_OBJ_NUMANODE); + hwloc_obj_t node = NULL; + hwloc_bitmap_zero(cpuset); + while ((node = hwloc_get_next_obj_by_depth(topology, depth, node)) != NULL) + if (numa_bitmask_isbitset(bitmask, node->os_index)) + if (hwloc_bitmap_or(cpuset, cpuset, node->cpuset) < 0) + return -1; + return 0; +} + +/** \brief Convert libnuma bitmask \p bitmask into hwloc NUMA node set \p nodeset + * + * This function may be used after calling many numa_ functions + * that use a struct bitmask as an output parameter. + * + * \return 0 on success. + * \return -1 with errno set to \c ENOMEM if some internal reallocation failed. + */ +static __hwloc_inline int +hwloc_nodeset_from_linux_libnuma_bitmask(hwloc_topology_t topology, hwloc_nodeset_t nodeset, + const struct bitmask *bitmask) +{ + int depth = hwloc_get_type_depth(topology, HWLOC_OBJ_NUMANODE); + hwloc_obj_t node = NULL; + hwloc_bitmap_zero(nodeset); + while ((node = hwloc_get_next_obj_by_depth(topology, depth, node)) != NULL) + if (numa_bitmask_isbitset(bitmask, node->os_index)) + if (hwloc_bitmap_set(nodeset, node->os_index) < 0) + return -1; + return 0; +} + +/** @} */ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* HWLOC_LINUX_NUMA_H */ diff --git a/src/deps/hwloc/include/hwloc/linux.h b/src/deps/hwloc/include/hwloc/linux.h new file mode 100644 index 000000000..fb3054218 --- /dev/null +++ b/src/deps/hwloc/include/hwloc/linux.h @@ -0,0 +1,96 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * Copyright © 2009 CNRS + * Copyright © 2009-2023 Inria. All rights reserved. + * Copyright © 2009-2011 Université Bordeaux + * See COPYING in top-level directory. + */ + +/** \file + * \brief Macros to help interaction between hwloc and Linux. + * + * Applications that use hwloc on Linux may want to include this file + * if using some low-level Linux features. + */ + +#ifndef HWLOC_LINUX_H +#define HWLOC_LINUX_H + +#include "hwloc.h" + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** \defgroup hwlocality_linux Linux-specific helpers + * + * This includes helpers for manipulating Linux kernel cpumap files, and hwloc + * equivalents of the Linux sched_setaffinity and sched_getaffinity system calls. + * + * @{ + */ + +/** \brief Bind a thread \p tid on cpus given in cpuset \p set + * + * The behavior is exactly the same as the Linux sched_setaffinity system call, + * but uses a hwloc cpuset. + * + * \return 0 on success, -1 on error. + * + * \note This is equivalent to calling hwloc_set_proc_cpubind() with + * HWLOC_CPUBIND_THREAD as flags. + */ +HWLOC_DECLSPEC int hwloc_linux_set_tid_cpubind(hwloc_topology_t topology, pid_t tid, hwloc_const_cpuset_t set); + +/** \brief Get the current binding of thread \p tid + * + * The CPU-set \p set (previously allocated by the caller) + * is filled with the list of PUs which the thread + * was last bound to. + * + * The behavior is exactly the same as the Linux sched_getaffinity system call, + * but uses a hwloc cpuset. + * + * \return 0 on success, -1 on error. + * + * \note This is equivalent to calling hwloc_get_proc_cpubind() with + * ::HWLOC_CPUBIND_THREAD as flags. + */ +HWLOC_DECLSPEC int hwloc_linux_get_tid_cpubind(hwloc_topology_t topology, pid_t tid, hwloc_cpuset_t set); + +/** \brief Get the last physical CPU where thread \p tid ran. + * + * The CPU-set \p set (previously allocated by the caller) + * is filled with the PU which the thread last ran on. + * + * \return 0 on success, -1 on error. + * + * \note This is equivalent to calling hwloc_get_proc_last_cpu_location() with + * ::HWLOC_CPUBIND_THREAD as flags. + */ +HWLOC_DECLSPEC int hwloc_linux_get_tid_last_cpu_location(hwloc_topology_t topology, pid_t tid, hwloc_bitmap_t set); + +/** \brief Convert a linux kernel cpumask file \p path into a hwloc bitmap \p set. + * + * Might be used when reading CPU set from sysfs attributes such as topology + * and caches for processors, or local_cpus for devices. + * + * \return 0 on success, -1 on error. + * + * \note This function ignores the HWLOC_FSROOT environment variable. + */ +HWLOC_DECLSPEC int hwloc_linux_read_path_as_cpumask(const char *path, hwloc_bitmap_t set); + +/** @} */ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* HWLOC_LINUX_H */ diff --git a/src/deps/hwloc/include/hwloc/memattrs.h b/src/deps/hwloc/include/hwloc/memattrs.h new file mode 100644 index 000000000..aa69085e3 --- /dev/null +++ b/src/deps/hwloc/include/hwloc/memattrs.h @@ -0,0 +1,672 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * Copyright © 2019-2025 Inria. All rights reserved. + * See COPYING in top-level directory. + */ + +/** \file + * \brief Memory node attributes. + */ + +#ifndef HWLOC_MEMATTR_H +#define HWLOC_MEMATTR_H + +#include "hwloc.h" + +#ifdef __cplusplus +extern "C" { +#elif 0 +} +#endif + +/** \defgroup hwlocality_memattrs Comparing memory node attributes for finding where to allocate on + * + * Platforms with heterogeneous memory require ways to decide whether + * a buffer should be allocated on "fast" memory (such as HBM), + * "normal" memory (DDR) or even "slow" but large-capacity memory + * (non-volatile memory). + * These memory nodes are called "Targets" while the CPU accessing them + * is called the "Initiator". Access performance depends on their + * locality (NUMA platforms) as well as the intrinsic performance + * of the targets (heterogeneous platforms). + * + * The following attributes describe the performance of memory accesses + * from an Initiator to a memory Target, for instance their latency + * or bandwidth. + * Initiators performing these memory accesses are usually some PUs or Cores + * (described as a CPU set). + * Hence a Core may choose where to allocate a memory buffer by comparing + * the attributes of different target memory nodes nearby. + * + * There are also some attributes that are system-wide. + * Their value does not depend on a specific initiator performing + * an access. + * The memory node Capacity is an example of such attribute without + * initiator. + * + * One way to use this API is to start with a cpuset describing the Cores where + * a program is bound. The best target NUMA node for allocating memory in this + * program on these Cores may be obtained by passing this cpuset as an initiator + * to hwloc_memattr_get_best_target() with the relevant memory attribute. + * For instance, if the code is latency limited, use the Latency attribute. + * + * A more flexible approach consists in getting the list of local NUMA nodes + * by passing this cpuset to hwloc_get_local_numanode_objs(). + * Attribute values for these nodes, if any, may then be obtained with + * hwloc_memattr_get_value() and manually compared with the desired criteria. + * + * Memory attributes are also used internally to build Memory Tiers which provide + * an easy way to distinguish NUMA nodes of different kinds, as explained + * in \ref heteromem. + * + * Beside tiers, hwloc defines a set of "default" nodes where normal memory + * allocations should be made from (see hwloc_topology_get_default_nodeset()). + * This is also useful for dividing the machine into a set of non-overlapping + * NUMA domains, for instance for binding tasks per domain. + * + * \sa An example is available in doc/examples/memory-attributes.c in the source tree. + * + * \note The API also supports specific objects as initiator, + * but it is currently not used internally by hwloc. + * Users may for instance use it to provide custom performance + * values for host memory accesses performed by GPUs. + * + * \note The interface actually also accepts targets that are not NUMA nodes. + * @{ + */ + +/** \brief Predefined memory attribute IDs. + * See ::hwloc_memattr_id_t for the generic definition of IDs + * for predefined or custom attributes. + */ +enum hwloc_memattr_id_e { + /** \brief + * The \"Capacity\" is returned in bytes (local_memory attribute in objects). + * + * Best capacity nodes are nodes with higher capacity. + * + * No initiator is involved when looking at this attribute. + * The corresponding attribute flags are ::HWLOC_MEMATTR_FLAG_HIGHER_FIRST. + * + * Capacity values may not be modified using hwloc_memattr_set_value(). + * \hideinitializer + */ + HWLOC_MEMATTR_ID_CAPACITY = 0, + + /** \brief + * The \"Locality\" is returned as the number of PUs in that locality + * (e.g. the weight of its cpuset). + * + * Best locality nodes are nodes with smaller locality + * (nodes that are local to very few PUs). + * Poor locality nodes are nodes with larger locality + * (nodes that are local to the entire machine). + * + * No initiator is involved when looking at this attribute. + * The corresponding attribute flags are ::HWLOC_MEMATTR_FLAG_HIGHER_FIRST. + + * Locality values may not be modified using hwloc_memattr_set_value(). + * \hideinitializer + */ + HWLOC_MEMATTR_ID_LOCALITY = 1, + + /** \brief + * The \"Bandwidth\" is returned in MiB/s, as seen from the given initiator location. + * + * Best bandwidth nodes are nodes with higher bandwidth. + * + * The corresponding attribute flags are ::HWLOC_MEMATTR_FLAG_HIGHER_FIRST + * and ::HWLOC_MEMATTR_FLAG_NEED_INITIATOR. + * + * This is the average bandwidth for read and write accesses. If the platform + * provides individual read and write bandwidths but no explicit average value, + * hwloc computes and returns the average. + * \hideinitializer + */ + HWLOC_MEMATTR_ID_BANDWIDTH = 2, + + /** \brief + * The \"ReadBandwidth\" is returned in MiB/s, as seen from the given initiator location. + * + * Best bandwidth nodes are nodes with higher bandwidth. + * + * The corresponding attribute flags are ::HWLOC_MEMATTR_FLAG_HIGHER_FIRST + * and ::HWLOC_MEMATTR_FLAG_NEED_INITIATOR. + * \hideinitializer + */ + HWLOC_MEMATTR_ID_READ_BANDWIDTH = 4, + + /** \brief + * The \"WriteBandwidth\" is returned in MiB/s, as seen from the given initiator location. + * + * Best bandwidth nodes are nodes with higher bandwidth. + * + * The corresponding attribute flags are ::HWLOC_MEMATTR_FLAG_HIGHER_FIRST + * and ::HWLOC_MEMATTR_FLAG_NEED_INITIATOR. + * \hideinitializer + */ + HWLOC_MEMATTR_ID_WRITE_BANDWIDTH = 5, + + /** \brief + * The \"Latency\" is returned as nanoseconds, as seen from the given initiator location. + * + * Best latency nodes are nodes with smaller latency. + * + * The corresponding attribute flags are ::HWLOC_MEMATTR_FLAG_LOWER_FIRST + * and ::HWLOC_MEMATTR_FLAG_NEED_INITIATOR. + * + * This is the average latency for read and write accesses. If the platform + * provides individual read and write latencies but no explicit average value, + * hwloc computes and returns the average. + * \hideinitializer + */ + HWLOC_MEMATTR_ID_LATENCY = 3, + + /** \brief + * The \"ReadLatency\" is returned as nanoseconds, as seen from the given initiator location. + * + * Best latency nodes are nodes with smaller latency. + * + * The corresponding attribute flags are ::HWLOC_MEMATTR_FLAG_LOWER_FIRST + * and ::HWLOC_MEMATTR_FLAG_NEED_INITIATOR. + * \hideinitializer + */ + HWLOC_MEMATTR_ID_READ_LATENCY = 6, + + /** \brief + * The \"WriteLatency\" is returned as nanoseconds, as seen from the given initiator location. + * + * Best latency nodes are nodes with smaller latency. + * + * The corresponding attribute flags are ::HWLOC_MEMATTR_FLAG_LOWER_FIRST + * and ::HWLOC_MEMATTR_FLAG_NEED_INITIATOR. + * \hideinitializer + */ + HWLOC_MEMATTR_ID_WRITE_LATENCY = 7, + + /* TODO persistence? */ + + HWLOC_MEMATTR_ID_MAX /**< \private + * Sentinel value for predefined attributes. + * Dynamically registered custom attributes start here. + */ +}; + +/** \brief A memory attribute identifier. + * + * hwloc predefines some commonly-used attributes in ::hwloc_memattr_id_e. + * One may then dynamically register custom ones with hwloc_memattr_register(), + * they will be assigned IDs immediately after the predefined ones. + * See \ref hwlocality_memattrs_manage for more information about + * existing attribute IDs. + */ +typedef unsigned hwloc_memattr_id_t; + +/** \brief Return the identifier of the memory attribute with the given name. + * + * \return 0 on success. + * \return -1 with errno set to \c EINVAL if no such attribute exists. + */ +HWLOC_DECLSPEC int +hwloc_memattr_get_by_name(hwloc_topology_t topology, + const char *name, + hwloc_memattr_id_t *id); + + +/** \brief Type of location. */ +enum hwloc_location_type_e { + /** \brief Location is given as a cpuset, in the location cpuset union field. \hideinitializer */ + HWLOC_LOCATION_TYPE_CPUSET = 1, + /** \brief Location is given as an object, in the location object union field. \hideinitializer */ + HWLOC_LOCATION_TYPE_OBJECT = 0 +}; + +/** \brief Where to measure attributes from. */ +struct hwloc_location { + /** \brief Type of location. */ + enum hwloc_location_type_e type; + /** \brief Actual location. */ + union hwloc_location_u { + /** \brief Location as a cpuset, when the location type is ::HWLOC_LOCATION_TYPE_CPUSET. */ + hwloc_cpuset_t cpuset; + /** \brief Location as an object, when the location type is ::HWLOC_LOCATION_TYPE_OBJECT. */ + hwloc_obj_t object; + } location; +}; + + +/** \brief Flags for selecting target NUMA nodes. */ +enum hwloc_local_numanode_flag_e { + /** \brief Select NUMA nodes whose locality is larger than the given cpuset. + * For instance, if a single PU (or its cpuset) is given in \p initiator, + * select all nodes close to the package that contains this PU. + * \hideinitializer + */ + HWLOC_LOCAL_NUMANODE_FLAG_LARGER_LOCALITY = (1UL<<0), + + /** \brief Select NUMA nodes whose locality is smaller than the given cpuset. + * For instance, if a package (or its cpuset) is given in \p initiator, + * also select nodes that are attached to only a half of that package. + * \hideinitializer + */ + HWLOC_LOCAL_NUMANODE_FLAG_SMALLER_LOCALITY = (1UL<<1), + + /** \brief Select NUMA nodes whose locality intersects the given cpuset. + * This includes larger and smaller localities as well as localities + * that are partially included. + * For instance, if the locality is one core of both packages, a NUMA node + * local to one package is neither larger nor smaller than this locality, + * but it intersects it. + * \hideinitializer + */ + HWLOC_LOCAL_NUMANODE_FLAG_INTERSECT_LOCALITY = (1UL<<3), + + /** \brief Select all NUMA nodes in the topology. + * The initiator \p initiator is ignored. + * \hideinitializer + */ + HWLOC_LOCAL_NUMANODE_FLAG_ALL = (1UL<<2) +}; + +/** \brief Return an array of local NUMA nodes. + * + * By default only select the NUMA nodes whose locality is exactly + * the given \p location. More nodes may be selected if additional flags + * are given as a OR'ed set of ::hwloc_local_numanode_flag_e. + * + * If \p location is given as an explicit object, its CPU set is used + * to find NUMA nodes with the corresponding locality. + * If the object does not have a CPU set (e.g. I/O object), the CPU + * parent (where the I/O object is attached) is used. + * + * On input, \p nr points to the number of nodes that may be stored + * in the \p nodes array. + * On output, \p nr will be changed to the number of stored nodes, + * or the number of nodes that would have been stored if there were + * enough room. + * + * \return 0 on success or -1 on error. + * + * \note Some of these NUMA nodes may not have any memory attribute + * values and hence not be reported as actual targets in other functions. + * + * \note The number of NUMA nodes in the topology (obtained by + * hwloc_bitmap_weight() on the root object nodeset) may be used + * to allocate the \p nodes array. + * + * \note When an object CPU set is given as locality, for instance a Package, + * and when flags contain both ::HWLOC_LOCAL_NUMANODE_FLAG_LARGER_LOCALITY + * and ::HWLOC_LOCAL_NUMANODE_FLAG_SMALLER_LOCALITY, + * the returned array corresponds to the nodeset of that object. + */ +HWLOC_DECLSPEC int +hwloc_get_local_numanode_objs(hwloc_topology_t topology, + struct hwloc_location *location, + unsigned *nr, + hwloc_obj_t *nodes, + unsigned long flags); + +/** \brief Return the set of default NUMA nodes + * + * In machines with heterogeneous memory, some NUMA nodes are considered + * the default ones, i.e. where basic allocations should be made from. + * These are usually DRAM nodes. + * + * Other nodes may be reserved for specific use (I/O device memory, e.g. GPU memory), + * small but high performance (HBM), large but slow memory (NVM), etc. + * Buffers should usually not be allocated from there unless explicitly required. + * + * This function fills \p nodeset with the bits of NUMA nodes considered default. + * + * It is guaranteed that these nodes have non-intersecting CPU sets, + * i.e. cores may not have multiple local NUMA nodes anymore. + * Hence this may be used to iterate over the platform divided into separate + * NUMA localities, for instance for binding one task per NUMA domain. + * + * Any core that had some local NUMA node(s) in the initial topology should + * still have one in the default nodeset. Corner cases where this would be + * wrong consist in asymmetric platforms with missing DRAM nodes, or topologies + * that were already restricted to less NUMA nodes. + * + * The returned nodeset may be passed to hwloc_topology_restrict() with + * ::HWLOC_RESTRICT_FLAG_BYNODESET to remove all non-default nodes from + * the topology. The resulting topology will be easier to use when iterating + * over (now homogeneous) NUMA nodes. + * + * The heuristics for finding default nodes relies on memory tiers and subtypes + * (see \ref heteromem) as well as the assumption that hardware vendors list + * default nodes first in hardware tables. + * + * \p flags must be \c 0 for now. + * + * \return 0 on success. + * \return -1 on error. + * + * \note The returned nodeset usually contains all nodes from a single memory + * tier, likely the DRAM one. + * + * \note The returned nodeset is included in the list of available nodes + * returned by hwloc_topology_get_topology_nodeset(). It is strictly smaller + * if the machine has heterogeneous memory. + * + * \note The heuristics may return a suboptimal set of nodes if hwloc could + * not guess memory types and/or if some default nodes were removed earlier + * from the topology (e.g. with hwloc_topology_restrict()). + */ +HWLOC_DECLSPEC int +hwloc_topology_get_default_nodeset(hwloc_topology_t topology, + hwloc_nodeset_t nodeset, + unsigned long flags); + +/** \brief Return an attribute value for a specific target NUMA node. + * + * If the attribute does not relate to a specific initiator + * (it does not have the flag ::HWLOC_MEMATTR_FLAG_NEED_INITIATOR), + * location \p initiator is ignored and may be \c NULL. + * + * \p target_node cannot be \c NULL. If \p attribute is ::HWLOC_MEMATTR_ID_CAPACITY, + * \p target_node must be a NUMA node. If it is ::HWLOC_MEMATTR_ID_LOCALITY, + * \p target_node must have a CPU set. + * + * \p flags must be \c 0 for now. + * + * \return 0 on success. + * \return -1 on error, for instance with errno set to \c EINVAL if flags + * are invalid or no such attribute exists. + * + * \note The initiator \p initiator should be of type ::HWLOC_LOCATION_TYPE_CPUSET + * when refering to accesses performed by CPU cores. + * ::HWLOC_LOCATION_TYPE_OBJECT is currently unused internally by hwloc, + * but users may for instance use it to provide custom information about + * host memory accesses performed by GPUs. + */ +HWLOC_DECLSPEC int +hwloc_memattr_get_value(hwloc_topology_t topology, + hwloc_memattr_id_t attribute, + hwloc_obj_t target_node, + struct hwloc_location *initiator, + unsigned long flags, + hwloc_uint64_t *value); + +/** \brief Return the best target NUMA node for the given attribute and initiator. + * + * If the attribute does not relate to a specific initiator + * (it does not have the flag ::HWLOC_MEMATTR_FLAG_NEED_INITIATOR), + * location \p initiator is ignored and may be \c NULL. + * + * If \p value is non \c NULL, the corresponding value is returned there. + * + * If multiple targets have the same attribute values, only one is + * returned (and there is no way to clarify how that one is chosen). + * Applications that want to detect targets with identical/similar + * values, or that want to look at values for multiple attributes, + * should rather get all values using hwloc_memattr_get_value() + * and manually select the target they consider the best. + * + * \p flags must be \c 0 for now. + * + * \return 0 on success. + * \return -1 with errno set to \c ENOENT if there are no matching targets. + * \return -1 with errno set to \c EINVAL if flags are invalid, + * or no such attribute exists. + * + * \note The initiator \p initiator should be of type ::HWLOC_LOCATION_TYPE_CPUSET + * when refering to accesses performed by CPU cores. + * ::HWLOC_LOCATION_TYPE_OBJECT is currently unused internally by hwloc, + * but users may for instance use it to provide custom information about + * host memory accesses performed by GPUs. + */ +HWLOC_DECLSPEC int +hwloc_memattr_get_best_target(hwloc_topology_t topology, + hwloc_memattr_id_t attribute, + struct hwloc_location *initiator, + unsigned long flags, + hwloc_obj_t *best_target, hwloc_uint64_t *value); + +/** \brief Return the best initiator for the given attribute and target NUMA node. + * + * If \p value is non \c NULL, the corresponding value is returned there. + * + * If multiple initiators have the same attribute values, only one is + * returned (and there is no way to clarify how that one is chosen). + * Applications that want to detect initiators with identical/similar + * values, or that want to look at values for multiple attributes, + * should rather get all values using hwloc_memattr_get_value() + * and manually select the initiator they consider the best. + * + * The returned initiator should not be modified or freed, + * it belongs to the topology. + * + * \p target_node cannot be \c NULL. + * + * \p flags must be \c 0 for now. + * + * \return 0 on success. + * \return -1 with errno set to \c ENOENT if there are no matching initiators. + * \return -1 with errno set to \c EINVAL if the attribute does not relate to a specific initiator + * (it does not have the flag ::HWLOC_MEMATTR_FLAG_NEED_INITIATOR). + */ +HWLOC_DECLSPEC int +hwloc_memattr_get_best_initiator(hwloc_topology_t topology, + hwloc_memattr_id_t attribute, + hwloc_obj_t target_node, + unsigned long flags, + struct hwloc_location *best_initiator, hwloc_uint64_t *value); + +/** \brief Return the target NUMA nodes that have some values for a given attribute. + * + * Return targets for the given attribute in the \p targets array + * (for the given initiator if any). + * If \p values is not \c NULL, the corresponding attribute values + * are stored in the array it points to. + * + * On input, \p nr points to the number of targets that may be stored + * in the array \p targets (and \p values). + * On output, \p nr points to the number of targets (and values) that + * were actually found, even if some of them couldn't be stored in the array. + * Targets that couldn't be stored are ignored, but the function still + * returns success (\c 0). The caller may find out by comparing the value pointed + * by \p nr before and after the function call. + * + * The returned targets should not be modified or freed, + * they belong to the topology. + * + * Argument \p initiator is ignored if the attribute does not relate to a specific + * initiator (it does not have the flag ::HWLOC_MEMATTR_FLAG_NEED_INITIATOR). + * Otherwise \p initiator may be non \c NULL to report only targets + * that have a value for that initiator. + * + * \p flags must be \c 0 for now. + * + * \note This function is meant for tools and debugging (listing internal information) + * rather than for application queries. Applications should rather select useful + * NUMA nodes with hwloc_get_local_numanode_objs() and then look at their attribute + * values. + * + * \return 0 on success or -1 on error. + * + * \note The initiator \p initiator should be of type ::HWLOC_LOCATION_TYPE_CPUSET + * when referring to accesses performed by CPU cores. + * ::HWLOC_LOCATION_TYPE_OBJECT is currently unused internally by hwloc, + * but users may for instance use it to provide custom information about + * host memory accesses performed by GPUs. + */ +HWLOC_DECLSPEC int +hwloc_memattr_get_targets(hwloc_topology_t topology, + hwloc_memattr_id_t attribute, + struct hwloc_location *initiator, + unsigned long flags, + unsigned *nr, hwloc_obj_t *targets, hwloc_uint64_t *values); + +/** \brief Return the initiators that have values for a given attribute for a specific target NUMA node. + * + * Return initiators for the given attribute and target node in the + * \p initiators array. + * If \p values is not \c NULL, the corresponding attribute values + * are stored in the array it points to. + * + * On input, \p nr points to the number of initiators that may be stored + * in the array \p initiators (and \p values). + * On output, \p nr points to the number of initiators (and values) that + * were actually found, even if some of them couldn't be stored in the array. + * Initiators that couldn't be stored are ignored, but the function still + * returns success (\c 0). The caller may find out by comparing the value pointed + * by \p nr before and after the function call. + * + * The returned initiators should not be modified or freed, + * they belong to the topology. + * + * \p target_node cannot be \c NULL. + * + * \p flags must be \c 0 for now. + * + * If the attribute does not relate to a specific initiator + * (it does not have the flag ::HWLOC_MEMATTR_FLAG_NEED_INITIATOR), + * no initiator is returned. + * + * \return 0 on success or -1 on error. + * + * \note This function is meant for tools and debugging (listing internal information) + * rather than for application queries. Applications should rather select useful + * NUMA nodes with hwloc_get_local_numanode_objs() and then look at their attribute + * values for some relevant initiators. + */ +HWLOC_DECLSPEC int +hwloc_memattr_get_initiators(hwloc_topology_t topology, + hwloc_memattr_id_t attribute, + hwloc_obj_t target_node, + unsigned long flags, + unsigned *nr, struct hwloc_location *initiators, hwloc_uint64_t *values); + +/** @} */ + + +/** \defgroup hwlocality_memattrs_manage Managing memory attributes + * + * Memory attribues are identified by an ID (::hwloc_memattr_id_t) + * and a name. hwloc_memattr_get_name() and hwloc_memattr_get_by_name() + * convert between them (or return error if the attribute does not exist). + * + * The set of valid ::hwloc_memattr_id_t is a contigous set starting at \c 0. + * It first contains predefined attributes, as listed + * in ::hwloc_memattr_id_e (from \c 0 to \c HWLOC_MEMATTR_ID_MAX-1). + * Then custom attributes may be dynamically registered with + * hwloc_memattr_register(). They will get the following IDs + * (\c HWLOC_MEMATTR_ID_MAX for the first one, etc.). + * + * To iterate over all valid attributes + * (either predefined or dynamically registered custom ones), + * one may iterate over IDs starting from \c 0 until hwloc_memattr_get_name() + * or hwloc_memattr_get_flags() returns an error. + * + * The values for an existing attribute or for custom dynamically registered ones + * may be set or modified with hwloc_memattr_set_value(). + * + * @{ + */ + +/** \brief Return the name of a memory attribute. + * + * The output pointer \p name cannot be \c NULL. + * + * \return 0 on success. + * \return -1 with errno set to \c EINVAL if the attribute does not exist. + */ +HWLOC_DECLSPEC int +hwloc_memattr_get_name(hwloc_topology_t topology, + hwloc_memattr_id_t attribute, + const char **name); + +/** \brief Return the flags of the given attribute. + * + * Flags are a OR'ed set of ::hwloc_memattr_flag_e. + * + * The output pointer \p flags cannot be \c NULL. + * + * \return 0 on success. + * \return -1 with errno set to \c EINVAL if the attribute does not exist. + */ +HWLOC_DECLSPEC int +hwloc_memattr_get_flags(hwloc_topology_t topology, + hwloc_memattr_id_t attribute, + unsigned long *flags); + +/** \brief Memory attribute flags. + * Given to hwloc_memattr_register() and returned by hwloc_memattr_get_flags(). + */ +enum hwloc_memattr_flag_e { + /** \brief The best nodes for this memory attribute are those with the higher values. + * For instance Bandwidth. + */ + HWLOC_MEMATTR_FLAG_HIGHER_FIRST = (1UL<<0), + /** \brief The best nodes for this memory attribute are those with the lower values. + * For instance Latency. + */ + HWLOC_MEMATTR_FLAG_LOWER_FIRST = (1UL<<1), + /** \brief The value returned for this memory attribute depends on the given initiator. + * For instance Bandwidth and Latency, but not Capacity. + */ + HWLOC_MEMATTR_FLAG_NEED_INITIATOR = (1UL<<2) +}; + +/** \brief Register a new memory attribute. + * + * Add a new custom memory attribute. + * Flags are a OR'ed set of ::hwloc_memattr_flag_e. It must contain one of + * ::HWLOC_MEMATTR_FLAG_HIGHER_FIRST or ::HWLOC_MEMATTR_FLAG_LOWER_FIRST but not both. + * + * The new attribute \p id is immediately after the last existing attribute ID + * (which is either the ID of the last registered attribute if any, + * or the ID of the last predefined attribute in ::hwloc_memattr_id_e). + * + * \return 0 on success. + * \return -1 with errno set to \c EINVAL if an invalid set of flags is given. + * \return -1 with errno set to \c EBUSY if another attribute already uses this name. + */ +HWLOC_DECLSPEC int +hwloc_memattr_register(hwloc_topology_t topology, + const char *name, + unsigned long flags, + hwloc_memattr_id_t *id); + +/** \brief Set an attribute value for a specific target NUMA node. + * + * If the attribute does not relate to a specific initiator + * (it does not have the flag ::HWLOC_MEMATTR_FLAG_NEED_INITIATOR), + * location \p initiator is ignored and may be \c NULL. + * + * The initiator will be copied into the topology, + * the caller should free anything allocated to store the initiator, + * for instance the cpuset. + * + * \p target_node cannot be \c NULL. + * + * \p attribute cannot be ::HWLOC_MEMATTR_ID_CAPACITY or + * ::HWLOC_MEMATTR_ID_LOCALITY. + * + * \p flags must be \c 0 for now. + * + * \note The initiator \p initiator should be of type ::HWLOC_LOCATION_TYPE_CPUSET + * when referring to accesses performed by CPU cores. + * ::HWLOC_LOCATION_TYPE_OBJECT is currently unused internally by hwloc, + * but users may for instance use it to provide custom information about + * host memory accesses performed by GPUs. + * + * \return 0 on success or -1 on error. + */ +HWLOC_DECLSPEC int +hwloc_memattr_set_value(hwloc_topology_t topology, + hwloc_memattr_id_t attribute, + hwloc_obj_t target_node, + struct hwloc_location *initiator, + unsigned long flags, + hwloc_uint64_t value); + +/** @} */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* HWLOC_MEMATTR_H */ diff --git a/src/deps/hwloc/include/hwloc/nvml.h b/src/deps/hwloc/include/hwloc/nvml.h new file mode 100644 index 000000000..c1badd13a --- /dev/null +++ b/src/deps/hwloc/include/hwloc/nvml.h @@ -0,0 +1,185 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * Copyright © 2012-2023 Inria. All rights reserved. + * See COPYING in top-level directory. + */ + +/** \file + * \brief Macros to help interaction between hwloc and the NVIDIA Management Library. + * + * Applications that use both hwloc and the NVIDIA Management Library may want to + * include this file so as to get topology information for NVML devices. + */ + +#ifndef HWLOC_NVML_H +#define HWLOC_NVML_H + +#include "hwloc.h" +#include "hwloc/autogen/config.h" +#include "hwloc/helper.h" +#ifdef HWLOC_LINUX_SYS +#include "hwloc/linux.h" +#endif + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** \defgroup hwlocality_nvml Interoperability with the NVIDIA Management Library + * + * This interface offers ways to retrieve topology information about + * devices managed by the NVIDIA Management Library (NVML). + * + * @{ + */ + +/** \brief Get the CPU set of processors that are physically + * close to NVML device \p device. + * + * Store in \p set the CPU-set describing the locality of the NVML device \p device. + * + * Topology \p topology and device \p device must match the local machine. + * I/O devices detection and the NVML component are not needed in the topology. + * + * The function only returns the locality of the device. + * If more information about the device is needed, OS objects should + * be used instead, see hwloc_nvml_get_device_osdev() + * and hwloc_nvml_get_device_osdev_by_index(). + * + * This function is currently only implemented in a meaningful way for + * Linux; other systems will simply get a full cpuset. + * + * \return 0 on success. + * \return -1 on error, for instance if device information could not be found. + */ +static __hwloc_inline int +hwloc_nvml_get_device_cpuset(hwloc_topology_t topology __hwloc_attribute_unused, + nvmlDevice_t device, hwloc_cpuset_t set) +{ +#ifdef HWLOC_LINUX_SYS + /* If we're on Linux, use the sysfs mechanism to get the local cpus */ +#define HWLOC_NVML_DEVICE_SYSFS_PATH_MAX 128 + char path[HWLOC_NVML_DEVICE_SYSFS_PATH_MAX]; + nvmlReturn_t nvres; + nvmlPciInfo_t pci; + + if (!hwloc_topology_is_thissystem(topology)) { + errno = EINVAL; + return -1; + } + + nvres = nvmlDeviceGetPciInfo(device, &pci); + if (NVML_SUCCESS != nvres) { + errno = EINVAL; + return -1; + } + + sprintf(path, "/sys/bus/pci/devices/%04x:%02x:%02x.0/local_cpus", pci.domain, pci.bus, pci.device); + if (hwloc_linux_read_path_as_cpumask(path, set) < 0 + || hwloc_bitmap_iszero(set)) + hwloc_bitmap_copy(set, hwloc_topology_get_complete_cpuset(topology)); +#else + /* Non-Linux systems simply get a full cpuset */ + hwloc_bitmap_copy(set, hwloc_topology_get_complete_cpuset(topology)); +#endif + return 0; +} + +/** \brief Get the hwloc OS device object corresponding to the + * NVML device whose index is \p idx. + * + * \return The hwloc OS device object describing the NVML device whose index is \p idx. + * \return \c NULL if none could be found. + * + * The topology \p topology does not necessarily have to match the current + * machine. For instance the topology may be an XML import of a remote host. + * I/O devices detection and the NVML component must be enabled in the topology. + * + * \note The corresponding PCI device object can be obtained by looking + * at the OS device parent object (unless PCI devices are filtered out). + */ +static __hwloc_inline hwloc_obj_t +hwloc_nvml_get_device_osdev_by_index(hwloc_topology_t topology, unsigned idx) +{ + hwloc_obj_t osdev = NULL; + while ((osdev = hwloc_get_next_osdev(topology, osdev)) != NULL) { + if (HWLOC_OBJ_OSDEV_GPU == osdev->attr->osdev.type + && osdev->name + && !strncmp("nvml", osdev->name, 4) + && atoi(osdev->name + 4) == (int) idx) + return osdev; + } + return NULL; +} + +/** \brief Get the hwloc OS device object corresponding to NVML device \p device. + * + * \return The hwloc OS device object that describes the given NVML device \p device. + * \return \c NULL if none could be found. + * + * Topology \p topology and device \p device must match the local machine. + * I/O devices detection and the NVML component must be enabled in the topology. + * If not, the locality of the object may still be found using + * hwloc_nvml_get_device_cpuset(). + * + * \note The corresponding hwloc PCI device may be found by looking + * at the result parent pointer (unless PCI devices are filtered out). + */ +static __hwloc_inline hwloc_obj_t +hwloc_nvml_get_device_osdev(hwloc_topology_t topology, nvmlDevice_t device) +{ + hwloc_obj_t osdev; + nvmlReturn_t nvres; + nvmlPciInfo_t pci; + char uuid[64]; + + if (!hwloc_topology_is_thissystem(topology)) { + errno = EINVAL; + return NULL; + } + + nvres = nvmlDeviceGetPciInfo(device, &pci); + if (NVML_SUCCESS != nvres) + return NULL; + + nvres = nvmlDeviceGetUUID(device, uuid, sizeof(uuid)); + if (NVML_SUCCESS != nvres) + uuid[0] = '\0'; + + osdev = NULL; + while ((osdev = hwloc_get_next_osdev(topology, osdev)) != NULL) { + hwloc_obj_t pcidev = osdev->parent; + const char *info; + + if (strncmp(osdev->name, "nvml", 4)) + continue; + + if (pcidev + && pcidev->type == HWLOC_OBJ_PCI_DEVICE + && pcidev->attr->pcidev.domain == pci.domain + && pcidev->attr->pcidev.bus == pci.bus + && pcidev->attr->pcidev.dev == pci.device + && pcidev->attr->pcidev.func == 0) + return osdev; + + info = hwloc_obj_get_info_by_name(osdev, "NVIDIAUUID"); + if (info && !strcmp(info, uuid)) + return osdev; + } + + return NULL; +} + +/** @} */ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* HWLOC_NVML_H */ diff --git a/src/deps/hwloc/include/hwloc/opencl.h b/src/deps/hwloc/include/hwloc/opencl.h new file mode 100644 index 000000000..c4da40318 --- /dev/null +++ b/src/deps/hwloc/include/hwloc/opencl.h @@ -0,0 +1,278 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * Copyright © 2012-2023 Inria. All rights reserved. + * Copyright © 2013, 2018 Université Bordeaux. All right reserved. + * See COPYING in top-level directory. + */ + +/** \file + * \brief Macros to help interaction between hwloc and the OpenCL interface. + * + * Applications that use both hwloc and OpenCL may want to + * include this file so as to get topology information for OpenCL devices. + */ + +#ifndef HWLOC_OPENCL_H +#define HWLOC_OPENCL_H + +#include "hwloc.h" +#include "hwloc/autogen/config.h" +#include "hwloc/helper.h" +#ifdef HWLOC_LINUX_SYS +#include "hwloc/linux.h" +#endif + +#ifdef __APPLE__ +#include +#else +#include +#endif + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* OpenCL extensions aren't always shipped with default headers, and + * they don't always reflect what the installed implementations support. + * Try everything and let the implementation return errors when non supported. + */ +/* Copyright (c) 2008-2018 The Khronos Group Inc. */ + +/* needs "cl_khr_pci_bus_info" device extension, but not strictly required for clGetDeviceInfo() */ +typedef struct { + cl_uint pci_domain; + cl_uint pci_bus; + cl_uint pci_device; + cl_uint pci_function; +} hwloc_cl_device_pci_bus_info_khr; +#define HWLOC_CL_DEVICE_PCI_BUS_INFO_KHR 0x410F + +/* needs "cl_amd_device_attribute_query" device extension, but not strictly required for clGetDeviceInfo() */ +#define HWLOC_CL_DEVICE_TOPOLOGY_AMD 0x4037 +typedef union { + struct { cl_uint type; cl_uint data[5]; } raw; + struct { cl_uint type; cl_char unused[17]; cl_char bus; cl_char device; cl_char function; } pcie; +} hwloc_cl_device_topology_amd; +#define HWLOC_CL_DEVICE_TOPOLOGY_TYPE_PCIE_AMD 1 + +/* needs "cl_nv_device_attribute_query" device extension, but not strictly required for clGetDeviceInfo() */ +#define HWLOC_CL_DEVICE_PCI_BUS_ID_NV 0x4008 +#define HWLOC_CL_DEVICE_PCI_SLOT_ID_NV 0x4009 +#define HWLOC_CL_DEVICE_PCI_DOMAIN_ID_NV 0x400A + + +/** \defgroup hwlocality_opencl Interoperability with OpenCL + * + * This interface offers ways to retrieve topology information about + * OpenCL devices. + * + * Only AMD and NVIDIA OpenCL implementations currently offer useful locality + * information about their devices. + * + * @{ + */ + +/** \brief Return the domain, bus and device IDs of the OpenCL device \p device. + * + * Device \p device must match the local machine. + * + * \return 0 on success. + * \return -1 on error, for instance if device information could not be found. + */ +static __hwloc_inline int +hwloc_opencl_get_device_pci_busid(cl_device_id device, + unsigned *domain, unsigned *bus, unsigned *dev, unsigned *func) +{ + hwloc_cl_device_topology_amd amdtopo; + hwloc_cl_device_pci_bus_info_khr khrbusinfo; + cl_uint nvbus, nvslot, nvdomain; + cl_int clret; + + clret = clGetDeviceInfo(device, HWLOC_CL_DEVICE_PCI_BUS_INFO_KHR, sizeof(khrbusinfo), &khrbusinfo, NULL); + if (CL_SUCCESS == clret) { + *domain = (unsigned) khrbusinfo.pci_domain; + *bus = (unsigned) khrbusinfo.pci_bus; + *dev = (unsigned) khrbusinfo.pci_device; + *func = (unsigned) khrbusinfo.pci_function; + return 0; + } + + clret = clGetDeviceInfo(device, HWLOC_CL_DEVICE_TOPOLOGY_AMD, sizeof(amdtopo), &amdtopo, NULL); + if (CL_SUCCESS == clret + && HWLOC_CL_DEVICE_TOPOLOGY_TYPE_PCIE_AMD == amdtopo.raw.type) { + *domain = 0; /* can't do anything better */ + /* cl_device_topology_amd stores bus ID in cl_char, dont convert those signed char directly to unsigned int */ + *bus = (unsigned) (unsigned char) amdtopo.pcie.bus; + *dev = (unsigned) (unsigned char) amdtopo.pcie.device; + *func = (unsigned) (unsigned char) amdtopo.pcie.function; + return 0; + } + + clret = clGetDeviceInfo(device, HWLOC_CL_DEVICE_PCI_BUS_ID_NV, sizeof(nvbus), &nvbus, NULL); + if (CL_SUCCESS == clret) { + clret = clGetDeviceInfo(device, HWLOC_CL_DEVICE_PCI_SLOT_ID_NV, sizeof(nvslot), &nvslot, NULL); + if (CL_SUCCESS == clret) { + clret = clGetDeviceInfo(device, HWLOC_CL_DEVICE_PCI_DOMAIN_ID_NV, sizeof(nvdomain), &nvdomain, NULL); + if (CL_SUCCESS == clret) { /* available since CUDA 10.2 */ + *domain = nvdomain; + } else { + *domain = 0; + } + *bus = nvbus & 0xff; + /* non-documented but used in many other projects */ + *dev = nvslot >> 3; + *func = nvslot & 0x7; + return 0; + } + } + + return -1; +} + +/** \brief Get the CPU set of processors that are physically + * close to OpenCL device \p device. + * + * Store in \p set the CPU-set describing the locality of the OpenCL device \p device. + * + * Topology \p topology and device \p device must match the local machine. + * I/O devices detection and the OpenCL component are not needed in the topology. + * + * The function only returns the locality of the device. + * If more information about the device is needed, OS objects should + * be used instead, see hwloc_opencl_get_device_osdev() + * and hwloc_opencl_get_device_osdev_by_index(). + * + * This function is currently only implemented in a meaningful way for + * Linux with the AMD or NVIDIA OpenCL implementation; other systems will simply + * get a full cpuset. + * + * \return 0 on success. + * \return -1 on error, for instance if the device could not be found. + */ +static __hwloc_inline int +hwloc_opencl_get_device_cpuset(hwloc_topology_t topology __hwloc_attribute_unused, + cl_device_id device __hwloc_attribute_unused, + hwloc_cpuset_t set) +{ +#if (defined HWLOC_LINUX_SYS) + /* If we're on Linux, try AMD/NVIDIA extensions + the sysfs mechanism to get the local cpus */ +#define HWLOC_OPENCL_DEVICE_SYSFS_PATH_MAX 128 + char path[HWLOC_OPENCL_DEVICE_SYSFS_PATH_MAX]; + unsigned pcidomain, pcibus, pcidev, pcifunc; + + if (!hwloc_topology_is_thissystem(topology)) { + errno = EINVAL; + return -1; + } + + if (hwloc_opencl_get_device_pci_busid(device, &pcidomain, &pcibus, &pcidev, &pcifunc) < 0) { + hwloc_bitmap_copy(set, hwloc_topology_get_complete_cpuset(topology)); + return 0; + } + + sprintf(path, "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/local_cpus", pcidomain, pcibus, pcidev, pcifunc); + if (hwloc_linux_read_path_as_cpumask(path, set) < 0 + || hwloc_bitmap_iszero(set)) + hwloc_bitmap_copy(set, hwloc_topology_get_complete_cpuset(topology)); +#else + /* Non-Linux systems simply get a full cpuset */ + hwloc_bitmap_copy(set, hwloc_topology_get_complete_cpuset(topology)); +#endif + return 0; +} + +/** \brief Get the hwloc OS device object corresponding to the + * OpenCL device for the given indexes. + * + * \return The hwloc OS device object describing the OpenCL device + * whose platform index is \p platform_index, + * and whose device index within this platform if \p device_index. + * \return \c NULL if there is none. + * + * The topology \p topology does not necessarily have to match the current + * machine. For instance the topology may be an XML import of a remote host. + * I/O devices detection and the OpenCL component must be enabled in the topology. + * + * \note The corresponding PCI device object can be obtained by looking + * at the OS device parent object (unless PCI devices are filtered out). + */ +static __hwloc_inline hwloc_obj_t +hwloc_opencl_get_device_osdev_by_index(hwloc_topology_t topology, + unsigned platform_index, unsigned device_index) +{ + unsigned x = (unsigned) -1, y = (unsigned) -1; + hwloc_obj_t osdev = NULL; + while ((osdev = hwloc_get_next_osdev(topology, osdev)) != NULL) { + if (HWLOC_OBJ_OSDEV_COPROC == osdev->attr->osdev.type + && osdev->name + && sscanf(osdev->name, "opencl%ud%u", &x, &y) == 2 + && platform_index == x && device_index == y) + return osdev; + } + return NULL; +} + +/** \brief Get the hwloc OS device object corresponding to OpenCL device \p deviceX. + * + * \return The hwloc OS device object corresponding to the given OpenCL device \p device. + * \return \c NULL if none could be found, for instance + * if required OpenCL attributes are not available. + * + * This function currently only works on AMD and NVIDIA OpenCL devices that support + * relevant OpenCL extensions. hwloc_opencl_get_device_osdev_by_index() + * should be preferred whenever possible, i.e. when platform and device index + * are known. + * + * Topology \p topology and device \p device must match the local machine. + * I/O devices detection and the OpenCL component must be enabled in the topology. + * If not, the locality of the object may still be found using + * hwloc_opencl_get_device_cpuset(). + * + * \note This function cannot work if PCI devices are filtered out. + * + * \note The corresponding hwloc PCI device may be found by looking + * at the result parent pointer (unless PCI devices are filtered out). + */ +static __hwloc_inline hwloc_obj_t +hwloc_opencl_get_device_osdev(hwloc_topology_t topology __hwloc_attribute_unused, + cl_device_id device __hwloc_attribute_unused) +{ + hwloc_obj_t osdev; + unsigned pcidomain, pcibus, pcidevice, pcifunc; + + if (hwloc_opencl_get_device_pci_busid(device, &pcidomain, &pcibus, &pcidevice, &pcifunc) < 0) { + errno = EINVAL; + return NULL; + } + + osdev = NULL; + while ((osdev = hwloc_get_next_osdev(topology, osdev)) != NULL) { + hwloc_obj_t pcidev = osdev->parent; + if (strncmp(osdev->name, "opencl", 6)) + continue; + if (pcidev + && pcidev->type == HWLOC_OBJ_PCI_DEVICE + && pcidev->attr->pcidev.domain == pcidomain + && pcidev->attr->pcidev.bus == pcibus + && pcidev->attr->pcidev.dev == pcidevice + && pcidev->attr->pcidev.func == pcifunc) + return osdev; + /* if PCI are filtered out, we need a info attr to match on */ + } + + return NULL; +} + +/** @} */ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* HWLOC_OPENCL_H */ diff --git a/src/deps/hwloc/include/hwloc/openfabrics-verbs.h b/src/deps/hwloc/include/hwloc/openfabrics-verbs.h new file mode 100644 index 000000000..9ba4888d0 --- /dev/null +++ b/src/deps/hwloc/include/hwloc/openfabrics-verbs.h @@ -0,0 +1,156 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * Copyright © 2009 CNRS + * Copyright © 2009-2023 Inria. All rights reserved. + * Copyright © 2009-2010 Université Bordeaux + * Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved. + * See COPYING in top-level directory. + */ + +/** \file + * \brief Macros to help interaction between hwloc and OpenFabrics + * verbs. + * + * Applications that use both hwloc and OpenFabrics verbs may want to + * include this file so as to get topology information for OpenFabrics + * hardware (InfiniBand, etc). + * + */ + +#ifndef HWLOC_OPENFABRICS_VERBS_H +#define HWLOC_OPENFABRICS_VERBS_H + +#include "hwloc.h" +#include "hwloc/autogen/config.h" +#ifdef HWLOC_LINUX_SYS +#include "hwloc/linux.h" +#endif + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** \defgroup hwlocality_openfabrics Interoperability with OpenFabrics + * + * This interface offers ways to retrieve topology information about + * OpenFabrics devices (InfiniBand, Omni-Path, usNIC, etc). + * + * @{ + */ + +/** \brief Get the CPU set of processors that are physically + * close to device \p ibdev. + * + * Store in \p set the CPU-set describing the locality of the OpenFabrics + * device \p ibdev (InfiniBand, etc). + * + * Topology \p topology and device \p ibdev must match the local machine. + * I/O devices detection is not needed in the topology. + * + * The function only returns the locality of the device. + * If more information about the device is needed, OS objects should + * be used instead, see hwloc_ibv_get_device_osdev() + * and hwloc_ibv_get_device_osdev_by_name(). + * + * This function is currently only implemented in a meaningful way for + * Linux; other systems will simply get a full cpuset. + * + * \return 0 on success. + * \return -1 on error, for instance if device information could not be found. + */ +static __hwloc_inline int +hwloc_ibv_get_device_cpuset(hwloc_topology_t topology __hwloc_attribute_unused, + struct ibv_device *ibdev, hwloc_cpuset_t set) +{ +#ifdef HWLOC_LINUX_SYS + /* If we're on Linux, use the verbs-provided sysfs mechanism to + get the local cpus */ +#define HWLOC_OPENFABRICS_VERBS_SYSFS_PATH_MAX 128 + char path[HWLOC_OPENFABRICS_VERBS_SYSFS_PATH_MAX]; + + if (!hwloc_topology_is_thissystem(topology)) { + errno = EINVAL; + return -1; + } + + sprintf(path, "/sys/class/infiniband/%s/device/local_cpus", + ibv_get_device_name(ibdev)); + if (hwloc_linux_read_path_as_cpumask(path, set) < 0 + || hwloc_bitmap_iszero(set)) + hwloc_bitmap_copy(set, hwloc_topology_get_complete_cpuset(topology)); +#else + /* Non-Linux systems simply get a full cpuset */ + hwloc_bitmap_copy(set, hwloc_topology_get_complete_cpuset(topology)); +#endif + return 0; +} + +/** \brief Get the hwloc OS device object corresponding to the OpenFabrics + * device named \p ibname. + * + * \return The hwloc OS device object describing the OpenFabrics device + * (InfiniBand, Omni-Path, usNIC, etc) whose name is \p ibname + * (mlx5_0, hfi1_0, usnic_0, qib0, etc). + * \return \c NULL if none could be found. + * + * The name \p ibname is usually obtained from ibv_get_device_name(). + * + * The topology \p topology does not necessarily have to match the current + * machine. For instance the topology may be an XML import of a remote host. + * I/O devices detection must be enabled in the topology. + * + * \note The corresponding PCI device object can be obtained by looking + * at the OS device parent object. + */ +static __hwloc_inline hwloc_obj_t +hwloc_ibv_get_device_osdev_by_name(hwloc_topology_t topology, + const char *ibname) +{ + hwloc_obj_t osdev = NULL; + while ((osdev = hwloc_get_next_osdev(topology, osdev)) != NULL) { + if (HWLOC_OBJ_OSDEV_OPENFABRICS == osdev->attr->osdev.type + && osdev->name && !strcmp(ibname, osdev->name)) + return osdev; + } + return NULL; +} + +/** \brief Get the hwloc OS device object corresponding to the OpenFabrics + * device \p ibdev. + * + * \return The hwloc OS device object describing the OpenFabrics + * device \p ibdev (InfiniBand, etc). + * \return \c NULL if none could be found. + * + * Topology \p topology and device \p ibdev must match the local machine. + * I/O devices detection must be enabled in the topology. + * If not, the locality of the object may still be found using + * hwloc_ibv_get_device_cpuset(). + * + * \note The corresponding PCI device object can be obtained by looking + * at the OS device parent object. + */ +static __hwloc_inline hwloc_obj_t +hwloc_ibv_get_device_osdev(hwloc_topology_t topology, + struct ibv_device *ibdev) +{ + if (!hwloc_topology_is_thissystem(topology)) { + errno = EINVAL; + return NULL; + } + return hwloc_ibv_get_device_osdev_by_name(topology, ibv_get_device_name(ibdev)); +} + +/** @} */ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* HWLOC_OPENFABRICS_VERBS_H */ diff --git a/src/deps/hwloc/include/hwloc/plugins.h b/src/deps/hwloc/include/hwloc/plugins.h new file mode 100644 index 000000000..ad6f28911 --- /dev/null +++ b/src/deps/hwloc/include/hwloc/plugins.h @@ -0,0 +1,704 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * Copyright © 2013-2024 Inria. All rights reserved. + * Copyright © 2016 Cisco Systems, Inc. All rights reserved. + * Copyright © 2025 Siemens Corporation and/or its affiliates. All rights reserved. + * See COPYING in top-level directory. + */ + +#ifndef HWLOC_PLUGINS_H +#define HWLOC_PLUGINS_H + +/** \file + * \brief Public interface for building hwloc plugins. + */ + +struct hwloc_backend; + +#include "hwloc.h" + +#ifdef HWLOC_INSIDE_PLUGIN +/* needed for hwloc_plugin_check_namespace() */ +#ifdef HWLOC_HAVE_LTDL +#include +#elif !defined(HWLOC_WIN_SYS) +#include +#endif +#endif + + + +/** \defgroup hwlocality_disc_components Components and Plugins: Discovery components and backends + * + * \note These structures and functions may change when ::HWLOC_COMPONENT_ABI is modified. + * + * @{ + */ + +/** \brief Discovery component structure + * + * This is the major kind of components, taking care of the discovery. + * They are registered by generic components, either statically-built or as plugins. + */ +struct hwloc_disc_component { + /** \brief Name. + * If this component is built as a plugin, this name does not have to match the plugin filename. + */ + const char *name; + + /** \brief Discovery phases performed by this component. + * OR'ed set of ::hwloc_disc_phase_t + */ + unsigned phases; + + /** \brief Component phases to exclude, as an OR'ed set of ::hwloc_disc_phase_t. + * + * For a GLOBAL component, this usually includes all other phases (\c ~UL). + * + * Other components only exclude types that may bring conflicting + * topology information. MISC components should likely not be excluded + * since they usually bring non-primary additional information. + */ + unsigned excluded_phases; + + /** \brief Instantiate callback to create a backend from the component. + * Parameters data1, data2, data3 are NULL except for components + * that have special enabling routines such as hwloc_topology_set_xml(). */ + struct hwloc_backend * (*instantiate)(struct hwloc_topology *topology, struct hwloc_disc_component *component, unsigned excluded_phases, const void *data1, const void *data2, const void *data3); + + /** \brief Component priority. + * Used to sort topology->components, higher priority first. + * Also used to decide between two components with the same name. + * + * Usual values are + * 50 for native OS (or platform) components, + * 45 for x86, + * 40 for no-OS fallback, + * 30 for global components (xml, synthetic), + * 20 for pci, + * 10 for other misc components (opencl etc.). + */ + unsigned priority; + + /** \brief Enabled by default. + * If unset, if will be disabled unless explicitly requested. + */ + unsigned enabled_by_default; + + /** \private Used internally to list components by priority on topology->components + * (the component structure is usually read-only, + * the core copies it before using this field for queueing) + */ + struct hwloc_disc_component * next; +}; + +/** \brief Discovery phase */ +typedef enum hwloc_disc_phase_e { + /** \brief xml or synthetic, platform-specific components such as bgq. + * Discovers everything including CPU, memory, I/O and everything else. + * A component with a Global phase usually excludes all other phases. + * \hideinitializer */ + HWLOC_DISC_PHASE_GLOBAL = (1U<<0), + + /** \brief CPU discovery. + * \hideinitializer */ + HWLOC_DISC_PHASE_CPU = (1U<<1), + + /** \brief Attach memory to existing CPU objects. + * \hideinitializer */ + HWLOC_DISC_PHASE_MEMORY = (1U<<2), + + /** \brief Attach PCI devices and bridges to existing CPU objects. + * \hideinitializer */ + HWLOC_DISC_PHASE_PCI = (1U<<3), + + /** \brief I/O discovery that requires PCI devices (OS devices such as OpenCL, CUDA, etc.). + * \hideinitializer */ + HWLOC_DISC_PHASE_IO = (1U<<4), + + /** \brief Misc objects that gets added below anything else. + * \hideinitializer */ + HWLOC_DISC_PHASE_MISC = (1U<<5), + + /** \brief Annotating existing objects, adding distances, etc. + * \hideinitializer */ + HWLOC_DISC_PHASE_ANNOTATE = (1U<<6), + + /** \brief Final tweaks to a ready-to-use topology. + * This phase runs once the topology is loaded, before it is returned to the topology. + * Hence it may only use the main hwloc API for modifying the topology, + * for instance by restricting it, adding info attributes, etc. + * \hideinitializer */ + HWLOC_DISC_PHASE_TWEAK = (1U<<7) +} hwloc_disc_phase_t; + +/** \brief Discovery status flags */ +enum hwloc_disc_status_flag_e { + /** \brief The sets of allowed resources were already retrieved \hideinitializer */ + HWLOC_DISC_STATUS_FLAG_GOT_ALLOWED_RESOURCES = (1UL<<1) +}; + +/** \brief Discovery status structure + * + * Used by the core and backends to inform about what has been/is being done + * during the discovery process. + */ +struct hwloc_disc_status { + /** \brief The current discovery phase that is performed. + * Must match one of the phases in the component phases field. + */ + hwloc_disc_phase_t phase; + + /** \brief Dynamically excluded phases. + * If a component decides during discovery that some phases are no longer needed. + */ + unsigned excluded_phases; + + /** \brief OR'ed set of ::hwloc_disc_status_flag_e */ + unsigned long flags; +}; + +/** \brief Discovery backend structure + * + * A backend is the instantiation of a discovery component. + * When a component gets enabled for a topology, + * its instantiate() callback creates a backend. + * + * hwloc_backend_alloc() initializes all fields to default values + * that the component may change (except "component" and "next") + * before enabling the backend with hwloc_backend_enable(). + * + * Most backends assume that the topology is_thissystem flag is + * set because they talk to the underlying operating system. + * However they may still be used in topologies without the + * is_thissystem flag for debugging reasons. + * In practice, they are usually auto-disabled in such cases + * (excluded by xml or synthetic backends, or by environment + * variables when changing the Linux fsroot or the x86 cpuid path). + */ +struct hwloc_backend { + /** \private Reserved for the core, set by hwloc_backend_alloc() */ + struct hwloc_disc_component * component; + /** \private Reserved for the core, set by hwloc_backend_enable() */ + struct hwloc_topology * topology; + /** \private Reserved for the core. Set to 1 if forced through envvar, 0 otherwise. */ + int envvar_forced; + /** \private Reserved for the core. Used internally to list backends topology->backends. */ + struct hwloc_backend * next; + + /** \brief Discovery phases performed by this component, possibly without some of them if excluded by other components. + * OR'ed set of ::hwloc_disc_phase_t + */ + unsigned phases; + + /** \brief Backend flags, currently always 0. */ + unsigned long flags; + + /** \brief Backend-specific 'is_thissystem' property. + * Set to 0 if the backend disables the thissystem flag for this topology + * (e.g. loading from xml or synthetic string, + * or using a different fsroot on Linux, or a x86 CPUID dump). + * Set to -1 if the backend doesn't care (default). + */ + int is_thissystem; + + /** \brief Backend private data, or NULL if none. */ + void * private_data; + /** \brief Callback for freeing the private_data. + * May be NULL. + */ + void (*disable)(struct hwloc_backend *backend); + + /** \brief Main discovery callback. + * returns -1 on error, either because it couldn't add its objects ot the existing topology, + * or because of an actual discovery/gathering failure. + * May be NULL. + */ + int (*discover)(struct hwloc_backend *backend, struct hwloc_disc_status *status); + + /** \brief Callback to retrieve the locality of a PCI object. + * Called by the PCI core when attaching PCI hierarchy to CPU objects. + * May be NULL. + */ + int (*get_pci_busid_cpuset)(struct hwloc_backend *backend, struct hwloc_pcidev_attr_s *busid, hwloc_bitmap_t cpuset); +}; + +/** \brief Allocate a backend structure, set good default values, initialize backend->component and topology, etc. + * The caller will then modify whatever needed, and call hwloc_backend_enable(). + */ +HWLOC_DECLSPEC struct hwloc_backend * hwloc_backend_alloc(struct hwloc_topology *topology, struct hwloc_disc_component *component); + +/** \brief Enable a previously allocated and setup backend. */ +HWLOC_DECLSPEC int hwloc_backend_enable(struct hwloc_backend *backend); + +/** @} */ + + + + +/** \defgroup hwlocality_generic_components Components and Plugins: Generic components + * + * \note These structures and functions may change when ::HWLOC_COMPONENT_ABI is modified. + * + * @{ + */ + +/** \brief Generic component type */ +typedef enum hwloc_component_type_e { + /** \brief The data field must point to a struct hwloc_disc_component. */ + HWLOC_COMPONENT_TYPE_DISC, + + /** \brief The data field must point to a struct hwloc_xml_component. */ + HWLOC_COMPONENT_TYPE_XML +} hwloc_component_type_t; + +/** \brief Generic component structure + * + * Generic components structure, either statically listed by configure in static-components.h + * or dynamically loaded as a plugin. + */ +struct hwloc_component { + /** \brief Component ABI version, set to ::HWLOC_COMPONENT_ABI */ + unsigned abi; + + /** \brief Process-wide component initialization callback. + * + * This optional callback is called when the component is registered + * to the hwloc core (after loading the plugin). + * + * When the component is built as a plugin, this callback + * should call hwloc_check_plugin_namespace() + * and return an negative error code on error. + * + * \p flags is always 0 for now. + * + * \return 0 on success, or a negative code on error. + * + * \note If the component uses ltdl for loading its own plugins, + * it should load/unload them only in init() and finalize(), + * to avoid race conditions with hwloc's use of ltdl. + */ + int (*init)(unsigned long flags); + + /** \brief Process-wide component termination callback. + * + * This optional callback is called after unregistering the component + * from the hwloc core (before unloading the plugin). + * + * \p flags is always 0 for now. + * + * \note If the component uses ltdl for loading its own plugins, + * it should load/unload them only in init() and finalize(), + * to avoid race conditions with hwloc's use of ltdl. + */ + void (*finalize)(unsigned long flags); + + /** \brief Component type */ + hwloc_component_type_t type; + + /** \brief Component flags, unused for now */ + unsigned long flags; + + /** \brief Component data, pointing to a struct hwloc_disc_component or struct hwloc_xml_component. */ + void * data; +}; + +/** \brief Make sure that plugins can lookup core symbols. + * + * This is a sanity check to avoid lazy-lookup failures when libhwloc + * is loaded within a plugin, and later tries to load its own plugins. + * This may fail (and abort the program) if libhwloc symbols are in a + * private namespace. + * + * \return 0 on success. + * \return -1 if the plugin cannot be successfully loaded. The caller + * plugin init() callback should return a negative error code as well. + * + * Plugins should call this function in their init() callback to avoid + * later crashes if lazy symbol resolution is used by the upper layer that + * loaded hwloc (e.g. OpenCL implementations using dlopen with RTLD_LAZY). + * + * \note The build system must define HWLOC_INSIDE_PLUGIN if and only if + * building the caller as a plugin. + * + * \note This function should remain inline so plugins can call it even + * when they cannot find libhwloc symbols. + */ +static __hwloc_inline int +hwloc_plugin_check_namespace(const char *pluginname __hwloc_attribute_unused, const char *symbol __hwloc_attribute_unused) +{ +#ifdef HWLOC_INSIDE_PLUGIN + void *sym; +#ifdef HWLOC_HAVE_LTDL + lt_dlhandle handle = lt_dlopen(NULL); +#elif defined(HWLOC_WIN_SYS) + HMODULE handle = GetModuleHandleA(NULL); +#else + void *handle = dlopen(NULL, RTLD_NOW|RTLD_LOCAL); +#endif + if (!handle) + /* cannot check, assume things will work */ + return 0; +#ifdef HWLOC_HAVE_LTDL + sym = lt_dlsym(handle, symbol); + lt_dlclose(handle); +#elif defined(HWLOC_WIN_SYS) + sym = GetModuleHandleA("hwloc.dll"); + FreeLibrary(handle); +#else + sym = dlsym(handle, symbol); + dlclose(handle); +#endif + if (!sym) { + static int verboseenv_checked = 0; + static int verboseenv_value = 0; + if (!verboseenv_checked) { + const char *verboseenv = getenv("HWLOC_PLUGINS_VERBOSE"); + verboseenv_value = verboseenv ? atoi(verboseenv) : 0; + verboseenv_checked = 1; + } + if (verboseenv_value) + fprintf(stderr, "Plugin `%s' disabling itself because it cannot find the `%s' core symbol.\n", + pluginname, symbol); + return -1; + } +#endif /* HWLOC_INSIDE_PLUGIN */ + return 0; +} + +/** @} */ + + + + +/** \defgroup hwlocality_components_core_funcs Components and Plugins: Core functions to be used by components + * + * \note These structures and functions may change when ::HWLOC_COMPONENT_ABI is modified. + * + * @{ + */ + +/** \brief Check whether error messages are hidden. + * + * Callers should print critical error messages + * (e.g. invalid hw topo info, invalid config) + * only if this function returns strictly less than 2. + * + * Callers should print non-critical error messages + * (e.g. failure to initialize CUDA) + * if this function returns 0. + * + * This function return 1 by default (show critical only), + * 0 in lstopo (show all), + * or anything set in HWLOC_HIDE_ERRORS in the environment. + * + * Use macros HWLOC_SHOW_CRITICAL_ERRORS() and HWLOC_SHOW_ALL_ERRORS() + * for clarity. + */ +HWLOC_DECLSPEC int hwloc_hide_errors(void); + +#define HWLOC_SHOW_CRITICAL_ERRORS() (hwloc_hide_errors() < 2) +#define HWLOC_SHOW_ALL_ERRORS() (hwloc_hide_errors() == 0) + +/** \brief Add an object to the topology. + * + * Insert new object \p obj in the topology starting under existing object \p root + * (if \c NULL, the topology root object is used). + * + * It is sorted along the tree of other objects according to the inclusion of + * cpusets, to eventually be added as a child of the smallest object including + * this object. + * + * If the cpuset is empty, the type of the object (and maybe some attributes) + * must be enough to find where to insert the object. This is especially true + * for NUMA nodes with memory and no CPUs. + * + * The given object should not have children. + * + * This shall only be called before levels are built. + * + * The caller should check whether the object type is filtered-out before calling this function. + * + * The topology cpuset/nodesets will be enlarged to include the object sets. + * + * \p reason is a unique string identifying where and why this insertion call was performed + * (it will be displayed in case of internal insertion error). + * + * Returns the object on success. + * Returns NULL and frees obj on error. + * Returns another object and frees obj if it was merged with an identical pre-existing object. + */ +HWLOC_DECLSPEC hwloc_obj_t +hwloc__insert_object_by_cpuset(struct hwloc_topology *topology, hwloc_obj_t root, + hwloc_obj_t obj, const char *reason); + +/** \brief Insert an object somewhere in the topology. + * + * It is added as the last child of the given parent. + * The cpuset is completely ignored, so strange objects such as I/O devices should + * preferably be inserted with this. + * + * When used for "normal" children with cpusets (when importing from XML + * when duplicating a topology), the caller should make sure that: + * - children are inserted in order, + * - children cpusets do not intersect. + * + * The given object may have normal, I/O or Misc children, as long as they are in order as well. + * These children must have valid parent and next_sibling pointers. + * + * The caller should check whether the object type is filtered-out before calling this function. + */ +HWLOC_DECLSPEC void hwloc_insert_object_by_parent(struct hwloc_topology *topology, hwloc_obj_t parent, hwloc_obj_t obj); + +/** \brief Allocate and initialize an object of the given type and physical index. + * + * If \p os_index is unknown or irrelevant, use \c HWLOC_UNKNOWN_INDEX. + */ +HWLOC_DECLSPEC hwloc_obj_t hwloc_alloc_setup_object(hwloc_topology_t topology, hwloc_obj_type_t type, unsigned os_index); + +/** \brief Setup object cpusets/nodesets by OR'ing its children. + * + * Used when adding an object late in the topology. + * Will update the new object by OR'ing all its new children sets. + * + * Used when PCI backend adds a hostbridge parent, when distances + * add a new Group, etc. + */ +HWLOC_DECLSPEC int hwloc_obj_add_children_sets(hwloc_obj_t obj); + +/** \brief Request a reconnection of children and levels in the topology. + * + * May be used by backends during discovery if they need arrays or lists + * of object within levels or children to be fully connected. + * + * \p flags is currently unused, must 0. + */ +HWLOC_DECLSPEC int hwloc_topology_reconnect(hwloc_topology_t topology, unsigned long flags __hwloc_attribute_unused); + +/** @} */ + + + + +/** \defgroup hwlocality_components_filtering Components and Plugins: Filtering objects + * + * \note These structures and functions may change when ::HWLOC_COMPONENT_ABI is modified. + * + * @{ + */ + +/** \brief Check whether the given PCI device classid is important. + * + * \return 1 if important, 0 otherwise. + */ +static __hwloc_inline int +hwloc_filter_check_pcidev_subtype_important(unsigned classid) +{ + unsigned baseclass = classid >> 8; + return (baseclass == 0x03 /* PCI_BASE_CLASS_DISPLAY */ + || baseclass == 0x02 /* PCI_BASE_CLASS_NETWORK */ + || baseclass == 0x01 /* PCI_BASE_CLASS_STORAGE */ + || baseclass == 0x00 /* Unclassified, for Atos/Bull BXI */ + || baseclass == 0x0b /* PCI_BASE_CLASS_PROCESSOR */ + || classid == 0x0c04 /* PCI_CLASS_SERIAL_FIBER */ + || classid == 0x0c06 /* PCI_CLASS_SERIAL_INFINIBAND */ + || classid == 0x0502 /* PCI_CLASS_MEMORY_CXL */ + || baseclass == 0x06 /* PCI_BASE_CLASS_BRIDGE with non-PCI downstream. the core will drop the useless ones later */ + || baseclass == 0x12 /* Processing Accelerators */); +} + +/** \brief Check whether the given OS device subtype is important. + * + * \return 1 if important, 0 otherwise. + */ +static __hwloc_inline int +hwloc_filter_check_osdev_subtype_important(hwloc_obj_osdev_type_t subtype) +{ + return (subtype != HWLOC_OBJ_OSDEV_DMA); +} + +/** \brief Check whether a non-I/O object type should be filtered-out. + * + * Cannot be used for I/O objects. + * + * \return 1 if the object type should be kept, 0 otherwise. + */ +static __hwloc_inline int +hwloc_filter_check_keep_object_type(hwloc_topology_t topology, hwloc_obj_type_t type) +{ + enum hwloc_type_filter_e filter = HWLOC_TYPE_FILTER_KEEP_NONE; + hwloc_topology_get_type_filter(topology, type, &filter); + assert(filter != HWLOC_TYPE_FILTER_KEEP_IMPORTANT); /* IMPORTANT only used for I/O */ + return filter == HWLOC_TYPE_FILTER_KEEP_NONE ? 0 : 1; +} + +/** \brief Check whether the given object should be filtered-out. + * + * \return 1 if the object type should be kept, 0 otherwise. + */ +static __hwloc_inline int +hwloc_filter_check_keep_object(hwloc_topology_t topology, hwloc_obj_t obj) +{ + hwloc_obj_type_t type = obj->type; + enum hwloc_type_filter_e filter = HWLOC_TYPE_FILTER_KEEP_NONE; + hwloc_topology_get_type_filter(topology, type, &filter); + if (filter == HWLOC_TYPE_FILTER_KEEP_NONE) + return 0; + if (filter == HWLOC_TYPE_FILTER_KEEP_IMPORTANT) { + if (type == HWLOC_OBJ_PCI_DEVICE) + return hwloc_filter_check_pcidev_subtype_important(obj->attr->pcidev.class_id); + if (type == HWLOC_OBJ_OS_DEVICE) + return hwloc_filter_check_osdev_subtype_important(obj->attr->osdev.type); + } + return 1; +} + +/** @} */ + + + + +/** \defgroup hwlocality_components_pcidisc Components and Plugins: helpers for PCI discovery + * + * \note These structures and functions may change when ::HWLOC_COMPONENT_ABI is modified. + * + * @{ + */ + +/** \brief Return the offset of the given capability in the PCI config space buffer + * + * This function requires a 256-bytes config space. Unknown/unavailable bytes should be set to 0xff. + */ +HWLOC_DECLSPEC unsigned hwloc_pcidisc_find_cap(const unsigned char *config, unsigned cap); + +/** \brief Fill linkspeed by reading the PCI config space where PCI_CAP_ID_EXP is at position offset. + * + * Needs 20 bytes of EXP capability block starting at offset in the config space + * for registers up to link status. + */ +HWLOC_DECLSPEC int hwloc_pcidisc_find_linkspeed(const unsigned char *config, unsigned offset, float *linkspeed); + +/** \brief Return the hwloc object type (PCI device or Bridge) for the given class and configuration space. + * + * This function requires 16 bytes of common configuration header at the beginning of config. + */ +HWLOC_DECLSPEC hwloc_obj_type_t hwloc_pcidisc_check_bridge_type(unsigned device_class, const unsigned char *config); + +/** \brief Fills the attributes of the given PCI bridge using the given PCI config space. + * + * This function requires 32 bytes of common configuration header at the beginning of config. + * + * Returns -1 and destroys /p obj if bridge fields are invalid. + */ +HWLOC_DECLSPEC int hwloc_pcidisc_find_bridge_buses(unsigned domain, unsigned bus, unsigned dev, unsigned func, + unsigned *secondary_busp, unsigned *subordinate_busp, + const unsigned char *config); + +/** \brief Insert a PCI object in the given PCI tree by looking at PCI bus IDs. + * + * If \p treep points to \c NULL, the new object is inserted there. + */ +HWLOC_DECLSPEC void hwloc_pcidisc_tree_insert_by_busid(struct hwloc_obj **treep, struct hwloc_obj *obj); + +/** \brief Add some hostbridges on top of the given tree of PCI objects and attach them to the topology. + * + * Other backends may lookup PCI objects or localities (for instance to attach OS devices) + * by using hwloc_pcidisc_find_by_busid() or hwloc_pcidisc_find_busid_parent(). + */ +HWLOC_DECLSPEC int hwloc_pcidisc_tree_attach(struct hwloc_topology *topology, struct hwloc_obj *tree); + +/** @} */ + + + + +/** \defgroup hwlocality_components_pcifind Components and Plugins: finding PCI objects during other discoveries + * + * \note These structures and functions may change when ::HWLOC_COMPONENT_ABI is modified. + * + * @{ + */ + +/** \brief Find the object or a parent of a PCI bus ID. + * + * When attaching a new object (typically an OS device) whose locality + * is specified by PCI bus ID, this function returns the PCI object + * to use as a parent for attaching. + * + * If the exact PCI device with this bus ID exists, it is returned. + * Otherwise (for instance if it was filtered out), the function returns + * another object with similar locality (for instance a parent bridge, + * or the local CPU Package). + */ +HWLOC_DECLSPEC struct hwloc_obj * hwloc_pci_find_parent_by_busid(struct hwloc_topology *topology, unsigned domain, unsigned bus, unsigned dev, unsigned func); + +/** \brief Find the PCI device or bridge matching a PCI bus ID exactly. + * + * This is useful for adding specific information about some objects + * based on their PCI id. When it comes to attaching objects based on + * PCI locality, hwloc_pci_find_parent_by_busid() should be preferred. + */ +HWLOC_DECLSPEC struct hwloc_obj * hwloc_pci_find_by_busid(struct hwloc_topology *topology, unsigned domain, unsigned bus, unsigned dev, unsigned func); + + +/** @} */ + + + + +/** \defgroup hwlocality_components_distances Components and Plugins: distances + * + * \note These structures and functions may change when ::HWLOC_COMPONENT_ABI is modified. + * + * @{ + */ + +/** \brief Handle to a new distances structure during its addition to the topology. */ +typedef void * hwloc_backend_distances_add_handle_t; + +/** \brief Create a new empty distances structure. + * + * This is identical to hwloc_distances_add_create() + * but this variant is designed for backend inserting + * distances during topology discovery. + */ +HWLOC_DECLSPEC hwloc_backend_distances_add_handle_t +hwloc_backend_distances_add_create(hwloc_topology_t topology, + const char *name, unsigned long kind, + unsigned long flags); + +/** \brief Specify the objects and values in a new empty distances structure. + * + * This is similar to hwloc_distances_add_values() + * but this variant is designed for backend inserting + * distances during topology discovery. + * + * The only semantical difference is that \p objs and \p values + * are not duplicated, but directly attached to the topology. + * On success, these arrays are given to the core and should not + * ever be freed by the caller anymore. + */ +HWLOC_DECLSPEC int +hwloc_backend_distances_add_values(hwloc_topology_t topology, + hwloc_backend_distances_add_handle_t handle, + unsigned nbobjs, hwloc_obj_t *objs, + hwloc_uint64_t *values, + unsigned long flags); + +/** \brief Commit a new distances structure. + * + * This is similar to hwloc_distances_add_commit() + * but this variant is designed for backend inserting + * distances during topology discovery. + */ +HWLOC_DECLSPEC int +hwloc_backend_distances_add_commit(hwloc_topology_t topology, + hwloc_backend_distances_add_handle_t handle, + unsigned long flags); + +/** @} */ + + + + +#endif /* HWLOC_PLUGINS_H */ diff --git a/src/deps/hwloc/include/hwloc/rename.h b/src/deps/hwloc/include/hwloc/rename.h new file mode 100644 index 000000000..ef0355e0c --- /dev/null +++ b/src/deps/hwloc/include/hwloc/rename.h @@ -0,0 +1,923 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved. + * Copyright © 2010-2025 Inria. All rights reserved. + * See COPYING in top-level directory. + */ + +#ifndef HWLOC_RENAME_H +#define HWLOC_RENAME_H + +#include "hwloc/autogen/config.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* Only enact these defines if we're actually renaming the symbols + (i.e., avoid trying to have no-op defines if we're *not* + renaming). */ + +#if HWLOC_SYM_TRANSFORM + +/* Use a preprocessor two-step in order to get the prefixing right. + Make 2 macros: HWLOC_NAME and HWLOC_NAME_CAPS for renaming + things. */ + +#define HWLOC_MUNGE_NAME(a, b) HWLOC_MUNGE_NAME2(a, b) +#define HWLOC_MUNGE_NAME2(a, b) a ## b +#define HWLOC_NAME(name) HWLOC_MUNGE_NAME(HWLOC_SYM_PREFIX, hwloc_ ## name) +/* FIXME: should be "HWLOC_ ## name" below, unchanged because it doesn't matter much and could break some embedders hacks */ +#define HWLOC_NAME_CAPS(name) HWLOC_MUNGE_NAME(HWLOC_SYM_PREFIX_CAPS, hwloc_ ## name) + +/* Now define all the "real" names to be the prefixed names. This + allows us to use the real names throughout the code base (i.e., + "hwloc_"); the preprocessor will adjust to have the prefixed + name under the covers. */ + +/* Names from hwloc.h */ + +#define hwloc_get_api_version HWLOC_NAME(get_api_version) + +#define hwloc_topology HWLOC_NAME(topology) +#define hwloc_topology_t HWLOC_NAME(topology_t) + +#define hwloc_cpuset_t HWLOC_NAME(cpuset_t) +#define hwloc_const_cpuset_t HWLOC_NAME(const_cpuset_t) +#define hwloc_nodeset_t HWLOC_NAME(nodeset_t) +#define hwloc_const_nodeset_t HWLOC_NAME(const_nodeset_t) + +#define HWLOC_OBJ_MACHINE HWLOC_NAME_CAPS(OBJ_MACHINE) +#define HWLOC_OBJ_NUMANODE HWLOC_NAME_CAPS(OBJ_NUMANODE) +#define HWLOC_OBJ_MEMCACHE HWLOC_NAME_CAPS(OBJ_MEMCACHE) +#define HWLOC_OBJ_PACKAGE HWLOC_NAME_CAPS(OBJ_PACKAGE) +#define HWLOC_OBJ_DIE HWLOC_NAME_CAPS(OBJ_DIE) +#define HWLOC_OBJ_CORE HWLOC_NAME_CAPS(OBJ_CORE) +#define HWLOC_OBJ_PU HWLOC_NAME_CAPS(OBJ_PU) +#define HWLOC_OBJ_L1CACHE HWLOC_NAME_CAPS(OBJ_L1CACHE) +#define HWLOC_OBJ_L2CACHE HWLOC_NAME_CAPS(OBJ_L2CACHE) +#define HWLOC_OBJ_L3CACHE HWLOC_NAME_CAPS(OBJ_L3CACHE) +#define HWLOC_OBJ_L4CACHE HWLOC_NAME_CAPS(OBJ_L4CACHE) +#define HWLOC_OBJ_L5CACHE HWLOC_NAME_CAPS(OBJ_L5CACHE) +#define HWLOC_OBJ_L1ICACHE HWLOC_NAME_CAPS(OBJ_L1ICACHE) +#define HWLOC_OBJ_L2ICACHE HWLOC_NAME_CAPS(OBJ_L2ICACHE) +#define HWLOC_OBJ_L3ICACHE HWLOC_NAME_CAPS(OBJ_L3ICACHE) +#define HWLOC_OBJ_MISC HWLOC_NAME_CAPS(OBJ_MISC) +#define HWLOC_OBJ_GROUP HWLOC_NAME_CAPS(OBJ_GROUP) +#define HWLOC_OBJ_BRIDGE HWLOC_NAME_CAPS(OBJ_BRIDGE) +#define HWLOC_OBJ_PCI_DEVICE HWLOC_NAME_CAPS(OBJ_PCI_DEVICE) +#define HWLOC_OBJ_OS_DEVICE HWLOC_NAME_CAPS(OBJ_OS_DEVICE) +#define HWLOC_OBJ_TYPE_MAX HWLOC_NAME_CAPS(OBJ_TYPE_MAX) +#define hwloc_obj_type_t HWLOC_NAME(obj_type_t) + +#define hwloc_obj_cache_type_e HWLOC_NAME(obj_cache_type_e) +#define hwloc_obj_cache_type_t HWLOC_NAME(obj_cache_type_t) +#define HWLOC_OBJ_CACHE_UNIFIED HWLOC_NAME_CAPS(OBJ_CACHE_UNIFIED) +#define HWLOC_OBJ_CACHE_DATA HWLOC_NAME_CAPS(OBJ_CACHE_DATA) +#define HWLOC_OBJ_CACHE_INSTRUCTION HWLOC_NAME_CAPS(OBJ_CACHE_INSTRUCTION) + +#define hwloc_obj_bridge_type_e HWLOC_NAME(obj_bridge_type_e) +#define hwloc_obj_bridge_type_t HWLOC_NAME(obj_bridge_type_t) +#define HWLOC_OBJ_BRIDGE_HOST HWLOC_NAME_CAPS(OBJ_BRIDGE_HOST) +#define HWLOC_OBJ_BRIDGE_PCI HWLOC_NAME_CAPS(OBJ_BRIDGE_PCI) + +#define hwloc_obj_osdev_type_e HWLOC_NAME(obj_osdev_type_e) +#define hwloc_obj_osdev_type_t HWLOC_NAME(obj_osdev_type_t) +#define HWLOC_OBJ_OSDEV_BLOCK HWLOC_NAME_CAPS(OBJ_OSDEV_BLOCK) +#define HWLOC_OBJ_OSDEV_GPU HWLOC_NAME_CAPS(OBJ_OSDEV_GPU) +#define HWLOC_OBJ_OSDEV_NETWORK HWLOC_NAME_CAPS(OBJ_OSDEV_NETWORK) +#define HWLOC_OBJ_OSDEV_OPENFABRICS HWLOC_NAME_CAPS(OBJ_OSDEV_OPENFABRICS) +#define HWLOC_OBJ_OSDEV_DMA HWLOC_NAME_CAPS(OBJ_OSDEV_DMA) +#define HWLOC_OBJ_OSDEV_COPROC HWLOC_NAME_CAPS(OBJ_OSDEV_COPROC) + +#define hwloc_compare_types HWLOC_NAME(compare_types) + +#define hwloc_obj HWLOC_NAME(obj) +#define hwloc_obj_t HWLOC_NAME(obj_t) + +#define hwloc_info_s HWLOC_NAME(info_s) + +#define hwloc_obj_attr_u HWLOC_NAME(obj_attr_u) +#define hwloc_numanode_attr_s HWLOC_NAME(numanode_attr_s) +#define hwloc_memory_page_type_s HWLOC_NAME(memory_page_type_s) +#define hwloc_cache_attr_s HWLOC_NAME(cache_attr_s) +#define hwloc_group_attr_s HWLOC_NAME(group_attr_s) +#define hwloc_pcidev_attr_s HWLOC_NAME(pcidev_attr_s) +#define hwloc_bridge_attr_s HWLOC_NAME(bridge_attr_s) +#define hwloc_osdev_attr_s HWLOC_NAME(osdev_attr_s) + +#define hwloc_topology_init HWLOC_NAME(topology_init) +#define hwloc_topology_load HWLOC_NAME(topology_load) +#define hwloc_topology_destroy HWLOC_NAME(topology_destroy) +#define hwloc_topology_dup HWLOC_NAME(topology_dup) +#define hwloc_topology_abi_check HWLOC_NAME(topology_abi_check) +#define hwloc_topology_check HWLOC_NAME(topology_check) + +#define hwloc_topology_flags_e HWLOC_NAME(topology_flags_e) + +#define HWLOC_TOPOLOGY_FLAG_INCLUDE_DISALLOWED HWLOC_NAME_CAPS(TOPOLOGY_FLAG_WITH_DISALLOWED) +#define HWLOC_TOPOLOGY_FLAG_IS_THISSYSTEM HWLOC_NAME_CAPS(TOPOLOGY_FLAG_IS_THISSYSTEM) +#define HWLOC_TOPOLOGY_FLAG_THISSYSTEM_ALLOWED_RESOURCES HWLOC_NAME_CAPS(TOPOLOGY_FLAG_THISSYSTEM_ALLOWED_RESOURCES) +#define HWLOC_TOPOLOGY_FLAG_IMPORT_SUPPORT HWLOC_NAME_CAPS(TOPOLOGY_FLAG_IMPORT_SUPPORT) +#define HWLOC_TOPOLOGY_FLAG_RESTRICT_TO_CPUBINDING HWLOC_NAME_CAPS(TOPOLOGY_FLAG_RESTRICT_TO_CPUBINDING) +#define HWLOC_TOPOLOGY_FLAG_RESTRICT_TO_MEMBINDING HWLOC_NAME_CAPS(TOPOLOGY_FLAG_RESTRICT_TO_MEMBINDING) +#define HWLOC_TOPOLOGY_FLAG_DONT_CHANGE_BINDING HWLOC_NAME_CAPS(TOPOLOGY_FLAG_DONT_CHANGE_BINDING) +#define HWLOC_TOPOLOGY_FLAG_NO_DISTANCES HWLOC_NAME_CAPS(TOPOLOGY_FLAG_NO_DISTANCES) +#define HWLOC_TOPOLOGY_FLAG_NO_MEMATTRS HWLOC_NAME_CAPS(TOPOLOGY_FLAG_NO_MEMATTRS) +#define HWLOC_TOPOLOGY_FLAG_NO_CPUKINDS HWLOC_NAME_CAPS(TOPOLOGY_FLAG_NO_CPUKINDS) + +#define hwloc_topology_set_pid HWLOC_NAME(topology_set_pid) +#define hwloc_topology_set_synthetic HWLOC_NAME(topology_set_synthetic) +#define hwloc_topology_set_xml HWLOC_NAME(topology_set_xml) +#define hwloc_topology_set_xmlbuffer HWLOC_NAME(topology_set_xmlbuffer) +#define hwloc_topology_components_flag_e HWLOC_NAME(hwloc_topology_components_flag_e) +#define HWLOC_TOPOLOGY_COMPONENTS_FLAG_BLACKLIST HWLOC_NAME_CAPS(TOPOLOGY_COMPONENTS_FLAG_BLACKLIST) +#define hwloc_topology_set_components HWLOC_NAME(topology_set_components) + +#define hwloc_topology_set_flags HWLOC_NAME(topology_set_flags) +#define hwloc_topology_is_thissystem HWLOC_NAME(topology_is_thissystem) +#define hwloc_topology_get_flags HWLOC_NAME(topology_get_flags) +#define hwloc_topology_discovery_support HWLOC_NAME(topology_discovery_support) +#define hwloc_topology_cpubind_support HWLOC_NAME(topology_cpubind_support) +#define hwloc_topology_membind_support HWLOC_NAME(topology_membind_support) +#define hwloc_topology_misc_support HWLOC_NAME(topology_misc_support) +#define hwloc_topology_support HWLOC_NAME(topology_support) +#define hwloc_topology_get_support HWLOC_NAME(topology_get_support) + +#define hwloc_type_filter_e HWLOC_NAME(type_filter_e) +#define HWLOC_TYPE_FILTER_KEEP_ALL HWLOC_NAME_CAPS(TYPE_FILTER_KEEP_ALL) +#define HWLOC_TYPE_FILTER_KEEP_NONE HWLOC_NAME_CAPS(TYPE_FILTER_KEEP_NONE) +#define HWLOC_TYPE_FILTER_KEEP_STRUCTURE HWLOC_NAME_CAPS(TYPE_FILTER_KEEP_STRUCTURE) +#define HWLOC_TYPE_FILTER_KEEP_IMPORTANT HWLOC_NAME_CAPS(TYPE_FILTER_KEEP_IMPORTANT) +#define hwloc_topology_set_type_filter HWLOC_NAME(topology_set_type_filter) +#define hwloc_topology_get_type_filter HWLOC_NAME(topology_get_type_filter) +#define hwloc_topology_set_all_types_filter HWLOC_NAME(topology_set_all_types_filter) +#define hwloc_topology_set_cache_types_filter HWLOC_NAME(topology_set_cache_types_filter) +#define hwloc_topology_set_icache_types_filter HWLOC_NAME(topology_set_icache_types_filter) +#define hwloc_topology_set_io_types_filter HWLOC_NAME(topology_set_io_types_filter) + +#define hwloc_topology_set_userdata HWLOC_NAME(topology_set_userdata) +#define hwloc_topology_get_userdata HWLOC_NAME(topology_get_userdata) + +#define hwloc_restrict_flags_e HWLOC_NAME(restrict_flags_e) +#define HWLOC_RESTRICT_FLAG_REMOVE_CPULESS HWLOC_NAME_CAPS(RESTRICT_FLAG_REMOVE_CPULESS) +#define HWLOC_RESTRICT_FLAG_BYNODESET HWLOC_NAME_CAPS(RESTRICT_FLAG_BYNODESET) +#define HWLOC_RESTRICT_FLAG_REMOVE_MEMLESS HWLOC_NAME_CAPS(RESTRICT_FLAG_REMOVE_MEMLESS) +#define HWLOC_RESTRICT_FLAG_ADAPT_MISC HWLOC_NAME_CAPS(RESTRICT_FLAG_ADAPT_MISC) +#define HWLOC_RESTRICT_FLAG_ADAPT_IO HWLOC_NAME_CAPS(RESTRICT_FLAG_ADAPT_IO) +#define hwloc_topology_restrict HWLOC_NAME(topology_restrict) + +#define hwloc_allow_flags_e HWLOC_NAME(allow_flags_e) +#define HWLOC_ALLOW_FLAG_ALL HWLOC_NAME_CAPS(ALLOW_FLAG_ALL) +#define HWLOC_ALLOW_FLAG_LOCAL_RESTRICTIONS HWLOC_NAME_CAPS(ALLOW_FLAG_LOCAL_RESTRICTIONS) +#define HWLOC_ALLOW_FLAG_CUSTOM HWLOC_NAME_CAPS(ALLOW_FLAG_CUSTOM) +#define hwloc_topology_allow HWLOC_NAME(topology_allow) + +#define hwloc_topology_insert_misc_object HWLOC_NAME(topology_insert_misc_object) +#define hwloc_topology_alloc_group_object HWLOC_NAME(topology_alloc_group_object) +#define hwloc_topology_free_group_object HWLOC_NAME(topology_free_group_object) +#define hwloc_topology_insert_group_object HWLOC_NAME(topology_insert_group_object) +#define hwloc_obj_add_other_obj_sets HWLOC_NAME(obj_add_other_obj_sets) +#define hwloc_topology_refresh HWLOC_NAME(topology_refresh) + +#define hwloc_topology_get_depth HWLOC_NAME(topology_get_depth) +#define hwloc_get_type_depth HWLOC_NAME(get_type_depth) +#define hwloc_get_memory_parents_depth HWLOC_NAME(get_memory_parents_depth) + +#define hwloc_get_type_depth_e HWLOC_NAME(get_type_depth_e) +#define HWLOC_TYPE_DEPTH_UNKNOWN HWLOC_NAME_CAPS(TYPE_DEPTH_UNKNOWN) +#define HWLOC_TYPE_DEPTH_MULTIPLE HWLOC_NAME_CAPS(TYPE_DEPTH_MULTIPLE) +#define HWLOC_TYPE_DEPTH_BRIDGE HWLOC_NAME_CAPS(TYPE_DEPTH_BRIDGE) +#define HWLOC_TYPE_DEPTH_PCI_DEVICE HWLOC_NAME_CAPS(TYPE_DEPTH_PCI_DEVICE) +#define HWLOC_TYPE_DEPTH_OS_DEVICE HWLOC_NAME_CAPS(TYPE_DEPTH_OS_DEVICE) +#define HWLOC_TYPE_DEPTH_MISC HWLOC_NAME_CAPS(TYPE_DEPTH_MISC) +#define HWLOC_TYPE_DEPTH_NUMANODE HWLOC_NAME_CAPS(TYPE_DEPTH_NUMANODE) +#define HWLOC_TYPE_DEPTH_MEMCACHE HWLOC_NAME_CAPS(TYPE_DEPTH_MEMCACHE) + +#define hwloc_get_depth_type HWLOC_NAME(get_depth_type) +#define hwloc_get_nbobjs_by_depth HWLOC_NAME(get_nbobjs_by_depth) +#define hwloc_get_nbobjs_by_type HWLOC_NAME(get_nbobjs_by_type) + +#define hwloc_get_obj_by_depth HWLOC_NAME(get_obj_by_depth ) +#define hwloc_get_obj_by_type HWLOC_NAME(get_obj_by_type ) + +#define hwloc_obj_type_string HWLOC_NAME(obj_type_string ) +#define hwloc_obj_type_snprintf HWLOC_NAME(obj_type_snprintf ) +#define hwloc_obj_attr_snprintf HWLOC_NAME(obj_attr_snprintf ) +#define hwloc_type_sscanf HWLOC_NAME(type_sscanf) +#define hwloc_type_sscanf_as_depth HWLOC_NAME(type_sscanf_as_depth) + +#define hwloc_obj_get_info_by_name HWLOC_NAME(obj_get_info_by_name) +#define hwloc_obj_add_info HWLOC_NAME(obj_add_info) +#define hwloc_obj_set_subtype HWLOC_NAME(obj_set_subtype) + +#define HWLOC_CPUBIND_PROCESS HWLOC_NAME_CAPS(CPUBIND_PROCESS) +#define HWLOC_CPUBIND_THREAD HWLOC_NAME_CAPS(CPUBIND_THREAD) +#define HWLOC_CPUBIND_STRICT HWLOC_NAME_CAPS(CPUBIND_STRICT) +#define HWLOC_CPUBIND_NOMEMBIND HWLOC_NAME_CAPS(CPUBIND_NOMEMBIND) + +#define hwloc_cpubind_flags_t HWLOC_NAME(cpubind_flags_t) + +#define hwloc_set_cpubind HWLOC_NAME(set_cpubind) +#define hwloc_get_cpubind HWLOC_NAME(get_cpubind) +#define hwloc_set_proc_cpubind HWLOC_NAME(set_proc_cpubind) +#define hwloc_get_proc_cpubind HWLOC_NAME(get_proc_cpubind) +#define hwloc_set_thread_cpubind HWLOC_NAME(set_thread_cpubind) +#define hwloc_get_thread_cpubind HWLOC_NAME(get_thread_cpubind) + +#define hwloc_get_last_cpu_location HWLOC_NAME(get_last_cpu_location) +#define hwloc_get_proc_last_cpu_location HWLOC_NAME(get_proc_last_cpu_location) + +#define HWLOC_MEMBIND_DEFAULT HWLOC_NAME_CAPS(MEMBIND_DEFAULT) +#define HWLOC_MEMBIND_FIRSTTOUCH HWLOC_NAME_CAPS(MEMBIND_FIRSTTOUCH) +#define HWLOC_MEMBIND_BIND HWLOC_NAME_CAPS(MEMBIND_BIND) +#define HWLOC_MEMBIND_INTERLEAVE HWLOC_NAME_CAPS(MEMBIND_INTERLEAVE) +#define HWLOC_MEMBIND_WEIGHTED_INTERLEAVE HWLOC_NAME_CAPS(MEMBIND_WEIGHTED_INTERLEAVE) +#define HWLOC_MEMBIND_NEXTTOUCH HWLOC_NAME_CAPS(MEMBIND_NEXTTOUCH) +#define HWLOC_MEMBIND_MIXED HWLOC_NAME_CAPS(MEMBIND_MIXED) + +#define hwloc_membind_policy_t HWLOC_NAME(membind_policy_t) + +#define HWLOC_MEMBIND_PROCESS HWLOC_NAME_CAPS(MEMBIND_PROCESS) +#define HWLOC_MEMBIND_THREAD HWLOC_NAME_CAPS(MEMBIND_THREAD) +#define HWLOC_MEMBIND_STRICT HWLOC_NAME_CAPS(MEMBIND_STRICT) +#define HWLOC_MEMBIND_MIGRATE HWLOC_NAME_CAPS(MEMBIND_MIGRATE) +#define HWLOC_MEMBIND_NOCPUBIND HWLOC_NAME_CAPS(MEMBIND_NOCPUBIND) +#define HWLOC_MEMBIND_BYNODESET HWLOC_NAME_CAPS(MEMBIND_BYNODESET) + +#define hwloc_membind_flags_t HWLOC_NAME(membind_flags_t) + +#define hwloc_set_membind HWLOC_NAME(set_membind) +#define hwloc_get_membind HWLOC_NAME(get_membind) +#define hwloc_set_proc_membind HWLOC_NAME(set_proc_membind) +#define hwloc_get_proc_membind HWLOC_NAME(get_proc_membind) +#define hwloc_set_area_membind HWLOC_NAME(set_area_membind) +#define hwloc_get_area_membind HWLOC_NAME(get_area_membind) +#define hwloc_get_area_memlocation HWLOC_NAME(get_area_memlocation) +#define hwloc_alloc_membind HWLOC_NAME(alloc_membind) +#define hwloc_alloc HWLOC_NAME(alloc) +#define hwloc_free HWLOC_NAME(free) + +#define hwloc_get_non_io_ancestor_obj HWLOC_NAME(get_non_io_ancestor_obj) +#define hwloc_get_next_pcidev HWLOC_NAME(get_next_pcidev) +#define hwloc_get_pcidev_by_busid HWLOC_NAME(get_pcidev_by_busid) +#define hwloc_get_pcidev_by_busidstring HWLOC_NAME(get_pcidev_by_busidstring) +#define hwloc_get_next_osdev HWLOC_NAME(get_next_osdev) +#define hwloc_get_next_bridge HWLOC_NAME(get_next_bridge) +#define hwloc_bridge_covers_pcibus HWLOC_NAME(bridge_covers_pcibus) + +/* hwloc/bitmap.h */ + +#define hwloc_bitmap_s HWLOC_NAME(bitmap_s) +#define hwloc_bitmap_t HWLOC_NAME(bitmap_t) +#define hwloc_const_bitmap_t HWLOC_NAME(const_bitmap_t) + +#define hwloc_bitmap_alloc HWLOC_NAME(bitmap_alloc) +#define hwloc_bitmap_alloc_full HWLOC_NAME(bitmap_alloc_full) +#define hwloc_bitmap_free HWLOC_NAME(bitmap_free) +#define hwloc_bitmap_dup HWLOC_NAME(bitmap_dup) +#define hwloc_bitmap_copy HWLOC_NAME(bitmap_copy) +#define hwloc_bitmap_snprintf HWLOC_NAME(bitmap_snprintf) +#define hwloc_bitmap_asprintf HWLOC_NAME(bitmap_asprintf) +#define hwloc_bitmap_sscanf HWLOC_NAME(bitmap_sscanf) +#define hwloc_bitmap_list_snprintf HWLOC_NAME(bitmap_list_snprintf) +#define hwloc_bitmap_list_asprintf HWLOC_NAME(bitmap_list_asprintf) +#define hwloc_bitmap_list_sscanf HWLOC_NAME(bitmap_list_sscanf) +#define hwloc_bitmap_taskset_snprintf HWLOC_NAME(bitmap_taskset_snprintf) +#define hwloc_bitmap_taskset_asprintf HWLOC_NAME(bitmap_taskset_asprintf) +#define hwloc_bitmap_taskset_sscanf HWLOC_NAME(bitmap_taskset_sscanf) +#define hwloc_bitmap_zero HWLOC_NAME(bitmap_zero) +#define hwloc_bitmap_fill HWLOC_NAME(bitmap_fill) +#define hwloc_bitmap_from_ulong HWLOC_NAME(bitmap_from_ulong) +#define hwloc_bitmap_from_ulongs HWLOC_NAME(bitmap_from_ulongs) +#define hwloc_bitmap_from_ith_ulong HWLOC_NAME(bitmap_from_ith_ulong) +#define hwloc_bitmap_to_ulong HWLOC_NAME(bitmap_to_ulong) +#define hwloc_bitmap_to_ith_ulong HWLOC_NAME(bitmap_to_ith_ulong) +#define hwloc_bitmap_to_ulongs HWLOC_NAME(bitmap_to_ulongs) +#define hwloc_bitmap_nr_ulongs HWLOC_NAME(bitmap_nr_ulongs) +#define hwloc_bitmap_only HWLOC_NAME(bitmap_only) +#define hwloc_bitmap_allbut HWLOC_NAME(bitmap_allbut) +#define hwloc_bitmap_set HWLOC_NAME(bitmap_set) +#define hwloc_bitmap_set_range HWLOC_NAME(bitmap_set_range) +#define hwloc_bitmap_set_ith_ulong HWLOC_NAME(bitmap_set_ith_ulong) +#define hwloc_bitmap_clr HWLOC_NAME(bitmap_clr) +#define hwloc_bitmap_clr_range HWLOC_NAME(bitmap_clr_range) +#define hwloc_bitmap_isset HWLOC_NAME(bitmap_isset) +#define hwloc_bitmap_iszero HWLOC_NAME(bitmap_iszero) +#define hwloc_bitmap_isfull HWLOC_NAME(bitmap_isfull) +#define hwloc_bitmap_isequal HWLOC_NAME(bitmap_isequal) +#define hwloc_bitmap_intersects HWLOC_NAME(bitmap_intersects) +#define hwloc_bitmap_isincluded HWLOC_NAME(bitmap_isincluded) +#define hwloc_bitmap_or HWLOC_NAME(bitmap_or) +#define hwloc_bitmap_and HWLOC_NAME(bitmap_and) +#define hwloc_bitmap_andnot HWLOC_NAME(bitmap_andnot) +#define hwloc_bitmap_xor HWLOC_NAME(bitmap_xor) +#define hwloc_bitmap_not HWLOC_NAME(bitmap_not) +#define hwloc_bitmap_first HWLOC_NAME(bitmap_first) +#define hwloc_bitmap_last HWLOC_NAME(bitmap_last) +#define hwloc_bitmap_next HWLOC_NAME(bitmap_next) +#define hwloc_bitmap_first_unset HWLOC_NAME(bitmap_first_unset) +#define hwloc_bitmap_last_unset HWLOC_NAME(bitmap_last_unset) +#define hwloc_bitmap_next_unset HWLOC_NAME(bitmap_next_unset) +#define hwloc_bitmap_singlify HWLOC_NAME(bitmap_singlify) +#define hwloc_bitmap_compare_first HWLOC_NAME(bitmap_compare_first) +#define hwloc_bitmap_compare HWLOC_NAME(bitmap_compare) +#define hwloc_bitmap_weight HWLOC_NAME(bitmap_weight) + +/* hwloc/helper.h */ + +#define hwloc_get_type_or_below_depth HWLOC_NAME(get_type_or_below_depth) +#define hwloc_get_type_or_above_depth HWLOC_NAME(get_type_or_above_depth) +#define hwloc_get_root_obj HWLOC_NAME(get_root_obj) +#define hwloc_get_ancestor_obj_by_depth HWLOC_NAME(get_ancestor_obj_by_depth) +#define hwloc_get_ancestor_obj_by_type HWLOC_NAME(get_ancestor_obj_by_type) +#define hwloc_get_next_obj_by_depth HWLOC_NAME(get_next_obj_by_depth) +#define hwloc_get_next_obj_by_type HWLOC_NAME(get_next_obj_by_type) +#define hwloc_bitmap_singlify_per_core HWLOC_NAME(bitmap_singlify_by_core) +#define hwloc_get_pu_obj_by_os_index HWLOC_NAME(get_pu_obj_by_os_index) +#define hwloc_get_numanode_obj_by_os_index HWLOC_NAME(get_numanode_obj_by_os_index) +#define hwloc_get_next_child HWLOC_NAME(get_next_child) +#define hwloc_get_common_ancestor_obj HWLOC_NAME(get_common_ancestor_obj) +#define hwloc_obj_is_in_subtree HWLOC_NAME(obj_is_in_subtree) +#define hwloc_get_first_largest_obj_inside_cpuset HWLOC_NAME(get_first_largest_obj_inside_cpuset) +#define hwloc_get_largest_objs_inside_cpuset HWLOC_NAME(get_largest_objs_inside_cpuset) +#define hwloc_get_next_obj_inside_cpuset_by_depth HWLOC_NAME(get_next_obj_inside_cpuset_by_depth) +#define hwloc_get_next_obj_inside_cpuset_by_type HWLOC_NAME(get_next_obj_inside_cpuset_by_type) +#define hwloc_get_obj_inside_cpuset_by_depth HWLOC_NAME(get_obj_inside_cpuset_by_depth) +#define hwloc_get_obj_inside_cpuset_by_type HWLOC_NAME(get_obj_inside_cpuset_by_type) +#define hwloc_get_nbobjs_inside_cpuset_by_depth HWLOC_NAME(get_nbobjs_inside_cpuset_by_depth) +#define hwloc_get_nbobjs_inside_cpuset_by_type HWLOC_NAME(get_nbobjs_inside_cpuset_by_type) +#define hwloc_get_obj_index_inside_cpuset HWLOC_NAME(get_obj_index_inside_cpuset) +#define hwloc_get_child_covering_cpuset HWLOC_NAME(get_child_covering_cpuset) +#define hwloc_get_obj_covering_cpuset HWLOC_NAME(get_obj_covering_cpuset) +#define hwloc_get_next_obj_covering_cpuset_by_depth HWLOC_NAME(get_next_obj_covering_cpuset_by_depth) +#define hwloc_get_next_obj_covering_cpuset_by_type HWLOC_NAME(get_next_obj_covering_cpuset_by_type) +#define hwloc_obj_type_is_normal HWLOC_NAME(obj_type_is_normal) +#define hwloc_obj_type_is_memory HWLOC_NAME(obj_type_is_memory) +#define hwloc_obj_type_is_io HWLOC_NAME(obj_type_is_io) +#define hwloc_obj_type_is_cache HWLOC_NAME(obj_type_is_cache) +#define hwloc_obj_type_is_dcache HWLOC_NAME(obj_type_is_dcache) +#define hwloc_obj_type_is_icache HWLOC_NAME(obj_type_is_icache) +#define hwloc_get_cache_type_depth HWLOC_NAME(get_cache_type_depth) +#define hwloc_get_cache_covering_cpuset HWLOC_NAME(get_cache_covering_cpuset) +#define hwloc_get_shared_cache_covering_obj HWLOC_NAME(get_shared_cache_covering_obj) +#define hwloc_get_closest_objs HWLOC_NAME(get_closest_objs) +#define hwloc_get_obj_below_by_type HWLOC_NAME(get_obj_below_by_type) +#define hwloc_get_obj_below_array_by_type HWLOC_NAME(get_obj_below_array_by_type) +#define hwloc_get_obj_with_same_locality HWLOC_NAME(get_obj_with_same_locality) +#define hwloc_distrib_flags_e HWLOC_NAME(distrib_flags_e) +#define HWLOC_DISTRIB_FLAG_REVERSE HWLOC_NAME_CAPS(DISTRIB_FLAG_REVERSE) +#define hwloc_distrib HWLOC_NAME(distrib) +#define hwloc_alloc_membind_policy HWLOC_NAME(alloc_membind_policy) +#define hwloc_alloc_membind_policy_nodeset HWLOC_NAME(alloc_membind_policy_nodeset) +#define hwloc_topology_get_complete_cpuset HWLOC_NAME(topology_get_complete_cpuset) +#define hwloc_topology_get_topology_cpuset HWLOC_NAME(topology_get_topology_cpuset) +#define hwloc_topology_get_allowed_cpuset HWLOC_NAME(topology_get_allowed_cpuset) +#define hwloc_topology_get_complete_nodeset HWLOC_NAME(topology_get_complete_nodeset) +#define hwloc_topology_get_topology_nodeset HWLOC_NAME(topology_get_topology_nodeset) +#define hwloc_topology_get_allowed_nodeset HWLOC_NAME(topology_get_allowed_nodeset) +#define hwloc_cpuset_to_nodeset HWLOC_NAME(cpuset_to_nodeset) +#define hwloc_cpuset_from_nodeset HWLOC_NAME(cpuset_from_nodeset) + +/* memattrs.h */ + +#define hwloc_memattr_id_e HWLOC_NAME(memattr_id_e) +#define HWLOC_MEMATTR_ID_CAPACITY HWLOC_NAME_CAPS(MEMATTR_ID_CAPACITY) +#define HWLOC_MEMATTR_ID_LOCALITY HWLOC_NAME_CAPS(MEMATTR_ID_LOCALITY) +#define HWLOC_MEMATTR_ID_BANDWIDTH HWLOC_NAME_CAPS(MEMATTR_ID_BANDWIDTH) +#define HWLOC_MEMATTR_ID_LATENCY HWLOC_NAME_CAPS(MEMATTR_ID_LATENCY) +#define HWLOC_MEMATTR_ID_READ_BANDWIDTH HWLOC_NAME_CAPS(MEMATTR_ID_READ_BANDWIDTH) +#define HWLOC_MEMATTR_ID_WRITE_BANDWIDTH HWLOC_NAME_CAPS(MEMATTR_ID_WRITE_BANDWIDTH) +#define HWLOC_MEMATTR_ID_READ_LATENCY HWLOC_NAME_CAPS(MEMATTR_ID_READ_LATENCY) +#define HWLOC_MEMATTR_ID_WRITE_LATENCY HWLOC_NAME_CAPS(MEMATTR_ID_WRITE_LATENCY) +#define HWLOC_MEMATTR_ID_MAX HWLOC_NAME_CAPS(MEMATTR_ID_MAX) + +#define hwloc_memattr_id_t HWLOC_NAME(memattr_id_t) +#define hwloc_memattr_get_by_name HWLOC_NAME(memattr_get_by_name) + +#define hwloc_location HWLOC_NAME(location) +#define hwloc_location_type_e HWLOC_NAME(location_type_e) +#define HWLOC_LOCATION_TYPE_OBJECT HWLOC_NAME_CAPS(LOCATION_TYPE_OBJECT) +#define HWLOC_LOCATION_TYPE_CPUSET HWLOC_NAME_CAPS(LOCATION_TYPE_CPUSET) +#define hwloc_location_u HWLOC_NAME(location_u) + +#define hwloc_memattr_get_value HWLOC_NAME(memattr_get_value) +#define hwloc_memattr_get_best_target HWLOC_NAME(memattr_get_best_target) +#define hwloc_memattr_get_best_initiator HWLOC_NAME(memattr_get_best_initiator) + +#define hwloc_local_numanode_flag_e HWLOC_NAME(local_numanode_flag_e) +#define HWLOC_LOCAL_NUMANODE_FLAG_LARGER_LOCALITY HWLOC_NAME_CAPS(LOCAL_NUMANODE_FLAG_LARGER_LOCALITY) +#define HWLOC_LOCAL_NUMANODE_FLAG_SMALLER_LOCALITY HWLOC_NAME_CAPS(LOCAL_NUMANODE_FLAG_SMALLER_LOCALITY) +#define HWLOC_LOCAL_NUMANODE_FLAG_INTERSECT_LOCALITY HWLOC_NAME_CAPS(LOCAL_NUMANODE_FLAG_INTERSECT_LOCALITY) +#define HWLOC_LOCAL_NUMANODE_FLAG_ALL HWLOC_NAME_CAPS(LOCAL_NUMANODE_FLAG_ALL) +#define hwloc_get_local_numanode_objs HWLOC_NAME(get_local_numanode_objs) +#define hwloc_topology_get_default_nodeset HWLOC_NAME(topology_get_default_nodeset) + +#define hwloc_memattr_get_name HWLOC_NAME(memattr_get_name) +#define hwloc_memattr_get_flags HWLOC_NAME(memattr_get_flags) +#define hwloc_memattr_flag_e HWLOC_NAME(memattr_flag_e) +#define HWLOC_MEMATTR_FLAG_HIGHER_FIRST HWLOC_NAME_CAPS(MEMATTR_FLAG_HIGHER_FIRST) +#define HWLOC_MEMATTR_FLAG_LOWER_FIRST HWLOC_NAME_CAPS(MEMATTR_FLAG_LOWER_FIRST) +#define HWLOC_MEMATTR_FLAG_NEED_INITIATOR HWLOC_NAME_CAPS(MEMATTR_FLAG_NEED_INITIATOR) +#define hwloc_memattr_register HWLOC_NAME(memattr_register) +#define hwloc_memattr_set_value HWLOC_NAME(memattr_set_value) +#define hwloc_memattr_get_targets HWLOC_NAME(memattr_get_targets) +#define hwloc_memattr_get_initiators HWLOC_NAME(memattr_get_initiators) + +/* cpukinds.h */ + +#define hwloc_cpukinds_get_nr HWLOC_NAME(cpukinds_get_nr) +#define hwloc_cpukinds_get_by_cpuset HWLOC_NAME(cpukinds_get_by_cpuset) +#define hwloc_cpukinds_get_info HWLOC_NAME(cpukinds_get_info) +#define hwloc_cpukinds_register HWLOC_NAME(cpukinds_register) + +/* export.h */ + +#define hwloc_topology_export_xml_flags_e HWLOC_NAME(topology_export_xml_flags_e) +#define HWLOC_TOPOLOGY_EXPORT_XML_FLAG_V1 HWLOC_NAME_CAPS(TOPOLOGY_EXPORT_XML_FLAG_V1) +#define hwloc_topology_export_xml HWLOC_NAME(topology_export_xml) +#define hwloc_topology_export_xmlbuffer HWLOC_NAME(topology_export_xmlbuffer) +#define hwloc_free_xmlbuffer HWLOC_NAME(free_xmlbuffer) +#define hwloc_topology_set_userdata_export_callback HWLOC_NAME(topology_set_userdata_export_callback) +#define hwloc_export_obj_userdata HWLOC_NAME(export_obj_userdata) +#define hwloc_export_obj_userdata_base64 HWLOC_NAME(export_obj_userdata_base64) +#define hwloc_topology_set_userdata_import_callback HWLOC_NAME(topology_set_userdata_import_callback) + +#define hwloc_topology_export_synthetic_flags_e HWLOC_NAME(topology_export_synthetic_flags_e) +#define HWLOC_TOPOLOGY_EXPORT_SYNTHETIC_FLAG_NO_EXTENDED_TYPES HWLOC_NAME_CAPS(TOPOLOGY_EXPORT_SYNTHETIC_FLAG_NO_EXTENDED_TYPES) +#define HWLOC_TOPOLOGY_EXPORT_SYNTHETIC_FLAG_NO_ATTRS HWLOC_NAME_CAPS(TOPOLOGY_EXPORT_SYNTHETIC_FLAG_NO_ATTRS) +#define HWLOC_TOPOLOGY_EXPORT_SYNTHETIC_FLAG_V1 HWLOC_NAME_CAPS(TOPOLOGY_EXPORT_SYNTHETIC_FLAG_V1) +#define HWLOC_TOPOLOGY_EXPORT_SYNTHETIC_FLAG_IGNORE_MEMORY HWLOC_NAME_CAPS(TOPOLOGY_EXPORT_SYNTHETIC_FLAG_IGNORE_MEMORY) +#define hwloc_topology_export_synthetic HWLOC_NAME(topology_export_synthetic) + +/* distances.h */ + +#define hwloc_distances_s HWLOC_NAME(distances_s) + +#define hwloc_distances_kind_e HWLOC_NAME(distances_kind_e) +#define HWLOC_DISTANCES_KIND_FROM_OS HWLOC_NAME_CAPS(DISTANCES_KIND_FROM_OS) +#define HWLOC_DISTANCES_KIND_FROM_USER HWLOC_NAME_CAPS(DISTANCES_KIND_FROM_USER) +#define HWLOC_DISTANCES_KIND_MEANS_LATENCY HWLOC_NAME_CAPS(DISTANCES_KIND_MEANS_LATENCY) +#define HWLOC_DISTANCES_KIND_MEANS_BANDWIDTH HWLOC_NAME_CAPS(DISTANCES_KIND_MEANS_BANDWIDTH) +#define HWLOC_DISTANCES_KIND_HETEROGENEOUS_TYPES HWLOC_NAME_CAPS(DISTANCES_KIND_HETEROGENEOUS_TYPES) + +#define hwloc_distances_get HWLOC_NAME(distances_get) +#define hwloc_distances_get_by_depth HWLOC_NAME(distances_get_by_depth) +#define hwloc_distances_get_by_type HWLOC_NAME(distances_get_by_type) +#define hwloc_distances_get_by_name HWLOC_NAME(distances_get_by_name) +#define hwloc_distances_get_name HWLOC_NAME(distances_get_name) +#define hwloc_distances_release HWLOC_NAME(distances_release) +#define hwloc_distances_obj_index HWLOC_NAME(distances_obj_index) +#define hwloc_distances_obj_pair_values HWLOC_NAME(distances_pair_values) + +#define hwloc_distances_transform_e HWLOC_NAME(distances_transform_e) +#define HWLOC_DISTANCES_TRANSFORM_REMOVE_NULL HWLOC_NAME_CAPS(DISTANCES_TRANSFORM_REMOVE_NULL) +#define HWLOC_DISTANCES_TRANSFORM_LINKS HWLOC_NAME_CAPS(DISTANCES_TRANSFORM_LINKS) +#define HWLOC_DISTANCES_TRANSFORM_MERGE_SWITCH_PORTS HWLOC_NAME_CAPS(DISTANCES_TRANSFORM_MERGE_SWITCH_PORTS) +#define HWLOC_DISTANCES_TRANSFORM_TRANSITIVE_CLOSURE HWLOC_NAME_CAPS(DISTANCES_TRANSFORM_TRANSITIVE_CLOSURE) +#define hwloc_distances_transform HWLOC_NAME(distances_transform) + +#define hwloc_distances_add_flag_e HWLOC_NAME(distances_add_flag_e) +#define HWLOC_DISTANCES_ADD_FLAG_GROUP HWLOC_NAME_CAPS(DISTANCES_ADD_FLAG_GROUP) +#define HWLOC_DISTANCES_ADD_FLAG_GROUP_INACCURATE HWLOC_NAME_CAPS(DISTANCES_ADD_FLAG_GROUP_INACCURATE) + +#define hwloc_distances_add_handle_t HWLOC_NAME(distances_add_handle_t) +#define hwloc_distances_add_create HWLOC_NAME(distances_add_create) +#define hwloc_distances_add_values HWLOC_NAME(distances_add_values) +#define hwloc_distances_add_commit HWLOC_NAME(distances_add_commit) + +#define hwloc_distances_remove HWLOC_NAME(distances_remove) +#define hwloc_distances_remove_by_depth HWLOC_NAME(distances_remove_by_depth) +#define hwloc_distances_remove_by_type HWLOC_NAME(distances_remove_by_type) +#define hwloc_distances_release_remove HWLOC_NAME(distances_release_remove) + +/* diff.h */ + +#define hwloc_topology_diff_obj_attr_type_e HWLOC_NAME(topology_diff_obj_attr_type_e) +#define hwloc_topology_diff_obj_attr_type_t HWLOC_NAME(topology_diff_obj_attr_type_t) +#define HWLOC_TOPOLOGY_DIFF_OBJ_ATTR_SIZE HWLOC_NAME_CAPS(TOPOLOGY_DIFF_OBJ_ATTR_SIZE) +#define HWLOC_TOPOLOGY_DIFF_OBJ_ATTR_NAME HWLOC_NAME_CAPS(TOPOLOGY_DIFF_OBJ_ATTR_NAME) +#define HWLOC_TOPOLOGY_DIFF_OBJ_ATTR_INFO HWLOC_NAME_CAPS(TOPOLOGY_DIFF_OBJ_ATTR_INFO) +#define hwloc_topology_diff_obj_attr_u HWLOC_NAME(topology_diff_obj_attr_u) +#define hwloc_topology_diff_obj_attr_generic_s HWLOC_NAME(topology_diff_obj_attr_generic_s) +#define hwloc_topology_diff_obj_attr_uint64_s HWLOC_NAME(topology_diff_obj_attr_uint64_s) +#define hwloc_topology_diff_obj_attr_string_s HWLOC_NAME(topology_diff_obj_attr_string_s) +#define hwloc_topology_diff_type_e HWLOC_NAME(topology_diff_type_e) +#define hwloc_topology_diff_type_t HWLOC_NAME(topology_diff_type_t) +#define HWLOC_TOPOLOGY_DIFF_OBJ_ATTR HWLOC_NAME_CAPS(TOPOLOGY_DIFF_OBJ_ATTR) +#define HWLOC_TOPOLOGY_DIFF_TOO_COMPLEX HWLOC_NAME_CAPS(TOPOLOGY_DIFF_TOO_COMPLEX) +#define hwloc_topology_diff_u HWLOC_NAME(topology_diff_u) +#define hwloc_topology_diff_t HWLOC_NAME(topology_diff_t) +#define hwloc_topology_diff_generic_s HWLOC_NAME(topology_diff_generic_s) +#define hwloc_topology_diff_obj_attr_s HWLOC_NAME(topology_diff_obj_attr_s) +#define hwloc_topology_diff_too_complex_s HWLOC_NAME(topology_diff_too_complex_s) +#define hwloc_topology_diff_build HWLOC_NAME(topology_diff_build) +#define hwloc_topology_diff_apply_flags_e HWLOC_NAME(topology_diff_apply_flags_e) +#define HWLOC_TOPOLOGY_DIFF_APPLY_REVERSE HWLOC_NAME_CAPS(TOPOLOGY_DIFF_APPLY_REVERSE) +#define hwloc_topology_diff_apply HWLOC_NAME(topology_diff_apply) +#define hwloc_topology_diff_destroy HWLOC_NAME(topology_diff_destroy) +#define hwloc_topology_diff_load_xml HWLOC_NAME(topology_diff_load_xml) +#define hwloc_topology_diff_export_xml HWLOC_NAME(topology_diff_export_xml) +#define hwloc_topology_diff_load_xmlbuffer HWLOC_NAME(topology_diff_load_xmlbuffer) +#define hwloc_topology_diff_export_xmlbuffer HWLOC_NAME(topology_diff_export_xmlbuffer) + +/* shmem.h */ + +#define hwloc_shmem_topology_get_length HWLOC_NAME(shmem_topology_get_length) +#define hwloc_shmem_topology_write HWLOC_NAME(shmem_topology_write) +#define hwloc_shmem_topology_adopt HWLOC_NAME(shmem_topology_adopt) + +/* glibc-sched.h */ + +#define hwloc_cpuset_to_glibc_sched_affinity HWLOC_NAME(cpuset_to_glibc_sched_affinity) +#define hwloc_cpuset_from_glibc_sched_affinity HWLOC_NAME(cpuset_from_glibc_sched_affinity) + +/* linux-libnuma.h */ + +#define hwloc_cpuset_to_linux_libnuma_ulongs HWLOC_NAME(cpuset_to_linux_libnuma_ulongs) +#define hwloc_nodeset_to_linux_libnuma_ulongs HWLOC_NAME(nodeset_to_linux_libnuma_ulongs) +#define hwloc_cpuset_from_linux_libnuma_ulongs HWLOC_NAME(cpuset_from_linux_libnuma_ulongs) +#define hwloc_nodeset_from_linux_libnuma_ulongs HWLOC_NAME(nodeset_from_linux_libnuma_ulongs) +#define hwloc_cpuset_to_linux_libnuma_bitmask HWLOC_NAME(cpuset_to_linux_libnuma_bitmask) +#define hwloc_nodeset_to_linux_libnuma_bitmask HWLOC_NAME(nodeset_to_linux_libnuma_bitmask) +#define hwloc_cpuset_from_linux_libnuma_bitmask HWLOC_NAME(cpuset_from_linux_libnuma_bitmask) +#define hwloc_nodeset_from_linux_libnuma_bitmask HWLOC_NAME(nodeset_from_linux_libnuma_bitmask) + +/* linux.h */ + +#define hwloc_linux_set_tid_cpubind HWLOC_NAME(linux_set_tid_cpubind) +#define hwloc_linux_get_tid_cpubind HWLOC_NAME(linux_get_tid_cpubind) +#define hwloc_linux_get_tid_last_cpu_location HWLOC_NAME(linux_get_tid_last_cpu_location) +#define hwloc_linux_read_path_as_cpumask HWLOC_NAME(linux_read_file_cpumask) + +/* windows.h */ + +#define hwloc_windows_get_nr_processor_groups HWLOC_NAME(windows_get_nr_processor_groups) +#define hwloc_windows_get_processor_group_cpuset HWLOC_NAME(windows_get_processor_group_cpuset) + +/* openfabrics-verbs.h */ + +#define hwloc_ibv_get_device_cpuset HWLOC_NAME(ibv_get_device_cpuset) +#define hwloc_ibv_get_device_osdev HWLOC_NAME(ibv_get_device_osdev) +#define hwloc_ibv_get_device_osdev_by_name HWLOC_NAME(ibv_get_device_osdev_by_name) + +/* opencl.h */ + +#define hwloc_cl_device_pci_bus_info_khr HWLOC_NAME(cl_device_pci_bus_info_khr) +#define hwloc_cl_device_topology_amd HWLOC_NAME(cl_device_topology_amd) +#define hwloc_opencl_get_device_pci_busid HWLOC_NAME(opencl_get_device_pci_ids) +#define hwloc_opencl_get_device_cpuset HWLOC_NAME(opencl_get_device_cpuset) +#define hwloc_opencl_get_device_osdev HWLOC_NAME(opencl_get_device_osdev) +#define hwloc_opencl_get_device_osdev_by_index HWLOC_NAME(opencl_get_device_osdev_by_index) + +/* cuda.h */ + +#define hwloc_cuda_get_device_pci_ids HWLOC_NAME(cuda_get_device_pci_ids) +#define hwloc_cuda_get_device_cpuset HWLOC_NAME(cuda_get_device_cpuset) +#define hwloc_cuda_get_device_pcidev HWLOC_NAME(cuda_get_device_pcidev) +#define hwloc_cuda_get_device_osdev HWLOC_NAME(cuda_get_device_osdev) +#define hwloc_cuda_get_device_osdev_by_index HWLOC_NAME(cuda_get_device_osdev_by_index) + +/* cudart.h */ + +#define hwloc_cudart_get_device_pci_ids HWLOC_NAME(cudart_get_device_pci_ids) +#define hwloc_cudart_get_device_cpuset HWLOC_NAME(cudart_get_device_cpuset) +#define hwloc_cudart_get_device_pcidev HWLOC_NAME(cudart_get_device_pcidev) +#define hwloc_cudart_get_device_osdev_by_index HWLOC_NAME(cudart_get_device_osdev_by_index) + +/* nvml.h */ + +#define hwloc_nvml_get_device_cpuset HWLOC_NAME(nvml_get_device_cpuset) +#define hwloc_nvml_get_device_osdev HWLOC_NAME(nvml_get_device_osdev) +#define hwloc_nvml_get_device_osdev_by_index HWLOC_NAME(nvml_get_device_osdev_by_index) + +/* rsmi.h */ + +#define hwloc_rsmi_get_device_cpuset HWLOC_NAME(rsmi_get_device_cpuset) +#define hwloc_rsmi_get_device_osdev HWLOC_NAME(rsmi_get_device_osdev) +#define hwloc_rsmi_get_device_osdev_by_index HWLOC_NAME(rsmi_get_device_osdev_by_index) + +/* levelzero.h */ + +#define hwloc_levelzero_get_device_cpuset HWLOC_NAME(levelzero_get_device_cpuset) +#define hwloc_levelzero_get_sysman_device_cpuset HWLOC_NAME(levelzero_get_sysman_device_cpuset) +#define hwloc_levelzero_get_device_osdev HWLOC_NAME(levelzero_get_device_osdev) +#define hwloc_levelzero_get_sysman_device_osdev HWLOC_NAME(levelzero_get_sysman_device_osdev) + +/* gl.h */ + +#define hwloc_gl_get_display_osdev_by_port_device HWLOC_NAME(gl_get_display_osdev_by_port_device) +#define hwloc_gl_get_display_osdev_by_name HWLOC_NAME(gl_get_display_osdev_by_name) +#define hwloc_gl_get_display_by_osdev HWLOC_NAME(gl_get_display_by_osdev) + +/* hwloc/plugins.h */ + +#define hwloc_disc_phase_e HWLOC_NAME(disc_phase_e) +#define HWLOC_DISC_PHASE_GLOBAL HWLOC_NAME_CAPS(DISC_PHASE_GLOBAL) +#define HWLOC_DISC_PHASE_CPU HWLOC_NAME_CAPS(DISC_PHASE_CPU) +#define HWLOC_DISC_PHASE_MEMORY HWLOC_NAME_CAPS(DISC_PHASE_MEMORY) +#define HWLOC_DISC_PHASE_PCI HWLOC_NAME_CAPS(DISC_PHASE_PCI) +#define HWLOC_DISC_PHASE_IO HWLOC_NAME_CAPS(DISC_PHASE_IO) +#define HWLOC_DISC_PHASE_MISC HWLOC_NAME_CAPS(DISC_PHASE_MISC) +#define HWLOC_DISC_PHASE_ANNOTATE HWLOC_NAME_CAPS(DISC_PHASE_ANNOTATE) +#define HWLOC_DISC_PHASE_TWEAK HWLOC_NAME_CAPS(DISC_PHASE_TWEAK) +#define hwloc_disc_phase_t HWLOC_NAME(disc_phase_t) +#define hwloc_disc_component HWLOC_NAME(disc_component) + +#define hwloc_disc_status_flag_e HWLOC_NAME(disc_status_flag_e) +#define HWLOC_DISC_STATUS_FLAG_GOT_ALLOWED_RESOURCES HWLOC_NAME_CAPS(DISC_STATUS_FLAG_GOT_ALLOWED_RESOURCES) +#define hwloc_disc_status HWLOC_NAME(disc_status) + +#define hwloc_backend HWLOC_NAME(backend) + +#define hwloc_backend_alloc HWLOC_NAME(backend_alloc) +#define hwloc_backend_enable HWLOC_NAME(backend_enable) + +#define hwloc_component_type_e HWLOC_NAME(component_type_e) +#define HWLOC_COMPONENT_TYPE_DISC HWLOC_NAME_CAPS(COMPONENT_TYPE_DISC) +#define HWLOC_COMPONENT_TYPE_XML HWLOC_NAME_CAPS(COMPONENT_TYPE_XML) +#define hwloc_component_type_t HWLOC_NAME(component_type_t) +#define hwloc_component HWLOC_NAME(component) + +#define hwloc_plugin_check_namespace HWLOC_NAME(plugin_check_namespace) + +#define hwloc_hide_errors HWLOC_NAME(hide_errors) +#define hwloc__insert_object_by_cpuset HWLOC_NAME(_insert_object_by_cpuset) +#define hwloc_insert_object_by_parent HWLOC_NAME(insert_object_by_parent) +#define hwloc_alloc_setup_object HWLOC_NAME(alloc_setup_object) +#define hwloc_obj_add_children_sets HWLOC_NAME(add_children_sets) +#define hwloc_topology_reconnect HWLOC_NAME(topology_reconnect) + +#define hwloc_filter_check_pcidev_subtype_important HWLOC_NAME(filter_check_pcidev_subtype_important) +#define hwloc_filter_check_osdev_subtype_important HWLOC_NAME(filter_check_osdev_subtype_important) +#define hwloc_filter_check_keep_object_type HWLOC_NAME(filter_check_keep_object_type) +#define hwloc_filter_check_keep_object HWLOC_NAME(filter_check_keep_object) + +#define hwloc_pcidisc_find_cap HWLOC_NAME(pcidisc_find_cap) +#define hwloc_pcidisc_find_linkspeed HWLOC_NAME(pcidisc_find_linkspeed) +#define hwloc_pcidisc_check_bridge_type HWLOC_NAME(pcidisc_check_bridge_type) +#define hwloc_pcidisc_find_bridge_buses HWLOC_NAME(pcidisc_find_bridge_buses) +#define hwloc_pcidisc_tree_insert_by_busid HWLOC_NAME(pcidisc_tree_insert_by_busid) +#define hwloc_pcidisc_tree_attach HWLOC_NAME(pcidisc_tree_attach) + +#define hwloc_pci_find_by_busid HWLOC_NAME(pcidisc_find_by_busid) +#define hwloc_pci_find_parent_by_busid HWLOC_NAME(pcidisc_find_busid_parent) + +#define hwloc_backend_distances_add_handle_t HWLOC_NAME(backend_distances_add_handle_t) +#define hwloc_backend_distances_add_create HWLOC_NAME(backend_distances_add_create) +#define hwloc_backend_distances_add_values HWLOC_NAME(backend_distances_add_values) +#define hwloc_backend_distances_add_commit HWLOC_NAME(backend_distances_add_commit) + +/* hwloc/deprecated.h */ + +#define hwloc_distances_add HWLOC_NAME(distances_add) + +#define hwloc_topology_insert_misc_object_by_parent HWLOC_NAME(topology_insert_misc_object_by_parent) +#define hwloc_obj_cpuset_snprintf HWLOC_NAME(obj_cpuset_snprintf) +#define hwloc_obj_type_sscanf HWLOC_NAME(obj_type_sscanf) + +#define hwloc_set_membind_nodeset HWLOC_NAME(set_membind_nodeset) +#define hwloc_get_membind_nodeset HWLOC_NAME(get_membind_nodeset) +#define hwloc_set_proc_membind_nodeset HWLOC_NAME(set_proc_membind_nodeset) +#define hwloc_get_proc_membind_nodeset HWLOC_NAME(get_proc_membind_nodeset) +#define hwloc_set_area_membind_nodeset HWLOC_NAME(set_area_membind_nodeset) +#define hwloc_get_area_membind_nodeset HWLOC_NAME(get_area_membind_nodeset) +#define hwloc_alloc_membind_nodeset HWLOC_NAME(alloc_membind_nodeset) + +#define hwloc_cpuset_to_nodeset_strict HWLOC_NAME(cpuset_to_nodeset_strict) +#define hwloc_cpuset_from_nodeset_strict HWLOC_NAME(cpuset_from_nodeset_strict) + +/* private/debug.h */ + +#define hwloc_debug_enabled HWLOC_NAME(debug_enabled) +#define hwloc_debug HWLOC_NAME(debug) + +/* private/misc.h */ + +#ifndef HWLOC_HAVE_CORRECT_SNPRINTF +#define hwloc_snprintf HWLOC_NAME(snprintf) +#endif +#define hwloc_ffsl_manual HWLOC_NAME(ffsl_manual) +#define hwloc_ffs32 HWLOC_NAME(ffs32) +#define hwloc_ffsl_from_ffs32 HWLOC_NAME(ffsl_from_ffs32) +#define hwloc_flsl_manual HWLOC_NAME(flsl_manual) +#define hwloc_fls32 HWLOC_NAME(fls32) +#define hwloc_flsl_from_fls32 HWLOC_NAME(flsl_from_fls32) +#define hwloc_weight_long HWLOC_NAME(weight_long) +#define hwloc_strncasecmp HWLOC_NAME(strncasecmp) + +#define hwloc_bitmap_compare_inclusion HWLOC_NAME(bitmap_compare_inclusion) + +#define hwloc_pci_class_string HWLOC_NAME(pci_class_string) +#define hwloc_linux_pci_link_speed_from_string HWLOC_NAME(linux_pci_link_speed_from_string) + +#define hwloc_cache_type_by_depth_type HWLOC_NAME(cache_type_by_depth_type) +#define hwloc__obj_type_is_normal HWLOC_NAME(_obj_type_is_normal) +#define hwloc__obj_type_is_memory HWLOC_NAME(_obj_type_is_memory) +#define hwloc__obj_type_is_io HWLOC_NAME(_obj_type_is_io) +#define hwloc__obj_type_is_special HWLOC_NAME(_obj_type_is_special) + +#define hwloc__obj_type_is_cache HWLOC_NAME(_obj_type_is_cache) +#define hwloc__obj_type_is_dcache HWLOC_NAME(_obj_type_is_dcache) +#define hwloc__obj_type_is_icache HWLOC_NAME(_obj_type_is_icache) + +#define hwloc__pci_link_speed HWLOC_NAME(_pci_link_speed) + +/* private/cpuid-x86.h */ + +#define hwloc_have_x86_cpuid HWLOC_NAME(have_x86_cpuid) +#define hwloc_x86_cpuid HWLOC_NAME(x86_cpuid) + +/* private/xml.h */ + +#define hwloc__xml_verbose HWLOC_NAME(_xml_verbose) + +#define hwloc__xml_import_state_s HWLOC_NAME(_xml_import_state_s) +#define hwloc__xml_import_state_t HWLOC_NAME(_xml_import_state_t) +#define hwloc__xml_import_diff HWLOC_NAME(_xml_import_diff) +#define hwloc_xml_backend_data_s HWLOC_NAME(xml_backend_data_s) +#define hwloc__xml_export_state_s HWLOC_NAME(_xml_export_state_s) +#define hwloc__xml_export_state_t HWLOC_NAME(_xml_export_state_t) +#define hwloc__xml_export_data_s HWLOC_NAME(_xml_export_data_s) +#define hwloc__xml_export_topology HWLOC_NAME(_xml_export_topology) +#define hwloc__xml_export_diff HWLOC_NAME(_xml_export_diff) + +#define hwloc_xml_callbacks HWLOC_NAME(xml_callbacks) +#define hwloc_xml_component HWLOC_NAME(xml_component) +#define hwloc_xml_callbacks_register HWLOC_NAME(xml_callbacks_register) +#define hwloc_xml_callbacks_reset HWLOC_NAME(xml_callbacks_reset) + +#define hwloc__xml_imported_v1distances_s HWLOC_NAME(_xml_imported_v1distances_s) + +/* private/components.h */ + +#define hwloc_disc_component_force_enable HWLOC_NAME(disc_component_force_enable) +#define hwloc_disc_components_enable_others HWLOC_NAME(disc_components_instantiate_others) + +#define hwloc_backends_is_thissystem HWLOC_NAME(backends_is_thissystem) +#define hwloc_backends_find_callbacks HWLOC_NAME(backends_find_callbacks) + +#define hwloc_topology_components_init HWLOC_NAME(topology_components_init) +#define hwloc_backends_disable_all HWLOC_NAME(backends_disable_all) +#define hwloc_topology_components_fini HWLOC_NAME(topology_components_fini) + +#define hwloc_components_init HWLOC_NAME(components_init) +#define hwloc_components_fini HWLOC_NAME(components_fini) + +/* private/internal-private.h */ + +#define hwloc_xml_component HWLOC_NAME(xml_component) +#define hwloc_synthetic_component HWLOC_NAME(synthetic_component) + +#define hwloc_aix_component HWLOC_NAME(aix_component) +#define hwloc_bgq_component HWLOC_NAME(bgq_component) +#define hwloc_darwin_component HWLOC_NAME(darwin_component) +#define hwloc_freebsd_component HWLOC_NAME(freebsd_component) +#define hwloc_hpux_component HWLOC_NAME(hpux_component) +#define hwloc_linux_component HWLOC_NAME(linux_component) +#define hwloc_netbsd_component HWLOC_NAME(netbsd_component) +#define hwloc_noos_component HWLOC_NAME(noos_component) +#define hwloc_solaris_component HWLOC_NAME(solaris_component) +#define hwloc_windows_component HWLOC_NAME(windows_component) +#define hwloc_x86_component HWLOC_NAME(x86_component) + +#define hwloc_cuda_component HWLOC_NAME(cuda_component) +#define hwloc_gl_component HWLOC_NAME(gl_component) +#define hwloc_levelzero_component HWLOC_NAME(levelzero_component) +#define hwloc_nvml_component HWLOC_NAME(nvml_component) +#define hwloc_rsmi_component HWLOC_NAME(rsmi_component) +#define hwloc_opencl_component HWLOC_NAME(opencl_component) +#define hwloc_pci_component HWLOC_NAME(pci_component) + +#define hwloc_xml_libxml_component HWLOC_NAME(xml_libxml_component) +#define hwloc_xml_nolibxml_component HWLOC_NAME(xml_nolibxml_component) + +/* private/private.h */ + +#define hwloc_internal_location_s HWLOC_NAME(internal_location_s) + +#define hwloc_special_level_s HWLOC_NAME(special_level_s) + +#define hwloc_pci_locality_s HWLOC_NAME(pci_locality_s) + +#define hwloc_topology_forced_component_s HWLOC_NAME(topology_forced_component) + +#define hwloc_alloc_root_sets HWLOC_NAME(alloc_root_sets) +#define hwloc_setup_pu_level HWLOC_NAME(setup_pu_level) +#define hwloc_get_sysctlbyname HWLOC_NAME(get_sysctlbyname) +#define hwloc_get_sysctl HWLOC_NAME(get_sysctl) +#define hwloc_fallback_nbprocessors HWLOC_NAME(fallback_nbprocessors) +#define hwloc_fallback_memsize HWLOC_NAME(fallback_memsize) + +#define hwloc__object_cpusets_compare_first HWLOC_NAME(_object_cpusets_compare_first) +#define hwloc__reorder_children HWLOC_NAME(_reorder_children) + +#define hwloc_topology_setup_defaults HWLOC_NAME(topology_setup_defaults) +#define hwloc_topology_clear HWLOC_NAME(topology_clear) + +#define hwloc__reconnect HWLOC_NAME(_reconnect) + +#define hwloc__attach_memory_object HWLOC_NAME(insert_memory_object) + +#define hwloc_get_obj_by_type_and_gp_index HWLOC_NAME(get_obj_by_type_and_gp_index) + +#define hwloc_pci_discovery_init HWLOC_NAME(pci_discovery_init) +#define hwloc_pci_discovery_prepare HWLOC_NAME(pci_discovery_prepare) +#define hwloc_pci_discovery_exit HWLOC_NAME(pci_discovery_exit) +#define hwloc_find_insert_io_parent_by_complete_cpuset HWLOC_NAME(hwloc_find_insert_io_parent_by_complete_cpuset) + +#define hwloc__add_info HWLOC_NAME(_add_info) +#define hwloc__add_info_nodup HWLOC_NAME(_add_info_nodup) +#define hwloc__move_infos HWLOC_NAME(_move_infos) +#define hwloc__free_infos HWLOC_NAME(_free_infos) +#define hwloc__tma_dup_infos HWLOC_NAME(_tma_dup_infos) + +#define hwloc_binding_hooks HWLOC_NAME(binding_hooks) +#define hwloc_set_native_binding_hooks HWLOC_NAME(set_native_binding_hooks) +#define hwloc_set_binding_hooks HWLOC_NAME(set_binding_hooks) + +#define hwloc_set_linuxfs_hooks HWLOC_NAME(set_linuxfs_hooks) +#define hwloc_set_bgq_hooks HWLOC_NAME(set_bgq_hooks) +#define hwloc_set_solaris_hooks HWLOC_NAME(set_solaris_hooks) +#define hwloc_set_aix_hooks HWLOC_NAME(set_aix_hooks) +#define hwloc_set_windows_hooks HWLOC_NAME(set_windows_hooks) +#define hwloc_set_darwin_hooks HWLOC_NAME(set_darwin_hooks) +#define hwloc_set_freebsd_hooks HWLOC_NAME(set_freebsd_hooks) +#define hwloc_set_netbsd_hooks HWLOC_NAME(set_netbsd_hooks) +#define hwloc_set_hpux_hooks HWLOC_NAME(set_hpux_hooks) + +#define hwloc_look_hardwired_fujitsu_k HWLOC_NAME(look_hardwired_fujitsu_k) +#define hwloc_look_hardwired_fujitsu_fx10 HWLOC_NAME(look_hardwired_fujitsu_fx10) +#define hwloc_look_hardwired_fujitsu_fx100 HWLOC_NAME(look_hardwired_fujitsu_fx100) + +#define hwloc_add_uname_info HWLOC_NAME(add_uname_info) +#define hwloc_free_unlinked_object HWLOC_NAME(free_unlinked_object) +#define hwloc_free_object_and_children HWLOC_NAME(free_object_and_children) +#define hwloc_free_object_siblings_and_children HWLOC_NAME(free_object_siblings_and_children) + +#define hwloc_alloc_heap HWLOC_NAME(alloc_heap) +#define hwloc_alloc_mmap HWLOC_NAME(alloc_mmap) +#define hwloc_free_heap HWLOC_NAME(free_heap) +#define hwloc_free_mmap HWLOC_NAME(free_mmap) +#define hwloc_alloc_or_fail HWLOC_NAME(alloc_or_fail) + +#define hwloc_internal_distances_s HWLOC_NAME(internal_distances_s) +#define hwloc_internal_distances_init HWLOC_NAME(internal_distances_init) +#define hwloc_internal_distances_prepare HWLOC_NAME(internal_distances_prepare) +#define hwloc_internal_distances_dup HWLOC_NAME(internal_distances_dup) +#define hwloc_internal_distances_refresh HWLOC_NAME(internal_distances_refresh) +#define hwloc_internal_distances_destroy HWLOC_NAME(internal_distances_destroy) +#define hwloc_internal_distances_add HWLOC_NAME(internal_distances_add) +#define hwloc_internal_distances_add_by_index HWLOC_NAME(internal_distances_add_by_index) +#define hwloc_internal_distances_invalidate_cached_objs HWLOC_NAME(hwloc_internal_distances_invalidate_cached_objs) + +#define hwloc_internal_memattr_set_value HWLOC_NAME(internal_memattr_set_value) +#define hwloc_internal_memattr_s HWLOC_NAME(internal_memattr_s) +#define hwloc_internal_memattr_target_s HWLOC_NAME(internal_memattr_target_s) +#define hwloc_internal_memattr_initiator_s HWLOC_NAME(internal_memattr_initiator_s) +#define hwloc_internal_memattrs_init HWLOC_NAME(internal_memattrs_init) +#define hwloc_internal_memattrs_prepare HWLOC_NAME(internal_memattrs_prepare) +#define hwloc_internal_memattrs_dup HWLOC_NAME(internal_memattrs_dup) +#define hwloc_internal_memattrs_destroy HWLOC_NAME(internal_memattrs_destroy) +#define hwloc_internal_memattrs_need_refresh HWLOC_NAME(internal_memattrs_need_refresh) +#define hwloc_internal_memattrs_refresh HWLOC_NAME(internal_memattrs_refresh) +#define hwloc_internal_memattrs_guess_memory_tiers HWLOC_NAME(internal_memattrs_guess_memory_tiers) + +#define hwloc_internal_cpukind_s HWLOC_NAME(internal_cpukind_s) +#define hwloc_internal_cpukinds_init HWLOC_NAME(internal_cpukinds_init) +#define hwloc_internal_cpukinds_destroy HWLOC_NAME(internal_cpukinds_destroy) +#define hwloc_internal_cpukinds_dup HWLOC_NAME(internal_cpukinds_dup) +#define hwloc_internal_cpukinds_register HWLOC_NAME(internal_cpukinds_register) +#define hwloc_internal_cpukinds_rank HWLOC_NAME(internal_cpukinds_rank) +#define hwloc_internal_cpukinds_restrict HWLOC_NAME(internal_cpukinds_restrict) + +#define hwloc_encode_to_base64 HWLOC_NAME(encode_to_base64) +#define hwloc_decode_from_base64 HWLOC_NAME(decode_from_base64) + +#define hwloc_progname HWLOC_NAME(progname) + +#define hwloc__topology_disadopt HWLOC_NAME(_topology_disadopt) +#define hwloc__topology_dup HWLOC_NAME(_topology_dup) + +#define hwloc_tma HWLOC_NAME(tma) +#define hwloc_tma_malloc HWLOC_NAME(tma_malloc) +#define hwloc_tma_calloc HWLOC_NAME(tma_calloc) +#define hwloc_tma_strdup HWLOC_NAME(tma_strdup) +#define hwloc_bitmap_tma_dup HWLOC_NAME(bitmap_tma_dup) + +/* private/solaris-chiptype.h */ + +#define hwloc_solaris_chip_info_s HWLOC_NAME(solaris_chip_info_s) +#define hwloc_solaris_get_chip_info HWLOC_NAME(solaris_get_chip_info) + +#endif /* HWLOC_SYM_TRANSFORM */ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* HWLOC_RENAME_H */ diff --git a/src/deps/hwloc/include/hwloc/rsmi.h b/src/deps/hwloc/include/hwloc/rsmi.h new file mode 100644 index 000000000..a9e9ad28f --- /dev/null +++ b/src/deps/hwloc/include/hwloc/rsmi.h @@ -0,0 +1,207 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * Copyright © 2012-2023 Inria. All rights reserved. + * Copyright (c) 2020, Advanced Micro Devices, Inc. All rights reserved. + * Written by Advanced Micro Devices, + * See COPYING in top-level directory. + */ + +/** \file + * \brief Macros to help interaction between hwloc and the ROCm SMI Management Library. + * + * Applications that use both hwloc and the ROCm SMI Management Library may want to + * include this file so as to get topology information for AMD GPU devices. + */ + +#ifndef HWLOC_RSMI_H +#define HWLOC_RSMI_H + +#include "hwloc.h" +#include "hwloc/autogen/config.h" +#include "hwloc/helper.h" +#ifdef HWLOC_LINUX_SYS +#include "hwloc/linux.h" +#endif + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** \defgroup hwlocality_rsmi Interoperability with the ROCm SMI Management Library + * + * This interface offers ways to retrieve topology information about + * devices managed by the ROCm SMI Management Library. + * + * @{ + */ + +/** \brief Get the CPU set of logical processors that are physically + * close to AMD GPU device whose index is \p dv_ind. + * + * Store in \p set the CPU-set describing the locality of the AMD GPU device + * whose index is \p dv_ind. + * + * Topology \p topology and device \p dv_ind must match the local machine. + * I/O devices detection and the ROCm SMI component are not needed in the + * topology. + * + * The function only returns the locality of the device. + * If more information about the device is needed, OS objects should + * be used instead, see hwloc_rsmi_get_device_osdev() + * and hwloc_rsmi_get_device_osdev_by_index(). + * + * This function is currently only implemented in a meaningful way for + * Linux; other systems will simply get a full cpuset. + * + * \return 0 on success. + * \return -1 on error, for instance if device information could not be found. + */ +static __hwloc_inline int +hwloc_rsmi_get_device_cpuset(hwloc_topology_t topology __hwloc_attribute_unused, + uint32_t dv_ind, hwloc_cpuset_t set) +{ +#ifdef HWLOC_LINUX_SYS + /* If we're on Linux, use the sysfs mechanism to get the local cpus */ +#define HWLOC_RSMI_DEVICE_SYSFS_PATH_MAX 128 + char path[HWLOC_RSMI_DEVICE_SYSFS_PATH_MAX]; + rsmi_status_t ret; + uint64_t bdfid = 0; + unsigned domain, device, bus; + + if (!hwloc_topology_is_thissystem(topology)) { + errno = EINVAL; + return -1; + } + + ret = rsmi_dev_pci_id_get(dv_ind, &bdfid); + if (RSMI_STATUS_SUCCESS != ret) { + errno = EINVAL; + return -1; + } + domain = (bdfid>>32) & 0xffffffff; + bus = ((bdfid & 0xffff)>>8) & 0xff; + device = ((bdfid & 0xff)>>3) & 0x1f; + + sprintf(path, "/sys/bus/pci/devices/%04x:%02x:%02x.0/local_cpus", domain, bus, device); + if (hwloc_linux_read_path_as_cpumask(path, set) < 0 + || hwloc_bitmap_iszero(set)) + hwloc_bitmap_copy(set, hwloc_topology_get_complete_cpuset(topology)); +#else + /* Non-Linux systems simply get a full cpuset */ + hwloc_bitmap_copy(set, hwloc_topology_get_complete_cpuset(topology)); +#endif + return 0; +} + +/** \brief Get the hwloc OS device object corresponding to the + * AMD GPU device whose index is \p dv_ind. + * + * \return The hwloc OS device object describing the AMD GPU device whose + * index is \p dv_ind. + * \return \c NULL if none could be found. + * + * The topology \p topology does not necessarily have to match the current + * machine. For instance the topology may be an XML import of a remote host. + * I/O devices detection and the ROCm SMI component must be enabled in the + * topology. + * + * \note The corresponding PCI device object can be obtained by looking + * at the OS device parent object (unless PCI devices are filtered out). + */ +static __hwloc_inline hwloc_obj_t +hwloc_rsmi_get_device_osdev_by_index(hwloc_topology_t topology, uint32_t dv_ind) +{ + hwloc_obj_t osdev = NULL; + while ((osdev = hwloc_get_next_osdev(topology, osdev)) != NULL) { + if (HWLOC_OBJ_OSDEV_GPU == osdev->attr->osdev.type + && osdev->name + && !strncmp("rsmi", osdev->name, 4) + && atoi(osdev->name + 4) == (int) dv_ind) + return osdev; + } + return NULL; +} + +/** \brief Get the hwloc OS device object corresponding to AMD GPU device, + * whose index is \p dv_ind. + * + * \return The hwloc OS device object that describes the given + * AMD GPU, whose index is \p dv_ind. + * \return \c NULL if none could be found. + * + * Topology \p topology and device \p dv_ind must match the local machine. + * I/O devices detection and the ROCm SMI component must be enabled in the + * topology. If not, the locality of the object may still be found using + * hwloc_rsmi_get_device_cpuset(). + * + * \note The corresponding hwloc PCI device may be found by looking + * at the result parent pointer (unless PCI devices are filtered out). + */ +static __hwloc_inline hwloc_obj_t +hwloc_rsmi_get_device_osdev(hwloc_topology_t topology, uint32_t dv_ind) +{ + hwloc_obj_t osdev; + rsmi_status_t ret; + uint64_t bdfid = 0; + unsigned domain, device, bus, func; + uint64_t id; + char uuid[64]; + + if (!hwloc_topology_is_thissystem(topology)) { + errno = EINVAL; + return NULL; + } + + ret = rsmi_dev_pci_id_get(dv_ind, &bdfid); + if (RSMI_STATUS_SUCCESS != ret) { + errno = EINVAL; + return NULL; + } + domain = (bdfid>>32) & 0xffffffff; + bus = ((bdfid & 0xffff)>>8) & 0xff; + device = ((bdfid & 0xff)>>3) & 0x1f; + func = bdfid & 0x7; + + ret = rsmi_dev_unique_id_get(dv_ind, &id); + if (RSMI_STATUS_SUCCESS != ret) + uuid[0] = '\0'; + else + sprintf(uuid, "%lx", id); + + osdev = NULL; + while ((osdev = hwloc_get_next_osdev(topology, osdev)) != NULL) { + hwloc_obj_t pcidev = osdev->parent; + const char *info; + + if (strncmp(osdev->name, "rsmi", 4)) + continue; + + if (pcidev + && pcidev->type == HWLOC_OBJ_PCI_DEVICE + && pcidev->attr->pcidev.domain == domain + && pcidev->attr->pcidev.bus == bus + && pcidev->attr->pcidev.dev == device + && pcidev->attr->pcidev.func == func) + return osdev; + + info = hwloc_obj_get_info_by_name(osdev, "AMDUUID"); + if (info && !strcmp(info, uuid)) + return osdev; + } + + return NULL; +} + +/** @} */ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* HWLOC_RSMI_H */ diff --git a/src/deps/hwloc/include/hwloc/shmem.h b/src/deps/hwloc/include/hwloc/shmem.h new file mode 100644 index 000000000..f35565a6b --- /dev/null +++ b/src/deps/hwloc/include/hwloc/shmem.h @@ -0,0 +1,143 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * Copyright © 2013-2023 Inria. All rights reserved. + * See COPYING in top-level directory. + */ + +/** \file + * \brief Sharing topologies between processes + */ + +#ifndef HWLOC_SHMEM_H +#define HWLOC_SHMEM_H + +#include "hwloc.h" + +#ifdef __cplusplus +extern "C" { +#elif 0 +} +#endif + + +/** \defgroup hwlocality_shmem Sharing topologies between processes + * + * These functions are used to share a topology between processes by + * duplicating it into a file-backed shared-memory buffer. + * + * The master process must first get the required shared-memory size + * for storing this topology with hwloc_shmem_topology_get_length(). + * + * Then it must find a virtual memory area of that size that is available + * in all processes (identical virtual addresses in all processes). + * On Linux, this can be done by comparing holes found in /proc/\/maps + * for each process. + * + * Once found, it must open a destination file for storing the buffer, + * and pass it to hwloc_shmem_topology_write() together with + * virtual memory address and length obtained above. + * + * Other processes may then adopt this shared topology by opening the + * same file and passing it to hwloc_shmem_topology_adopt() with the + * exact same virtual memory address and length. + * + * @{ + */ + +/** \brief Get the required shared memory length for storing a topology. + * + * This length (in bytes) must be used in hwloc_shmem_topology_write() + * and hwloc_shmem_topology_adopt() later. + * + * \return the length, or -1 on error, for instance if flags are invalid. + * + * \note Flags \p flags are currently unused, must be 0. + */ +HWLOC_DECLSPEC int hwloc_shmem_topology_get_length(hwloc_topology_t topology, + size_t *lengthp, + unsigned long flags); + +/** \brief Duplicate a topology to a shared memory file. + * + * Temporarily map a file in virtual memory and duplicate the + * topology \p topology by allocating duplicates in there. + * + * The segment of the file pointed by descriptor \p fd, + * starting at offset \p fileoffset, and of length \p length (in bytes), + * will be temporarily mapped at virtual address \p mmap_address + * during the duplication. + * + * The mapping length \p length must have been previously obtained with + * hwloc_shmem_topology_get_length() + * and the topology must not have been modified in the meantime. + * + * \note Flags \p flags are currently unused, must be 0. + * + * \note The object userdata pointer is duplicated but the pointed buffer + * is not. However the caller may also allocate it manually in shared memory + * to share it as well. + * + * \return 0 on success. + * \return -1 with errno set to \c EBUSY if the virtual memory mapping defined + * by \p mmap_address and \p length isn't available in the process. + * \return -1 with errno set to \c EINVAL if \p fileoffset, \p mmap_address + * or \p length aren't page-aligned. + */ +HWLOC_DECLSPEC int hwloc_shmem_topology_write(hwloc_topology_t topology, + int fd, hwloc_uint64_t fileoffset, + void *mmap_address, size_t length, + unsigned long flags); + +/** \brief Adopt a shared memory topology stored in a file. + * + * Map a file in virtual memory and adopt the topology that was previously + * stored there with hwloc_shmem_topology_write(). + * + * The returned adopted topology in \p topologyp can be used just like any + * topology. And it must be destroyed with hwloc_topology_destroy() as usual. + * + * However the topology is read-only. + * For instance, it cannot be modified with hwloc_topology_restrict() + * and object userdata pointers cannot be changed. + * + * The segment of the file pointed by descriptor \p fd, + * starting at offset \p fileoffset, and of length \p length (in bytes), + * will be mapped at virtual address \p mmap_address. + * + * The file pointed by descriptor \p fd, the offset \p fileoffset, + * the requested mapping virtual address \p mmap_address and the length \p length + * must be identical to what was given to hwloc_shmem_topology_write() earlier. + * + * \note Flags \p flags are currently unused, must be 0. + * + * \note The object userdata pointer should not be used unless the process + * that created the shared topology also placed userdata-pointed buffers + * in shared memory. + * + * \note This function takes care of calling hwloc_topology_abi_check(). + * + * \return 0 on success. + * + * \return -1 with errno set to \c EBUSY if the virtual memory mapping defined + * by \p mmap_address and \p length isn't available in the process. + * + * \return -1 with errno set to \c EINVAL if \p fileoffset, \p mmap_address + * or \p length aren't page-aligned, or do not match what was given to + * hwloc_shmem_topology_write() earlier. + * + * \return -1 with errno set to \c EINVAL if the layout of the topology structure + * is different between the writer process and the adopter process. + */ +HWLOC_DECLSPEC int hwloc_shmem_topology_adopt(hwloc_topology_t *topologyp, + int fd, hwloc_uint64_t fileoffset, + void *mmap_address, size_t length, + unsigned long flags); +/** @} */ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* HWLOC_SHMEM_H */ diff --git a/src/deps/hwloc/linux/build_hwloc.sh b/src/deps/hwloc/linux/build_hwloc.sh new file mode 100755 index 000000000..d0d80e0ec --- /dev/null +++ b/src/deps/hwloc/linux/build_hwloc.sh @@ -0,0 +1,62 @@ +#!/bin/bash +# Copyright (C) 2026 Intel Corporation +# Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +# Builds the static hwloc library bundled with UMF for Linux x86-64 and copies +# it, together with its headers, into src/deps/hwloc. Keep the configure +# options in sync with the hwloc ExternalProject in the top-level CMakeLists.txt. + +set -euo pipefail + +HWLOC_REPO=${HWLOC_REPO:-https://github.com/open-mpi/hwloc.git} +HWLOC_TAG=${HWLOC_TAG:-hwloc-2.13.0} + +SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +DEPS_DIR=$(dirname "$SCRIPT_DIR") +UMF_ROOT=$(cd "$SCRIPT_DIR/../../../.." && pwd) +TEMP_DIR="$SCRIPT_DIR/temp" +SRC_DIR="$TEMP_DIR/src" +INSTALL_DIR="$TEMP_DIR/install" + +if [ "$(uname -m)" != "x86_64" ]; then + echo "Error: the bundled hwloc is built only for x86-64" >&2 + exit 1 +fi + +rm -rf "$TEMP_DIR" +trap 'rm -rf "$TEMP_DIR"' EXIT + +git clone --depth 1 --branch "$HWLOC_TAG" "$HWLOC_REPO" "$SRC_DIR" +git -C "$SRC_DIR" apply "$UMF_ROOT/cmake/fix_coverity_issues.patch" + +cd "$SRC_DIR" +./autogen.sh +# -ffile-prefix-map keeps local build paths out of the committed archive +HWLOC_FLAGS="-O2 -fPIC -ffile-prefix-map=$SRC_DIR=hwloc" +./configure --prefix="$INSTALL_DIR" --runstatedir=/run \ + --enable-static=yes --enable-shared=no \ + --with-hwloc-symbol-prefix=umf_hwloc_ --disable-libxml2 \ + --disable-pci --disable-levelzero --disable-opencl \ + --disable-cuda --disable-nvml --disable-libudev --disable-rsmi \ + CFLAGS="$HWLOC_FLAGS" CXXFLAGS="$HWLOC_FLAGS" +make -j "$(nproc)" +make install + +unprefixed=$(nm -g --defined-only "$INSTALL_DIR/lib/libhwloc.a" | + awk 'NF == 3 {print $3}' | grep -v '^umf_hwloc_' || true) +if [ -n "$unprefixed" ]; then + echo "Error: hwloc defines symbols without the umf_hwloc_ prefix:" >&2 + echo "$unprefixed" >&2 + exit 1 +fi + +cp "$INSTALL_DIR/lib/libhwloc.a" "$SCRIPT_DIR/" +mkdir -p "$SCRIPT_DIR/include/hwloc/autogen" +cp "$INSTALL_DIR/include/hwloc/autogen/config.h" \ + "$SCRIPT_DIR/include/hwloc/autogen/" +mkdir -p "$DEPS_DIR/include/hwloc" +cp "$INSTALL_DIR/include/hwloc.h" "$DEPS_DIR/include/" +cp "$INSTALL_DIR"/include/hwloc/*.h "$DEPS_DIR/include/hwloc/" + +echo "Bundled hwloc ($HWLOC_TAG) updated in $DEPS_DIR" diff --git a/src/deps/hwloc/linux/include/hwloc/autogen/config.h b/src/deps/hwloc/linux/include/hwloc/autogen/config.h new file mode 100644 index 000000000..e44cb48aa --- /dev/null +++ b/src/deps/hwloc/linux/include/hwloc/autogen/config.h @@ -0,0 +1,243 @@ +/* include/hwloc/autogen/config.h. Generated from config.h.in by configure. */ +/* -*- c -*- + * SPDX-License-Identifier: BSD-3-Clause + * Copyright © 2009 CNRS + * Copyright © 2009-2022 Inria. All rights reserved. + * Copyright © 2009-2012 Université Bordeaux + * Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved. + * See COPYING in top-level directory. + */ + +/* The configuration file */ + +#ifndef HWLOC_CONFIG_H +#define HWLOC_CONFIG_H + +#define HWLOC_VERSION "2.13.0rc2-git" +#define HWLOC_VERSION_MAJOR 2 +#define HWLOC_VERSION_MINOR 13 +#define HWLOC_VERSION_RELEASE 0 +#define HWLOC_VERSION_GREEK "rc2" + +/* #undef HWLOC_PCI_COMPONENT_BUILTIN */ +/* #undef HWLOC_OPENCL_COMPONENT_BUILTIN */ +/* #undef HWLOC_CUDA_COMPONENT_BUILTIN */ +/* #undef HWLOC_NVML_COMPONENT_BUILTIN */ +/* #undef HWLOC_RSMI_COMPONENT_BUILTIN */ +/* #undef HWLOC_LEVELZERO_COMPONENT_BUILTIN */ +/* #undef HWLOC_GL_COMPONENT_BUILTIN */ +/* #undef HWLOC_XML_LIBXML_COMPONENT_BUILTIN */ + +#if (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)) +# define __hwloc_restrict __restrict +#else +# if __STDC_VERSION__ >= 199901L +# define __hwloc_restrict restrict +# else +# define __hwloc_restrict +# endif +#endif + +/* Note that if we're compiling C++, then just use the "inline" + keyword, since it's part of C++ */ +#if defined(c_plusplus) || defined(__cplusplus) +# define __hwloc_inline inline +#elif defined(_MSC_VER) || defined(__HP_cc) +# define __hwloc_inline __inline +#else +# define __hwloc_inline __inline__ +#endif + +/* + * Note: this is public. We can not assume anything from the compiler used + * by the application and thus the HWLOC_HAVE_* macros below are not + * fetched from the autoconf result here. We only automatically use a few + * well-known easy cases. + */ + +/* Some handy constants to make the logic below a little more readable */ +#if defined(__cplusplus) && \ + (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR >= 4)) +#define GXX_ABOVE_3_4 1 +#else +#define GXX_ABOVE_3_4 0 +#endif + +#if !defined(__cplusplus) && \ + (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)) +#define GCC_ABOVE_2_95 1 +#else +#define GCC_ABOVE_2_95 0 +#endif + +#if !defined(__cplusplus) && \ + (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)) +#define GCC_ABOVE_2_96 1 +#else +#define GCC_ABOVE_2_96 0 +#endif + +#if !defined(__cplusplus) && \ + (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) +#define GCC_ABOVE_3_3 1 +#else +#define GCC_ABOVE_3_3 0 +#endif + +#if !defined(__cplusplus) && \ + (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) +#define GCC_ABOVE_3_4 1 +#else +#define GCC_ABOVE_3_4 0 +#endif + +/* Maybe before gcc 2.95 too */ +#ifdef HWLOC_HAVE_ATTRIBUTE_UNUSED +#define __HWLOC_HAVE_ATTRIBUTE_UNUSED HWLOC_HAVE_ATTRIBUTE_UNUSED +#elif defined(__GNUC__) +# define __HWLOC_HAVE_ATTRIBUTE_UNUSED (GXX_ABOVE_3_4 || GCC_ABOVE_2_95) +#else +# define __HWLOC_HAVE_ATTRIBUTE_UNUSED 0 +#endif +#if __HWLOC_HAVE_ATTRIBUTE_UNUSED +# define __hwloc_attribute_unused __attribute__((__unused__)) +#else +# define __hwloc_attribute_unused +#endif + +#ifdef HWLOC_HAVE_ATTRIBUTE_MALLOC +#define __HWLOC_HAVE_ATTRIBUTE_MALLOC HWLOC_HAVE_ATTRIBUTE_MALLOC +#elif defined(__GNUC__) +# define __HWLOC_HAVE_ATTRIBUTE_MALLOC (GXX_ABOVE_3_4 || GCC_ABOVE_2_96) +#else +# define __HWLOC_HAVE_ATTRIBUTE_MALLOC 0 +#endif +#if __HWLOC_HAVE_ATTRIBUTE_MALLOC +# define __hwloc_attribute_malloc __attribute__((__malloc__)) +#else +# define __hwloc_attribute_malloc +#endif + +#ifdef HWLOC_HAVE_ATTRIBUTE_CONST +#define __HWLOC_HAVE_ATTRIBUTE_CONST HWLOC_HAVE_ATTRIBUTE_CONST +#elif defined(__GNUC__) +# define __HWLOC_HAVE_ATTRIBUTE_CONST (GXX_ABOVE_3_4 || GCC_ABOVE_2_95) +#else +# define __HWLOC_HAVE_ATTRIBUTE_CONST 0 +#endif +#if __HWLOC_HAVE_ATTRIBUTE_CONST +# define __hwloc_attribute_const __attribute__((__const__)) +#else +# define __hwloc_attribute_const +#endif + +#ifdef HWLOC_HAVE_ATTRIBUTE_PURE +#define __HWLOC_HAVE_ATTRIBUTE_PURE HWLOC_HAVE_ATTRIBUTE_PURE +#elif defined(__GNUC__) +# define __HWLOC_HAVE_ATTRIBUTE_PURE (GXX_ABOVE_3_4 || GCC_ABOVE_2_96) +#else +# define __HWLOC_HAVE_ATTRIBUTE_PURE 0 +#endif +#if __HWLOC_HAVE_ATTRIBUTE_PURE +# define __hwloc_attribute_pure __attribute__((__pure__)) +#else +# define __hwloc_attribute_pure +#endif + +#ifndef __hwloc_attribute_deprecated /* allow the user to disable these warnings by defining this macro to nothing */ +#ifdef HWLOC_HAVE_ATTRIBUTE_DEPRECATED +#define __HWLOC_HAVE_ATTRIBUTE_DEPRECATED HWLOC_HAVE_ATTRIBUTE_DEPRECATED +#elif defined(__GNUC__) +# define __HWLOC_HAVE_ATTRIBUTE_DEPRECATED (GXX_ABOVE_3_4 || GCC_ABOVE_3_3) +#else +# define __HWLOC_HAVE_ATTRIBUTE_DEPRECATED 0 +#endif +#if __HWLOC_HAVE_ATTRIBUTE_DEPRECATED +# define __hwloc_attribute_deprecated __attribute__((__deprecated__)) +#else +# define __hwloc_attribute_deprecated +#endif +#endif + +#ifdef HWLOC_HAVE_ATTRIBUTE_MAY_ALIAS +#define __HWLOC_HAVE_ATTRIBUTE_MAY_ALIAS HWLOC_HAVE_ATTRIBUTE_MAY_ALIAS +#elif defined(__GNUC__) +# define __HWLOC_HAVE_ATTRIBUTE_MAY_ALIAS (GXX_ABOVE_3_4 || GCC_ABOVE_3_3) +#else +# define __HWLOC_HAVE_ATTRIBUTE_MAY_ALIAS 0 +#endif +#if __HWLOC_HAVE_ATTRIBUTE_MAY_ALIAS +# define __hwloc_attribute_may_alias __attribute__((__may_alias__)) +#else +# define __hwloc_attribute_may_alias +#endif + +#ifdef HWLOC_HAVE_ATTRIBUTE_WARN_UNUSED_RESULT +#define __HWLOC_HAVE_ATTRIBUTE_WARN_UNUSED_RESULT HWLOC_HAVE_ATTRIBUTE_WARN_UNUSED_RESULT +#elif defined(__GNUC__) +# define __HWLOC_HAVE_ATTRIBUTE_WARN_UNUSED_RESULT (GXX_ABOVE_3_4 || GCC_ABOVE_3_4) +#else +# define __HWLOC_HAVE_ATTRIBUTE_WARN_UNUSED_RESULT 0 +#endif +#if __HWLOC_HAVE_ATTRIBUTE_WARN_UNUSED_RESULT +# define __hwloc_attribute_warn_unused_result __attribute__((__warn_unused_result__)) +#else +# define __hwloc_attribute_warn_unused_result +#endif + +#ifdef HWLOC_C_HAVE_VISIBILITY +# if HWLOC_C_HAVE_VISIBILITY +# define HWLOC_DECLSPEC __attribute__((__visibility__("default"))) +# else +# define HWLOC_DECLSPEC +# endif +#else +# define HWLOC_DECLSPEC +#endif + +/* Defined to 1 on Linux */ +#define HWLOC_LINUX_SYS 1 + +/* Defined to 1 if the CPU_SET macro works */ +#define HWLOC_HAVE_CPU_SET 1 + +/* Defined to 1 if you have the `windows.h' header. */ +/* #undef HWLOC_HAVE_WINDOWS_H */ +#define hwloc_pid_t pid_t +#define hwloc_thread_t pthread_t + +#ifdef HWLOC_HAVE_WINDOWS_H + +# include +typedef DWORDLONG hwloc_uint64_t; + +#else /* HWLOC_HAVE_WINDOWS_H */ + +# ifdef hwloc_thread_t +# include +# endif /* hwloc_thread_t */ + +/* Defined to 1 if you have the header file. */ +# define HWLOC_HAVE_STDINT_H 1 + +# include +# ifdef HWLOC_HAVE_STDINT_H +# include +# endif +typedef uint64_t hwloc_uint64_t; + +#endif /* HWLOC_HAVE_WINDOWS_H */ + +/* Define to 1 if --enable-32bits-pci-domain is called. */ +/* #undef HWLOC_HAVE_32BITS_PCI_DOMAIN */ + +/* Whether we need to re-define all the hwloc public symbols or not */ +#define HWLOC_SYM_TRANSFORM 1 + +/* The hwloc symbol prefix */ +#define HWLOC_SYM_PREFIX umf_hwloc_ + +/* The hwloc symbol prefix in all caps */ +#define HWLOC_SYM_PREFIX_CAPS UMF_HWLOC_ + +#endif /* HWLOC_CONFIG_H */ diff --git a/src/deps/hwloc/linux/libhwloc.a b/src/deps/hwloc/linux/libhwloc.a new file mode 100644 index 000000000..71cfd1a4f Binary files /dev/null and b/src/deps/hwloc/linux/libhwloc.a differ diff --git a/src/deps/hwloc/windows/build_hwloc.ps1 b/src/deps/hwloc/windows/build_hwloc.ps1 new file mode 100644 index 000000000..e4886632b --- /dev/null +++ b/src/deps/hwloc/windows/build_hwloc.ps1 @@ -0,0 +1,155 @@ +# Copyright (C) 2026 Intel Corporation +# Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +# Builds the static hwloc library bundled with UMF for Windows x64 and copies +# it, together with its headers, into src/deps/hwloc. +# Requires git, CMake and Visual Studio with the x64 C/C++ build tools. + +$ErrorActionPreference = 'Stop' +Set-StrictMode -Version Latest + +$HwlocRepo = if ($env:HWLOC_REPO) { $env:HWLOC_REPO } else { 'https://github.com/open-mpi/hwloc.git' } +$HwlocTag = if ($env:HWLOC_TAG) { $env:HWLOC_TAG } else { 'hwloc-2.13.0' } + +$ScriptDir = $PSScriptRoot +$DepsDir = Split-Path $ScriptDir -Parent +$UmfRoot = (Resolve-Path (Join-Path $ScriptDir '..\..\..\..')).Path +$TempDir = Join-Path $ScriptDir 'temp' +$SrcDir = Join-Path $TempDir 'src' +$BuildDir = Join-Path $TempDir 'build' + +function Invoke-Native { + param([string]$Exe, [string[]]$Arguments) + & $Exe @Arguments + if ($LASTEXITCODE -ne 0) { + throw "'$Exe $Arguments' failed with exit code $LASTEXITCODE" + } +} + +# The windows-cmake build has no symbol prefix option, so patch the config +# templates the same way configure's --with-hwloc-symbol-prefix would. +function Set-HwlocSymbolPrefix { + param([string]$Path) + $content = [IO.File]::ReadAllText($Path) + $replacements = [ordered]@{ + '(?m)^(#define HWLOC_SYM_TRANSFORM) 0(?=\r?$)' = '$1 1' + '(?m)^(#define HWLOC_SYM_PREFIX) hwloc_(?=\r?$)' = '$1 umf_hwloc_' + '(?m)^(#define HWLOC_SYM_PREFIX_CAPS) HWLOC_(?=\r?$)' = '$1 UMF_HWLOC_' + } + foreach ($pattern in $replacements.Keys) { + if ($content -notmatch $pattern) { + throw "Pattern '$pattern' not found in $Path" + } + $content = $content -replace $pattern, $replacements[$pattern] + } + [IO.File]::WriteAllText($Path, $content) +} + +function Find-Dumpbin { + $cmd = Get-Command dumpbin.exe -ErrorAction SilentlyContinue + if ($cmd) { + return $cmd.Source + } + $vswhere = Join-Path ${env:ProgramFiles(x86)} 'Microsoft Visual Studio\Installer\vswhere.exe' + if (Test-Path $vswhere) { + $found = & $vswhere -latest -products * -find 'VC\Tools\MSVC\**\bin\Hostx64\x64\dumpbin.exe' | + Select-Object -First 1 + if ($found) { + return $found + } + } + throw 'dumpbin.exe not found - install the Visual Studio C++ build tools' +} + +function Get-NormalizedText { + param([string]$Path) + return [IO.File]::ReadAllText($Path) -replace "`r`n", "`n" +} + +if (Test-Path $TempDir) { + Remove-Item -Recurse -Force $TempDir +} + +try { + Invoke-Native git @('clone', '-c', 'core.autocrlf=false', '-c', 'advice.detachedHead=false', + '--depth', '1', '--branch', $HwlocTag, $HwlocRepo, $SrcDir) + # The UMF checkout may have CRLF line endings, the hwloc clone has LF. + $patch = Join-Path $TempDir 'fix_coverity_issues.patch' + [IO.File]::WriteAllText($patch, + (Get-NormalizedText (Join-Path $UmfRoot 'cmake\fix_coverity_issues.patch'))) + Invoke-Native git @('-C', $SrcDir, 'apply', $patch) + + Set-HwlocSymbolPrefix (Join-Path $SrcDir 'contrib\windows\hwloc_config.h') + Set-HwlocSymbolPrefix (Join-Path $SrcDir 'contrib\windows-cmake\private_config.h.in') + + # /Zl omits the CRT name, so the archive links into both /MD and /MDd builds + # of UMF; /Brepro makes the output reproducible. RtlGetVersionProc is a + # global missing from hwloc's rename.h, so it is prefixed here. + Invoke-Native cmake @('-S', (Join-Path $SrcDir 'contrib\windows-cmake'), '-B', $BuildDir, + '-A', 'x64', + '-DBUILD_SHARED_LIBS=OFF', + '-DHWLOC_ENABLE_TESTING=OFF', + '-DHWLOC_SKIP_LSTOPO=ON', + '-DHWLOC_SKIP_TOOLS=ON', + '-DHWLOC_SKIP_INCLUDES=ON', + '-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDLL', + '-DCMAKE_C_FLAGS_RELEASE=/O2 /Ob2 /DNDEBUG /Zl /Brepro /DRtlGetVersionProc=umf_hwloc_RtlGetVersionProc', + '-DCMAKE_STATIC_LINKER_FLAGS=/Brepro') + Invoke-Native cmake @('--build', $BuildDir, '--config', 'Release', '--parallel') + + $lib = Join-Path $BuildDir 'Release\hwloc.lib' + $dumpbin = Find-Dumpbin + $dump = & $dumpbin /nologo /linkermember:1 $lib + if ($LASTEXITCODE -ne 0) { + throw "Failed to list symbols of $lib" + } + # Only the block after the "N public symbols" line lists symbol names. + $symbols = @() + $inSymbols = $false + foreach ($line in $dump) { + if ($line -match '^\s*[0-9A-F]+ public symbols\s*$') { + $inSymbols = $true + } + elseif ($inSymbols -and $line -match '^\s*$') { + if ($symbols.Count -gt 0) { break } + } + elseif ($inSymbols -and $line -match '^\s+[0-9A-F]+\s+(\S+)\s*$') { + $symbols += $Matches[1] + } + } + if ($symbols.Count -eq 0) { + throw "No public symbols found in $lib" + } + # COMDAT constants, string literals and CRT header inlines cannot conflict. + $allowedPrefixes = '^(__real@|__xmm@|__ymm@|\?\?_C@|\?_OptionsStorage@)' + $allowedNames = @( + '__isa_available_default', '__local_stdio_printf_options', + '__local_stdio_scanf_options', '_snprintf', '_vfprintf_l', '_vsnprintf', + '_vsnprintf_l', '_vsprintf_l', '_vsscanf_l', 'fabsf', 'fprintf', 'fstat', + 'sprintf', 'sscanf', 'stat', 'vsnprintf') + $unprefixed = @($symbols | Sort-Object -Unique | Where-Object { + $_ -notmatch '^umf_hwloc_' -and $_ -notmatch $allowedPrefixes -and + $_ -notin $allowedNames + }) + if ($unprefixed.Count -gt 0) { + throw "hwloc defines symbols without the umf_hwloc_ prefix:`n$($unprefixed -join "`n")" + } + + Copy-Item $lib $ScriptDir -Force + $autogenDir = Join-Path $ScriptDir 'include\hwloc\autogen' + New-Item -ItemType Directory -Force $autogenDir | Out-Null + Copy-Item (Join-Path $BuildDir 'include\hwloc\autogen\config.h') $autogenDir -Force + + $commonInclude = Join-Path $DepsDir 'include' + New-Item -ItemType Directory -Force (Join-Path $commonInclude 'hwloc') | Out-Null + Copy-Item (Join-Path $SrcDir 'include\hwloc.h') $commonInclude -Force + Copy-Item (Join-Path $SrcDir 'include\hwloc\*.h') (Join-Path $commonInclude 'hwloc') -Force +} +finally { + if (Test-Path $TempDir) { + Remove-Item -Recurse -Force $TempDir + } +} + +Write-Host "Bundled hwloc ($HwlocTag) updated in $DepsDir" diff --git a/src/deps/hwloc/windows/hwloc.lib b/src/deps/hwloc/windows/hwloc.lib new file mode 100644 index 000000000..0ae1b425f Binary files /dev/null and b/src/deps/hwloc/windows/hwloc.lib differ diff --git a/src/deps/hwloc/windows/include/hwloc/autogen/config.h b/src/deps/hwloc/windows/include/hwloc/autogen/config.h new file mode 100644 index 000000000..dde059faa --- /dev/null +++ b/src/deps/hwloc/windows/include/hwloc/autogen/config.h @@ -0,0 +1,60 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * Copyright © 2009 CNRS + * Copyright © 2009-2026 Inria. All rights reserved. + * Copyright © 2009-2012 Université Bordeaux + * Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved. + * See COPYING in top-level directory. + */ + +/* The configuration file */ + +#ifndef HWLOC_CONFIG_H +#define HWLOC_CONFIG_H + +#define HWLOC_VERSION "2.13.0rc2" +#define HWLOC_VERSION_MAJOR 2 +#define HWLOC_VERSION_MINOR 13 +#define HWLOC_VERSION_RELEASE 0 +#define HWLOC_VERSION_GREEK "rc2" + +#define __hwloc_restrict +#define __hwloc_inline __inline + +#define __hwloc_attribute_unused +#define __hwloc_attribute_malloc +#define __hwloc_attribute_const +#define __hwloc_attribute_pure +#define __hwloc_attribute_deprecated +#define __hwloc_attribute_may_alias +#define __hwloc_attribute_warn_unused_result + +/* Defined to 1 if you have the `windows.h' header. */ +#define HWLOC_HAVE_WINDOWS_H 1 +#define hwloc_pid_t HANDLE +#define hwloc_thread_t HANDLE + +#include +#include +typedef DWORDLONG hwloc_uint64_t; + +#if defined( _USRDLL ) /* dynamic linkage */ +#if defined( DECLSPEC_EXPORTS ) +#define HWLOC_DECLSPEC __declspec(dllexport) +#else +#define HWLOC_DECLSPEC __declspec(dllimport) +#endif +#else /* static linkage */ +#define HWLOC_DECLSPEC +#endif + +/* Whether we need to re-define all the hwloc public symbols or not */ +#define HWLOC_SYM_TRANSFORM 1 + +/* The hwloc symbol prefix */ +#define HWLOC_SYM_PREFIX umf_hwloc_ + +/* The hwloc symbol prefix in all caps */ +#define HWLOC_SYM_PREFIX_CAPS UMF_HWLOC_ + +#endif /* HWLOC_CONFIG_H */ diff --git a/test/install_test/CMakeLists.txt b/test/install_test/CMakeLists.txt new file mode 100644 index 000000000..8eb3d76d3 --- /dev/null +++ b/test/install_test/CMakeLists.txt @@ -0,0 +1,42 @@ +# Copyright (C) 2026 Intel Corporation +# Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +# Standalone project linking only against an installed UMF via find_package. +cmake_minimum_required(VERSION 3.14.0 FATAL_ERROR) +project(umf_install_consumer LANGUAGES C) +enable_testing() + +find_package(umf REQUIRED CONFIG) + +add_executable(umf_install_consumer main.c) +target_link_libraries(umf_install_consumer PRIVATE umf::umf umf::umf_headers) + +option(UMF_TEST_LINK_USER_HWLOC + "Also link the system hwloc, as a user application might" OFF) +if(UMF_TEST_LINK_USER_HWLOC) + # Prefer pkg-config (Linux); fall back to plain find_* (e.g. Windows with + # CMAKE_PREFIX_PATH pointing at a vcpkg-installed hwloc). + find_package(PkgConfig QUIET) + if(PkgConfig_FOUND) + pkg_check_modules(USER_HWLOC IMPORTED_TARGET hwloc) + endif() + if(USER_HWLOC_FOUND) + target_link_libraries(umf_install_consumer + PRIVATE PkgConfig::USER_HWLOC) + else() + find_path(USER_HWLOC_INCLUDE_DIR hwloc.h) + find_library(USER_HWLOC_LIBRARY hwloc) + if(NOT USER_HWLOC_INCLUDE_DIR OR NOT USER_HWLOC_LIBRARY) + message(FATAL_ERROR "User hwloc not found") + endif() + target_include_directories(umf_install_consumer + PRIVATE ${USER_HWLOC_INCLUDE_DIR}) + target_link_libraries(umf_install_consumer + PRIVATE ${USER_HWLOC_LIBRARY}) + endif() + target_compile_definitions(umf_install_consumer + PRIVATE UMF_TEST_LINK_USER_HWLOC=1) +endif() + +add_test(NAME umf_install_consumer COMMAND umf_install_consumer) diff --git a/test/install_test/main.c b/test/install_test/main.c new file mode 100644 index 000000000..c2f9baec4 --- /dev/null +++ b/test/install_test/main.c @@ -0,0 +1,93 @@ +/* + * + * Copyright (C) 2026 Intel Corporation + * + * Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + * + */ + +#include + +#ifdef UMF_TEST_LINK_USER_HWLOC +#include +#endif + +#include +#include +#include + +#ifdef UMF_TEST_LINK_USER_HWLOC +// The user's hwloc must keep working next to the copy embedded in UMF. +static int use_user_hwloc(void) { + hwloc_topology_t topology; + + if (hwloc_get_api_version() != HWLOC_API_VERSION) { + fprintf(stderr, + "hwloc API version mismatch: runtime 0x%x, header 0x%x\n", + hwloc_get_api_version(), HWLOC_API_VERSION); + return 1; + } + + if (hwloc_topology_init(&topology) != 0) { + fprintf(stderr, "hwloc_topology_init failed\n"); + return 1; + } + + int ret = hwloc_topology_load(topology); + hwloc_topology_destroy(topology); + if (ret != 0) { + fprintf(stderr, "hwloc_topology_load failed\n"); + return 1; + } + + return 0; +} +#endif + +// The OS memory provider pulls hwloc symbols into the link of a static UMF. +int main(void) { + umf_os_memory_provider_params_handle_t params = NULL; + umf_memory_provider_handle_t provider = NULL; + void *ptr = NULL; + const size_t size = 4096; + int ret = 1; + +#ifdef UMF_TEST_LINK_USER_HWLOC + if (use_user_hwloc() != 0) { + return 1; + } +#endif + + if (umfOsMemoryProviderParamsCreate(¶ms) != UMF_RESULT_SUCCESS) { + fprintf(stderr, "umfOsMemoryProviderParamsCreate failed\n"); + return 1; + } + + if (umfMemoryProviderCreate(umfOsMemoryProviderOps(), params, &provider) != + UMF_RESULT_SUCCESS) { + fprintf(stderr, "umfMemoryProviderCreate failed\n"); + goto err_params; + } + + if (umfMemoryProviderAlloc(provider, size, 0, &ptr) != UMF_RESULT_SUCCESS || + ptr == NULL) { + fprintf(stderr, "umfMemoryProviderAlloc failed\n"); + goto err_provider; + } + + ((char *)ptr)[0] = 1; + + if (umfMemoryProviderFree(provider, ptr, size) != UMF_RESULT_SUCCESS) { + fprintf(stderr, "umfMemoryProviderFree failed\n"); + goto err_provider; + } + + ret = 0; + +err_provider: + umfMemoryProviderDestroy(provider); +err_params: + umfOsMemoryProviderParamsDestroy(params); + return ret; +} diff --git a/test/test_installation.py b/test/test_installation.py index cba8a4fb3..33d2c96fc 100644 --- a/test/test_installation.py +++ b/test/test_installation.py @@ -1,4 +1,4 @@ -# Copyright (C) 2024-2025 Intel Corporation +# Copyright (C) 2024-2026 Intel Corporation # # Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception @@ -107,8 +107,10 @@ def _create_match_list(self) -> List[str]: for pool in self.pools: lib.append(f"lib/{lib_prefix}{pool}.{lib_ext_static}") - if platform.system() == "Windows" and self.hwloc: + if self.hwloc and platform.system() == "Windows": lib.append(f"lib/{lib_prefix}hwloc.{lib_ext_static}") + elif self.hwloc and not self.shared_library: + lib.append(f"lib/{lib_prefix}umf_hwloc.{lib_ext_static}") if self.shared_library: lib.append(f"lib/{lib_prefix}umf.{lib_ext_shared}") if platform.system() == "Windows" and self.umfd_lib: @@ -240,6 +242,53 @@ def validate_installed_files(self) -> None: print(line) sys.exit("Installation test - FAILED") + def validate_hwloc_symbols(self) -> None: + """ + Verifies that installed UMF libraries do not export unprefixed hwloc + symbols, which would clash with an hwloc linked by the application + """ + + if platform.system() != "Linux": + print(f"hwloc symbols check - SKIPPED on {platform.system()}", flush=True) + return + + lib_dir = Path(self.install_dir, "lib") + libs = [ + (lib, ["nm", "-g", "--defined-only"]) for lib in sorted(lib_dir.glob("*.a")) + ] + libs += [ + (lib, ["nm", "-D", "--defined-only"]) + for lib in sorted(lib_dir.glob("*.so*")) + if not lib.is_symlink() + ] + + failed = False + for lib, nm_cmd in libs: + cmd = nm_cmd + [str(lib)] + try: + result = subprocess.run( + cmd, capture_output=True, text=True, check=True + ) # nosec B603 + except (OSError, subprocess.CalledProcessError) as e: + sys.exit(f"Error: command '{' '.join(cmd)}' failed: {e}") + + symbols = [ + fields[2] + for fields in map(str.split, result.stdout.splitlines()) + if len(fields) == 3 + ] + + unprefixed = sorted({s for s in symbols if s.startswith("hwloc_")}) + if unprefixed: + failed = True + print(f"{lib.name} exports unprefixed hwloc symbols:", flush=True) + for symbol in unprefixed: + print(f" {symbol}") + + if failed: + sys.exit("hwloc symbols check - FAILED") + print("hwloc symbols check - PASSED", flush=True) + def uninstall_umf(self) -> None: """ Run the UMF uninstallation CMake target. @@ -359,6 +408,7 @@ def run(self) -> None: umf_installer.install_umf() umf_installer.validate_installed_files() + umf_installer.validate_hwloc_symbols() print("Installation test - PASSED", flush=True)