Update hwloc for MSVC to 2.4.0.

This commit is contained in:
XMRig 2020-12-14 02:55:50 +07:00
parent 7c682ec91a
commit ca3695a754
No known key found for this signature in database
GPG key ID: 446A53638BE94409
42 changed files with 4057 additions and 382 deletions

View file

@ -1,4 +1,4 @@
cmake_minimum_required (VERSION 2.8) cmake_minimum_required (VERSION 2.8.12)
project (hwloc C) project (hwloc C)
include_directories(include) include_directories(include)
@ -13,23 +13,25 @@ set(HEADERS
) )
set(SOURCES set(SOURCES
src/base64.c src/base64.c
src/bind.c src/bind.c
src/bitmap.c src/bitmap.c
src/components.c src/components.c
src/diff.c src/diff.c
src/distances.c src/distances.c
src/misc.c src/misc.c
src/pci-common.c src/pci-common.c
src/shmem.c src/shmem.c
src/topology.c src/topology.c
src/topology-noos.c src/topology-noos.c
src/topology-synthetic.c src/topology-synthetic.c
src/topology-windows.c src/topology-windows.c
src/topology-x86.c src/topology-x86.c
src/topology-xml.c src/topology-xml.c
src/topology-xml-nolibxml.c src/topology-xml-nolibxml.c
src/traversal.c src/traversal.c
src/memattrs.c
src/cpukinds.c
) )
add_library(hwloc STATIC add_library(hwloc STATIC

View file

@ -2,6 +2,7 @@ Copyright © 2009 CNRS
Copyright © 2009-2020 Inria. All rights reserved. Copyright © 2009-2020 Inria. All rights reserved.
Copyright © 2009-2013 Université Bordeaux Copyright © 2009-2013 Université Bordeaux
Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved. Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved.
Copyright © 2020 Hewlett Packard Enterprise. All rights reserved.
$COPYRIGHT$ $COPYRIGHT$
@ -16,6 +17,76 @@ bug fixes (and other actions) for each version of hwloc since version
0.9. 0.9.
Version 2.4.0
-------------
* API
+ Add hwloc/cpukinds.h for reporting information about hybrid CPUs.
- Use Linux cpufreq frequencies to rank cores by efficiency.
- Use x86 CPUID hybrid leaf and future Linux kernels sysfs CPU type
files to identify Intel Atom and Core cores.
- Use the Windows native EfficiencyClass to separate kinds.
* Backends
+ Properly handle Linux kernel 5.10+ exposing ACPI HMAT information
with knowledge of Generic Initiators.
* Tools
+ lstopo has new --cpukinds and --no-cpukinds options for showing
CPU kinds or not in textual and graphical modes respectively.
+ hwloc-calc has a new --cpukind option for filtering PUs by kind.
+ hwloc-annotate has a new cpukind command for modifying CPU kinds.
* Misc
+ Fix hwloc_bitmap_nr_ulongs(), thanks to Norbert Eicker.
+ Add a documentation section about
"Topology Attributes: Distances, Memory Attributes and CPU Kinds".
+ Silence some spurious warnings in the OpenCL backend and when showing
process binding with lstopo --ps.
Version 2.3.0
-------------
* API
+ Add hwloc/memattrs.h for exposing latency/bandwidth information
between initiators (CPU sets for now) and target NUMA nodes,
typically on heterogeneous platforms.
- When available, bandwidths and latencies are read from the ACPI HMAT
table exposed by Linux kernel 5.2+.
- Attributes may also be customized to expose user-defined performance
information.
+ Add hwloc_get_local_numanode_objs() for listing NUMA nodes that are
local to some locality.
+ The new topology flag HWLOC_TOPOLOGY_FLAG_IMPORT_SUPPORT causes
support arrays to be loaded from XML exported with hwloc 2.3+.
- hwloc_topology_get_support() now returns an additional "misc"
array with feature "imported_support" set when support was imported.
+ Add hwloc_topology_refresh() to refresh internal caches after modifying
the topology and before consulting the topology in a multithread context.
* Backends
+ Add a ROCm SMI backend and a hwloc/rsmi.h helper file for getting
the locality of AMD GPUs, now exposed as "rsmi" OS devices.
Thanks to Mike Li.
+ Remove POWER device-tree-based topology on Linux,
(it was disabled by default since 2.1).
* Tools
+ Command-line options for specifying flags now understand comma-separated
lists of flag names (substrings).
+ hwloc-info and hwloc-calc have new --local-memory --local-memory-flags
and --best-memattr options for reporting local memory nodes and filtering
by memory attributes.
+ hwloc-bind has a new --best-memattr option for filtering by memory attributes
among the memory binding set.
+ Tools that have a --restrict option may now receive a nodeset or
some custom flags for restricting the topology.
+ lstopo now has a --thickness option for changing line thickness in the
graphical output.
+ Fix lstopo drawing when autoresizing on Windows 10.
+ Pressing the F5 key in lstopo X11 and Windows graphical/interactive outputs
now refreshes the display according to the current topology and binding.
+ Add a tikz lstopo graphical backend to generate picture easily included into
LaTeX documents. Thanks to Clement Foyer.
* Misc
+ The default installation path of the Bash completion file has changed to
${datadir}/bash-completion/completions/hwloc. Thanks to Tomasz Kłoczko.
Version 2.2.0 Version 2.2.0
------------- -------------
* API * API

View file

@ -23,9 +23,9 @@ APIs are documented after these sections.
Installation Installation
hwloc (http://www.open-mpi.org/projects/hwloc/) is available under the BSD hwloc (https://www.open-mpi.org/projects/hwloc/) is available under the BSD
license. It is hosted as a sub-project of the overall Open MPI project (http:// license. It is hosted as a sub-project of the overall Open MPI project (https:/
www.open-mpi.org/). Note that hwloc does not require any functionality from /www.open-mpi.org/). Note that hwloc does not require any functionality from
Open MPI -- it is a wholly separate (and much smaller!) project and code base. Open MPI -- it is a wholly separate (and much smaller!) project and code base.
It just happens to be hosted as part of the overall Open MPI project. It just happens to be hosted as part of the overall Open MPI project.
@ -75,7 +75,7 @@ Bugs should be reported in the tracker (https://github.com/open-mpi/hwloc/
issues). Opening a new issue automatically displays lots of hints about how to issues). Opening a new issue automatically displays lots of hints about how to
debug and report issues. debug and report issues.
Questions may be sent to the users or developers mailing lists (http:// Questions may be sent to the users or developers mailing lists (https://
www.open-mpi.org/community/lists/hwloc.php). www.open-mpi.org/community/lists/hwloc.php).
There is also a #hwloc IRC channel on Freenode (irc.freenode.net). There is also a #hwloc IRC channel on Freenode (irc.freenode.net).

View file

@ -8,7 +8,7 @@
# Please update HWLOC_VERSION* in contrib/windows/hwloc_config.h too. # Please update HWLOC_VERSION* in contrib/windows/hwloc_config.h too.
major=2 major=2
minor=2 minor=4
release=0 release=0
# greek is used for alpha or beta release tags. If it is non-empty, # greek is used for alpha or beta release tags. If it is non-empty,
@ -22,7 +22,7 @@ greek=
# The date when this release was created # The date when this release was created
date="Mar 30, 2020" date="Nov 26, 2020"
# If snapshot=1, then use the value from snapshot_version as the # If snapshot=1, then use the value from snapshot_version as the
# entire hwloc version (i.e., ignore major, minor, release, and # entire hwloc version (i.e., ignore major, minor, release, and
@ -41,7 +41,7 @@ snapshot_version=${major}.${minor}.${release}${greek}-git
# 2. Version numbers are described in the Libtool current:revision:age # 2. Version numbers are described in the Libtool current:revision:age
# format. # format.
libhwloc_so_version=17:0:2 libhwloc_so_version=19:0:4
libnetloc_so_version=0:0:0 libnetloc_so_version=0:0:0
# Please also update the <TargetName> lines in contrib/windows/libhwloc.vcxproj # Please also update the <TargetName> lines in contrib/windows/libhwloc.vcxproj

View file

@ -2,7 +2,7 @@
* Copyright © 2009 CNRS * Copyright © 2009 CNRS
* Copyright © 2009-2020 Inria. All rights reserved. * Copyright © 2009-2020 Inria. All rights reserved.
* Copyright © 2009-2012 Université Bordeaux * Copyright © 2009-2012 Université Bordeaux
* Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved. * Copyright © 2009-2020 Cisco Systems, Inc. All rights reserved.
* See COPYING in top-level directory. * See COPYING in top-level directory.
*/ */
@ -11,7 +11,7 @@
* ------------------------------------------------ * ------------------------------------------------
* $tarball_directory/doc/doxygen-doc/ * $tarball_directory/doc/doxygen-doc/
* or * or
* http://www.open-mpi.org/projects/hwloc/doc/ * https://www.open-mpi.org/projects/hwloc/doc/
*===================================================================== *=====================================================================
* *
* FAIR WARNING: Do NOT expect to be able to figure out all the * FAIR WARNING: Do NOT expect to be able to figure out all the
@ -93,7 +93,7 @@ extern "C" {
* Two stable releases of the same series usually have the same ::HWLOC_API_VERSION * Two stable releases of the same series usually have the same ::HWLOC_API_VERSION
* even if their HWLOC_VERSION are different. * even if their HWLOC_VERSION are different.
*/ */
#define HWLOC_API_VERSION 0x00020100 #define HWLOC_API_VERSION 0x00020400
/** \brief Indicate at runtime which hwloc API version was used at build time. /** \brief Indicate at runtime which hwloc API version was used at build time.
* *
@ -102,7 +102,7 @@ extern "C" {
HWLOC_DECLSPEC unsigned hwloc_get_api_version(void); HWLOC_DECLSPEC unsigned hwloc_get_api_version(void);
/** \brief Current component and plugin ABI version (see hwloc/plugins.h) */ /** \brief Current component and plugin ABI version (see hwloc/plugins.h) */
#define HWLOC_COMPONENT_ABI 6 #define HWLOC_COMPONENT_ABI 7
/** @} */ /** @} */
@ -196,7 +196,7 @@ typedef enum {
*/ */
HWLOC_OBJ_CORE, /**< \brief Core. HWLOC_OBJ_CORE, /**< \brief Core.
* A computation unit (may be shared by several * A computation unit (may be shared by several
* logical processors). * PUs, aka logical processors).
*/ */
HWLOC_OBJ_PU, /**< \brief Processing Unit, or (Logical) Processor. HWLOC_OBJ_PU, /**< \brief Processing Unit, or (Logical) Processor.
* An execution unit (may share a core with some * An execution unit (may share a core with some
@ -257,22 +257,31 @@ typedef enum {
HWLOC_OBJ_BRIDGE, /**< \brief Bridge (filtered out by default). HWLOC_OBJ_BRIDGE, /**< \brief Bridge (filtered out by default).
* Any bridge (or PCI switch) that connects the host or an I/O bus, * Any bridge (or PCI switch) that connects the host or an I/O bus,
* to another I/O bus. * to another I/O bus.
* They are not added to the topology unless I/O discovery *
* is enabled with hwloc_topology_set_flags(). * 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, * I/O objects are not listed in the main children list,
* but rather in the dedicated io children list. * but rather in the dedicated io children list.
* I/O objects have NULL CPU and node sets. * I/O objects have NULL CPU and node sets.
*/ */
HWLOC_OBJ_PCI_DEVICE, /**< \brief PCI device (filtered out by default). HWLOC_OBJ_PCI_DEVICE, /**< \brief PCI device (filtered out by default).
* They are not added to the topology unless I/O discovery *
* is enabled with hwloc_topology_set_flags(). * 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, * I/O objects are not listed in the main children list,
* but rather in the dedicated io children list. * but rather in the dedicated io children list.
* I/O objects have NULL CPU and node sets. * I/O objects have NULL CPU and node sets.
*/ */
HWLOC_OBJ_OS_DEVICE, /**< \brief Operating system device (filtered out by default). HWLOC_OBJ_OS_DEVICE, /**< \brief Operating system device (filtered out by default).
* They are not added to the topology unless I/O discovery *
* is enabled with hwloc_topology_set_flags(). * 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, * I/O objects are not listed in the main children list,
* but rather in the dedicated io children list. * but rather in the dedicated io children list.
* I/O objects have NULL CPU and node sets. * I/O objects have NULL CPU and node sets.
@ -282,6 +291,10 @@ typedef enum {
* Objects without particular meaning, that can e.g. be * Objects without particular meaning, that can e.g. be
* added by the application for its own use, or by hwloc * added by the application for its own use, or by hwloc
* for miscellaneous objects such as MemoryModule (DIMMs). * 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, * These objects are not listed in the main children list,
* but rather in the dedicated misc children list. * but rather in the dedicated misc children list.
* Misc objects may only have Misc objects as children, * Misc objects may only have Misc objects as children,
@ -304,7 +317,6 @@ typedef enum {
HWLOC_OBJ_DIE, /**< \brief Die within a physical package. HWLOC_OBJ_DIE, /**< \brief Die within a physical package.
* A subpart of the physical package, that contains multiple cores. * A subpart of the physical package, that contains multiple cores.
* \hideinitializer
*/ */
HWLOC_OBJ_TYPE_MAX /**< \private Sentinel value */ HWLOC_OBJ_TYPE_MAX /**< \private Sentinel value */
@ -338,8 +350,7 @@ typedef enum hwloc_obj_osdev_type_e {
HWLOC_OBJ_OSDEV_DMA, /**< \brief Operating system dma engine device. HWLOC_OBJ_OSDEV_DMA, /**< \brief Operating system dma engine device.
* For instance the "dma0chan0" DMA channel on Linux. */ * For instance the "dma0chan0" DMA channel on Linux. */
HWLOC_OBJ_OSDEV_COPROC /**< \brief Operating system co-processor device. HWLOC_OBJ_OSDEV_COPROC /**< \brief Operating system co-processor device.
* For instance "mic0" for a Xeon Phi (MIC) on Linux, * For instance "opencl0d0" for a OpenCL device,
* "opencl0d0" for a OpenCL device,
* "cuda0" for a CUDA device. */ * "cuda0" for a CUDA device. */
} hwloc_obj_osdev_type_t; } hwloc_obj_osdev_type_t;
@ -512,7 +523,7 @@ struct hwloc_obj {
* *
* \note Its value must not be changed, hwloc_bitmap_dup() must be used instead. * \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 logical processors of this object, 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 * 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 * which topology information is unknown or incomplete, some offlines CPUs, and
@ -533,6 +544,8 @@ struct hwloc_obj {
* between this object and the NUMA node objects). * between this object and the NUMA node objects).
* *
* In the end, these nodes are those that are close to the current object. * 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, * If the ::HWLOC_TOPOLOGY_FLAG_INCLUDE_DISALLOWED configuration flag is set,
* some of these nodes may not be allowed for allocation, * some of these nodes may not be allowed for allocation,
@ -1929,7 +1942,31 @@ enum hwloc_topology_flags_e {
* would result in the same behavior. * would result in the same behavior.
* \hideinitializer * \hideinitializer
*/ */
HWLOC_TOPOLOGY_FLAG_THISSYSTEM_ALLOWED_RESOURCES = (1UL<<2) 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 Set OR'ed flags to non-yet-loaded topology. /** \brief Set OR'ed flags to non-yet-loaded topology.
@ -1972,6 +2009,8 @@ struct hwloc_topology_discovery_support {
unsigned char disallowed_pu; unsigned char disallowed_pu;
/** \brief Detecting and identifying NUMA nodes that are not available to the current process is supported. */ /** \brief Detecting and identifying NUMA nodes that are not available to the current process is supported. */
unsigned char disallowed_numa; 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. /** \brief Flags describing actual PU binding support for this topology.
@ -2042,6 +2081,13 @@ struct hwloc_topology_membind_support {
unsigned char get_area_memlocation; unsigned char get_area_memlocation;
}; };
/** \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. /** \brief Set of flags describing actual support for this topology.
* *
* This is retrieved with hwloc_topology_get_support() and will be valid until * This is retrieved with hwloc_topology_get_support() and will be valid until
@ -2052,6 +2098,7 @@ struct hwloc_topology_support {
struct hwloc_topology_discovery_support *discovery; struct hwloc_topology_discovery_support *discovery;
struct hwloc_topology_cpubind_support *cpubind; struct hwloc_topology_cpubind_support *cpubind;
struct hwloc_topology_membind_support *membind; struct hwloc_topology_membind_support *membind;
struct hwloc_topology_misc_support *misc;
}; };
/** \brief Retrieve the topology support. /** \brief Retrieve the topology support.
@ -2062,6 +2109,18 @@ struct hwloc_topology_support {
* call may still fail in some corner cases. * call may still fail in some corner cases.
* *
* These features are also listed by hwloc-info \--support * 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.
*/ */
HWLOC_DECLSPEC const struct hwloc_topology_support *hwloc_topology_get_support(hwloc_topology_t __hwloc_restrict topology); HWLOC_DECLSPEC const struct hwloc_topology_support *hwloc_topology_get_support(hwloc_topology_t __hwloc_restrict topology);
@ -2108,8 +2167,8 @@ enum hwloc_type_filter_e {
* *
* It is only useful for I/O object types. * It is only useful for I/O object types.
* For ::HWLOC_OBJ_PCI_DEVICE and ::HWLOC_OBJ_OS_DEVICE, it means that only objects * For ::HWLOC_OBJ_PCI_DEVICE and ::HWLOC_OBJ_OS_DEVICE, it means that only objects
* of major/common kinds are kept (storage, network, OpenFabrics, Intel MICs, CUDA, * of major/common kinds are kept (storage, network, OpenFabrics, CUDA,
* OpenCL, NVML, and displays). * OpenCL, RSMI, NVML, and displays).
* Also, only OS devices directly attached on PCI (e.g. no USB) are reported. * 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. * For ::HWLOC_OBJ_BRIDGE, it means that bridges are kept only if they have children.
* *
@ -2371,6 +2430,22 @@ HWLOC_DECLSPEC hwloc_obj_t hwloc_topology_insert_group_object(hwloc_topology_t t
*/ */
HWLOC_DECLSPEC int hwloc_obj_add_other_obj_sets(hwloc_obj_t dst, hwloc_obj_t src); 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
*/
HWLOC_DECLSPEC int hwloc_topology_refresh(hwloc_topology_t topology);
/** @} */ /** @} */
@ -2386,6 +2461,12 @@ HWLOC_DECLSPEC int hwloc_obj_add_other_obj_sets(hwloc_obj_t dst, hwloc_obj_t src
/* inline code of some functions above */ /* inline code of some functions above */
#include "hwloc/inlines.h" #include "hwloc/inlines.h"
/* memory attributes */
#include "hwloc/memattrs.h"
/* kinds of CPU cores */
#include "hwloc/cpukinds.h"
/* exporting to XML or synthetic */ /* exporting to XML or synthetic */
#include "hwloc/export.h" #include "hwloc/export.h"

View file

@ -1,6 +1,6 @@
/* /*
* Copyright © 2009 CNRS * Copyright © 2009 CNRS
* Copyright © 2009-2019 Inria. All rights reserved. * Copyright © 2009-2020 Inria. All rights reserved.
* Copyright © 2009-2012 Université Bordeaux * Copyright © 2009-2012 Université Bordeaux
* Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved. * Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved.
* See COPYING in top-level directory. * See COPYING in top-level directory.
@ -11,9 +11,9 @@
#ifndef HWLOC_CONFIG_H #ifndef HWLOC_CONFIG_H
#define HWLOC_CONFIG_H #define HWLOC_CONFIG_H
#define HWLOC_VERSION "2.2.0" #define HWLOC_VERSION "2.4.0"
#define HWLOC_VERSION_MAJOR 2 #define HWLOC_VERSION_MAJOR 2
#define HWLOC_VERSION_MINOR 2 #define HWLOC_VERSION_MINOR 4
#define HWLOC_VERSION_RELEASE 0 #define HWLOC_VERSION_RELEASE 0
#define HWLOC_VERSION_GREEK "" #define HWLOC_VERSION_GREEK ""

View file

@ -1,6 +1,6 @@
/* /*
* Copyright © 2009 CNRS * Copyright © 2009 CNRS
* Copyright © 2009-2018 Inria. All rights reserved. * Copyright © 2009-2020 Inria. All rights reserved.
* Copyright © 2009-2012 Université Bordeaux * Copyright © 2009-2012 Université Bordeaux
* Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved. * Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved.
* See COPYING in top-level directory. * See COPYING in top-level directory.
@ -231,7 +231,7 @@ HWLOC_DECLSPEC int hwloc_bitmap_clr_range(hwloc_bitmap_t bitmap, unsigned begin,
/** \brief Keep a single index among those set in bitmap \p bitmap /** \brief Keep a single index among those set in bitmap \p bitmap
* *
* May be useful before binding so that the process does not * May be useful before binding so that the process does not
* have a chance of migrating between multiple logical CPUs * have a chance of migrating between multiple processors
* in the original mask. * in the original mask.
* Instead of running the task on any PU inside the given CPU set, * 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 * the operating system scheduler will be forced to run it on a single

View file

@ -0,0 +1,188 @@
/*
* Copyright © 2020 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 intrinsic greater performance
* (and possibly less performance/power efficiency).
* Kinds with lower efficiency are ranked first:
* Passing 0 as \p kind_index to hwloc_cpukinds_get_info() will
* return information about the less efficient CPU kind.
*
* When available, efficiency values are gathered from the operating
* system (when \p cpukind_efficiency is set in the
* struct hwloc_topology_discovery_support array, only on Windows 10 for now).
* Otherwise 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.
*
* 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 */

View file

@ -1,5 +1,5 @@
/* /*
* Copyright © 2010-2017 Inria. All rights reserved. * Copyright © 2010-2020 Inria. All rights reserved.
* Copyright © 2010-2011 Université Bordeaux * Copyright © 2010-2011 Université Bordeaux
* Copyright © 2011 Cisco Systems, Inc. All rights reserved. * Copyright © 2011 Cisco Systems, Inc. All rights reserved.
* See COPYING in top-level directory. * See COPYING in top-level directory.
@ -72,7 +72,7 @@ hwloc_cuda_get_device_pci_ids(hwloc_topology_t topology __hwloc_attribute_unused
return 0; return 0;
} }
/** \brief Get the CPU set of logical processors that are physically /** \brief Get the CPU set of processors that are physically
* close to device \p cudevice. * close to device \p cudevice.
* *
* Return the CPU set describing the locality of the CUDA device \p cudevice. * Return the CPU set describing the locality of the CUDA device \p cudevice.

View file

@ -1,5 +1,5 @@
/* /*
* Copyright © 2010-2017 Inria. All rights reserved. * Copyright © 2010-2020 Inria. All rights reserved.
* Copyright © 2010-2011 Université Bordeaux * Copyright © 2010-2011 Université Bordeaux
* Copyright © 2011 Cisco Systems, Inc. All rights reserved. * Copyright © 2011 Cisco Systems, Inc. All rights reserved.
* See COPYING in top-level directory. * See COPYING in top-level directory.
@ -69,7 +69,7 @@ hwloc_cudart_get_device_pci_ids(hwloc_topology_t topology __hwloc_attribute_unus
return 0; return 0;
} }
/** \brief Get the CPU set of logical processors that are physically /** \brief Get the CPU set of processors that are physically
* close to device \p idx. * close to device \p idx.
* *
* Return the CPU set describing the locality of the CUDA device * Return the CPU set describing the locality of the CUDA device

View file

@ -1,5 +1,5 @@
/* /*
* Copyright © 2013-2018 Inria. All rights reserved. * Copyright © 2013-2020 Inria. All rights reserved.
* See COPYING in top-level directory. * See COPYING in top-level directory.
*/ */
@ -110,7 +110,7 @@ union hwloc_topology_diff_obj_attr_u {
*/ */
typedef enum hwloc_topology_diff_type_e { typedef enum hwloc_topology_diff_type_e {
/** \brief An object attribute was changed. /** \brief An object attribute was changed.
* The union is a hwloc_topology_diff_obj_attr_u::hwloc_topology_diff_obj_attr_s. * The union is a hwloc_topology_diff_u::hwloc_topology_diff_obj_attr_s.
*/ */
HWLOC_TOPOLOGY_DIFF_OBJ_ATTR, HWLOC_TOPOLOGY_DIFF_OBJ_ATTR,
@ -119,7 +119,7 @@ typedef enum hwloc_topology_diff_type_e {
* this object has not been checked. * this object has not been checked.
* hwloc_topology_diff_build() will return 1. * hwloc_topology_diff_build() will return 1.
* *
* The union is a hwloc_topology_diff_obj_attr_u::hwloc_topology_diff_too_complex_s. * The union is a hwloc_topology_diff_u::hwloc_topology_diff_too_complex_s.
*/ */
HWLOC_TOPOLOGY_DIFF_TOO_COMPLEX HWLOC_TOPOLOGY_DIFF_TOO_COMPLEX
} hwloc_topology_diff_type_t; } hwloc_topology_diff_type_t;

View file

@ -1,5 +1,5 @@
/* /*
* Copyright © 2010-2019 Inria. All rights reserved. * Copyright © 2010-2020 Inria. All rights reserved.
* See COPYING in top-level directory. * See COPYING in top-level directory.
*/ */
@ -34,6 +34,7 @@ extern "C" {
* It corresponds to the latency for accessing the memory of one node * It corresponds to the latency for accessing the memory of one node
* from a core in another node. * from a core in another node.
* The corresponding kind is ::HWLOC_DISTANCES_KIND_FROM_OS | ::HWLOC_DISTANCES_KIND_FROM_USER. * The corresponding kind is ::HWLOC_DISTANCES_KIND_FROM_OS | ::HWLOC_DISTANCES_KIND_FROM_USER.
* The name of this distances structure is "NUMALatency".
* *
* The matrix may also contain bandwidths between random sets of objects, * The matrix may also contain bandwidths between random sets of objects,
* possibly provided by the user, as specified in the \p kind attribute. * possibly provided by the user, as specified in the \p kind attribute.
@ -144,6 +145,8 @@ hwloc_distances_get_by_type(hwloc_topology_t topology, hwloc_obj_type_t type,
/** \brief Retrieve a distance matrix with the given name. /** \brief Retrieve a distance matrix with the given name.
* *
* Usually only one distances structure may match a given name. * Usually only one distances structure may match a given name.
*
* The name of the most common structure is "NUMALatency".
*/ */
HWLOC_DECLSPEC int HWLOC_DECLSPEC int
hwloc_distances_get_by_name(hwloc_topology_t topology, const char *name, hwloc_distances_get_by_name(hwloc_topology_t topology, const char *name,

View file

@ -1,6 +1,6 @@
/* /*
* Copyright © 2009 CNRS * Copyright © 2009 CNRS
* Copyright © 2009-2013 inria. All rights reserved. * Copyright © 2009-2020 Inria. All rights reserved.
* Copyright © 2009-2011 Université Bordeaux * Copyright © 2009-2011 Université Bordeaux
* Copyright © 2011 Cisco Systems, Inc. All rights reserved. * Copyright © 2011 Cisco Systems, Inc. All rights reserved.
* See COPYING in top-level directory. * See COPYING in top-level directory.
@ -22,7 +22,7 @@
#include <assert.h> #include <assert.h>
#if !defined _GNU_SOURCE || !defined _SCHED_H || (!defined CPU_SETSIZE && !defined sched_priority) #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 #error Please make sure to include sched.h before including glibc-sched.h, and define _GNU_SOURCE before any inclusion of sched.h
#endif #endif

View file

@ -872,8 +872,8 @@ hwloc_distrib(hwloc_topology_t topology,
unsigned chunk, weight; unsigned chunk, weight;
hwloc_obj_t root = roots[flags & HWLOC_DISTRIB_FLAG_REVERSE ? n_roots-1-i : i]; hwloc_obj_t root = roots[flags & HWLOC_DISTRIB_FLAG_REVERSE ? n_roots-1-i : i];
hwloc_cpuset_t cpuset = root->cpuset; hwloc_cpuset_t cpuset = root->cpuset;
if (root->type == HWLOC_OBJ_NUMANODE) while (!hwloc_obj_type_is_normal(root->type))
/* NUMANodes have same cpuset as their parent, but we need normal objects below */ /* If memory/io/misc, walk up to normal parent */
root = root->parent; root = root->parent;
weight = (unsigned) hwloc_bitmap_weight(cpuset); weight = (unsigned) hwloc_bitmap_weight(cpuset);
if (!weight) if (!weight)
@ -919,7 +919,7 @@ hwloc_distrib(hwloc_topology_t topology,
/** \brief Get complete CPU set /** \brief Get complete CPU set
* *
* \return the complete CPU set of logical processors of the system. * \return the complete CPU set of processors of the system.
* *
* \note The returned cpuset is not newly allocated and should thus not be * \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. * changed or freed; hwloc_bitmap_dup() must be used to obtain a local copy.
@ -931,7 +931,7 @@ hwloc_topology_get_complete_cpuset(hwloc_topology_t topology) __hwloc_attribute_
/** \brief Get topology CPU set /** \brief Get topology CPU set
* *
* \return the CPU set of logical processors of the system for which hwloc * \return the CPU set of processors of the system for which hwloc
* provides topology information. This is equivalent to the cpuset of the * provides topology information. This is equivalent to the cpuset of the
* system object. * system object.
* *
@ -945,7 +945,7 @@ hwloc_topology_get_topology_cpuset(hwloc_topology_t topology) __hwloc_attribute_
/** \brief Get allowed CPU set /** \brief Get allowed CPU set
* *
* \return the CPU set of allowed logical processors of the system. * \return the CPU set of allowed processors of the system.
* *
* \note If the topology flag ::HWLOC_TOPOLOGY_FLAG_INCLUDE_DISALLOWED was not set, * \note If the topology flag ::HWLOC_TOPOLOGY_FLAG_INCLUDE_DISALLOWED was not set,
* this is identical to hwloc_topology_get_topology_cpuset(), which means * this is identical to hwloc_topology_get_topology_cpuset(), which means

View file

@ -0,0 +1,455 @@
/*
* Copyright © 2019-2020 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.
*
* \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 Memory node attributes. */
enum hwloc_memattr_id_e {
/** \brief "Capacity".
* The capacity is returned in bytes
* (local_memory attribute in objects).
*
* Best capacity nodes are nodes with <b>higher capacity</b>.
*
* No initiator is involved when looking at this attribute.
* The corresponding attribute flags are ::HWLOC_MEMATTR_FLAG_HIGHER_FIRST.
*/
HWLOC_MEMATTR_ID_CAPACITY = 0,
/** \brief "Locality".
* 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 <b>smaller locality</b>
* (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.
*/
HWLOC_MEMATTR_ID_LOCALITY = 1,
/** \brief "Bandwidth".
* The bandwidth is returned in MiB/s, as seen from the given initiator location.
* Best bandwidth nodes are nodes with <b>higher bandwidth</b>.
* The corresponding attribute flags are ::HWLOC_MEMATTR_FLAG_HIGHER_FIRST
* and ::HWLOC_MEMATTR_FLAG_NEED_INITIATOR.
*/
HWLOC_MEMATTR_ID_BANDWIDTH = 2,
/** \brief "Latency".
* The latency is returned as nanoseconds, as seen from the given initiator location.
* Best latency nodes are nodes with <b>smaller latency</b>.
* The corresponding attribute flags are ::HWLOC_MEMATTR_FLAG_LOWER_FIRST
* and ::HWLOC_MEMATTR_FLAG_NEED_INITIATOR.
*/
HWLOC_MEMATTR_ID_LATENCY = 3
/* TODO read vs write, persistence? */
};
/** \brief A memory attribute identifier.
* May be either one of ::hwloc_memattr_id_e or a new id returned by hwloc_memattr_register().
*/
typedef unsigned hwloc_memattr_id_t;
/** \brief Return the identifier of the memory attribute with the given name.
*/
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 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.
*
* \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 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 flags must be \c 0 for now.
*
* \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.
*
* If there are no matching targets, \c -1 is returned with \p errno set to \c ENOENT;
*
* \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 the attribute does not relate to a specific initiator
* (it does not have the flag ::HWLOC_MEMATTR_FLAG_NEED_INITIATOR),
* \c -1 is returned and \p errno is set to \c EINVAL.
*
* 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 flags must be \c 0 for now.
*
* If there are no matching initiators, \c -1 is returned with \p errno set to \c ENOENT;
*/
HWLOC_DECLSPEC int
hwloc_memattr_get_best_initiator(hwloc_topology_t topology,
hwloc_memattr_id_t attribute,
hwloc_obj_t target,
unsigned long flags,
struct hwloc_location *best_initiator, hwloc_uint64_t *value);
/** @} */
/** \defgroup hwlocality_memattrs_manage Managing memory attributes
* @{
*/
/** \brief Return the name of a memory attribute.
*/
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.
*/
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 specific memory attribute that is not defined in ::hwloc_memattr_id_e.
* Flags are a OR'ed set of ::hwloc_memattr_flag_e. It must contain at least
* one of ::HWLOC_MEMATTR_FLAG_HIGHER_FIRST or ::HWLOC_MEMATTR_FLAG_LOWER_FIRST.
*/
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 flags must be \c 0 for now.
*
* \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_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);
/** \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.
*
* \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_targets(hwloc_topology_t topology,
hwloc_memattr_id_t attribute,
struct hwloc_location *initiator,
unsigned long flags,
unsigned *nrp, 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 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.
*
* \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);
/** @} */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* HWLOC_MEMATTR_H */

View file

@ -1,5 +1,5 @@
/* /*
* Copyright © 2012-2016 Inria. All rights reserved. * Copyright © 2012-2020 Inria. All rights reserved.
* See COPYING in top-level directory. * See COPYING in top-level directory.
*/ */
@ -36,7 +36,7 @@ extern "C" {
* @{ * @{
*/ */
/** \brief Get the CPU set of logical processors that are physically /** \brief Get the CPU set of processors that are physically
* close to NVML device \p device. * close to NVML device \p device.
* *
* Return the CPU set describing the locality of the NVML device \p device. * Return the CPU set describing the locality of the NVML device \p device.

View file

@ -1,5 +1,5 @@
/* /*
* Copyright © 2012-2019 Inria. All rights reserved. * Copyright © 2012-2020 Inria. All rights reserved.
* Copyright © 2013, 2018 Université Bordeaux. All right reserved. * Copyright © 2013, 2018 Université Bordeaux. All right reserved.
* See COPYING in top-level directory. * See COPYING in top-level directory.
*/ */
@ -109,7 +109,7 @@ hwloc_opencl_get_device_pci_busid(cl_device_id device,
return -1; return -1;
} }
/** \brief Get the CPU set of logical processors that are physically /** \brief Get the CPU set of processors that are physically
* close to OpenCL device \p device. * close to OpenCL device \p device.
* *
* Return the CPU set describing the locality of the OpenCL device \p device. * Return the CPU set describing the locality of the OpenCL device \p device.

View file

@ -1,6 +1,6 @@
/* /*
* Copyright © 2009 CNRS * Copyright © 2009 CNRS
* Copyright © 2009-2016 Inria. All rights reserved. * Copyright © 2009-2020 Inria. All rights reserved.
* Copyright © 2009-2010 Université Bordeaux * Copyright © 2009-2010 Université Bordeaux
* Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved. * Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved.
* See COPYING in top-level directory. * See COPYING in top-level directory.
@ -41,7 +41,7 @@ extern "C" {
* @{ * @{
*/ */
/** \brief Get the CPU set of logical processors that are physically /** \brief Get the CPU set of processors that are physically
* close to device \p ibdev. * close to device \p ibdev.
* *
* Return the CPU set describing the locality of the OpenFabrics * Return the CPU set describing the locality of the OpenFabrics

View file

@ -313,7 +313,13 @@ struct hwloc_component {
* @{ * @{
*/ */
/** \brief Check whether insertion errors are hidden */
HWLOC_DECLSPEC int hwloc_hide_errors(void);
/** \brief Add an object to the topology. /** \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 * 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 * cpusets, to eventually be added as a child of the smallest object including
@ -327,32 +333,20 @@ struct hwloc_component {
* *
* This shall only be called before levels are built. * This shall only be called before levels are built.
* *
* In case of error, hwloc_report_os_error() is called.
*
* The caller should check whether the object type is filtered-out before calling this function. * 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. * 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 the object on success.
* Returns NULL and frees obj on error. * Returns NULL and frees obj on error.
* Returns another object and frees obj if it was merged with an identical pre-existing object. * Returns another object and frees obj if it was merged with an identical pre-existing object.
*/ */
HWLOC_DECLSPEC struct hwloc_obj *hwloc_insert_object_by_cpuset(struct hwloc_topology *topology, hwloc_obj_t obj); HWLOC_DECLSPEC hwloc_obj_t
hwloc__insert_object_by_cpuset(struct hwloc_topology *topology, hwloc_obj_t root,
/** \brief Type of error callbacks during object insertion */ hwloc_obj_t obj, const char *reason);
typedef void (*hwloc_report_error_t)(const char * msg, int line);
/** \brief Report an insertion error from a backend */
HWLOC_DECLSPEC void hwloc_report_os_error(const char * msg, int line);
/** \brief Check whether insertion errors are hidden */
HWLOC_DECLSPEC int hwloc_hide_errors(void);
/** \brief Add an object to the topology and specify which error callback to use.
*
* This function is similar to hwloc_insert_object_by_cpuset() but it allows specifying
* where to start insertion from (if \p root is NULL, the topology root object is used),
* and specifying the error callback.
*/
HWLOC_DECLSPEC struct hwloc_obj *hwloc__insert_object_by_cpuset(struct hwloc_topology *topology, hwloc_obj_t root, hwloc_obj_t obj, hwloc_report_error_t report_error);
/** \brief Insert an object somewhere in the topology. /** \brief Insert an object somewhere in the topology.
* *

View file

@ -1,6 +1,6 @@
/* /*
* Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved. * Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved.
* Copyright © 2010-2019 Inria. All rights reserved. * Copyright © 2010-2020 Inria. All rights reserved.
* See COPYING in top-level directory. * See COPYING in top-level directory.
*/ */
@ -119,6 +119,7 @@ extern "C" {
#define HWLOC_TOPOLOGY_FLAG_INCLUDE_DISALLOWED HWLOC_NAME_CAPS(TOPOLOGY_FLAG_WITH_DISALLOWED) #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_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_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_set_pid HWLOC_NAME(topology_set_pid) #define hwloc_topology_set_pid HWLOC_NAME(topology_set_pid)
#define hwloc_topology_set_synthetic HWLOC_NAME(topology_set_synthetic) #define hwloc_topology_set_synthetic HWLOC_NAME(topology_set_synthetic)
@ -134,6 +135,7 @@ extern "C" {
#define hwloc_topology_discovery_support HWLOC_NAME(topology_discovery_support) #define hwloc_topology_discovery_support HWLOC_NAME(topology_discovery_support)
#define hwloc_topology_cpubind_support HWLOC_NAME(topology_cpubind_support) #define hwloc_topology_cpubind_support HWLOC_NAME(topology_cpubind_support)
#define hwloc_topology_membind_support HWLOC_NAME(topology_membind_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_support HWLOC_NAME(topology_support)
#define hwloc_topology_get_support HWLOC_NAME(topology_get_support) #define hwloc_topology_get_support HWLOC_NAME(topology_get_support)
@ -170,6 +172,7 @@ extern "C" {
#define hwloc_topology_alloc_group_object HWLOC_NAME(topology_alloc_group_object) #define hwloc_topology_alloc_group_object HWLOC_NAME(topology_alloc_group_object)
#define hwloc_topology_insert_group_object HWLOC_NAME(topology_insert_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_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_topology_get_depth HWLOC_NAME(topology_get_depth)
#define hwloc_get_type_depth HWLOC_NAME(get_type_depth) #define hwloc_get_type_depth HWLOC_NAME(get_type_depth)
@ -367,6 +370,51 @@ extern "C" {
#define hwloc_cpuset_to_nodeset HWLOC_NAME(cpuset_to_nodeset) #define hwloc_cpuset_to_nodeset HWLOC_NAME(cpuset_to_nodeset)
#define hwloc_cpuset_from_nodeset HWLOC_NAME(cpuset_from_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_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_ALL HWLOC_NAME_CAPS(LOCAL_NUMANODE_FLAG_ALL)
#define hwloc_get_local_numanode_objs HWLOC_NAME(get_local_numanode_objs)
#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 */ /* export.h */
#define hwloc_topology_export_xml_flags_e HWLOC_NAME(topology_export_xml_flags_e) #define hwloc_topology_export_xml_flags_e HWLOC_NAME(topology_export_xml_flags_e)
@ -510,6 +558,12 @@ extern "C" {
#define hwloc_nvml_get_device_osdev HWLOC_NAME(nvml_get_device_osdev) #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) #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)
/* gl.h */ /* 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_port_device HWLOC_NAME(gl_get_display_osdev_by_port_device)
@ -547,9 +601,6 @@ extern "C" {
#define hwloc_plugin_check_namespace HWLOC_NAME(plugin_check_namespace) #define hwloc_plugin_check_namespace HWLOC_NAME(plugin_check_namespace)
#define hwloc_insert_object_by_cpuset HWLOC_NAME(insert_object_by_cpuset)
#define hwloc_report_error_t HWLOC_NAME(report_error_t)
#define hwloc_report_os_error HWLOC_NAME(report_os_error)
#define hwloc_hide_errors HWLOC_NAME(hide_errors) #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_cpuset HWLOC_NAME(_insert_object_by_cpuset)
#define hwloc_insert_object_by_parent HWLOC_NAME(insert_object_by_parent) #define hwloc_insert_object_by_parent HWLOC_NAME(insert_object_by_parent)
@ -683,6 +734,7 @@ extern "C" {
#define hwloc_cuda_component HWLOC_NAME(cuda_component) #define hwloc_cuda_component HWLOC_NAME(cuda_component)
#define hwloc_gl_component HWLOC_NAME(gl_component) #define hwloc_gl_component HWLOC_NAME(gl_component)
#define hwloc_nvml_component HWLOC_NAME(nvml_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_opencl_component HWLOC_NAME(opencl_component)
#define hwloc_pci_component HWLOC_NAME(pci_component) #define hwloc_pci_component HWLOC_NAME(pci_component)
@ -691,6 +743,8 @@ extern "C" {
/* private/private.h */ /* 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_special_level_s HWLOC_NAME(special_level_s)
#define hwloc_pci_forced_locality_s HWLOC_NAME(pci_forced_locality_s) #define hwloc_pci_forced_locality_s HWLOC_NAME(pci_forced_locality_s)
@ -713,6 +767,8 @@ extern "C" {
#define hwloc__attach_memory_object HWLOC_NAME(insert_memory_object) #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_init HWLOC_NAME(pci_discovery_init)
#define hwloc_pci_discovery_prepare HWLOC_NAME(pci_discovery_prepare) #define hwloc_pci_discovery_prepare HWLOC_NAME(pci_discovery_prepare)
#define hwloc_pci_discovery_exit HWLOC_NAME(pci_discovery_exit) #define hwloc_pci_discovery_exit HWLOC_NAME(pci_discovery_exit)
@ -723,6 +779,7 @@ extern "C" {
#define hwloc__add_info_nodup HWLOC_NAME(_add_info_nodup) #define hwloc__add_info_nodup HWLOC_NAME(_add_info_nodup)
#define hwloc__move_infos HWLOC_NAME(_move_infos) #define hwloc__move_infos HWLOC_NAME(_move_infos)
#define hwloc__free_infos HWLOC_NAME(_free_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_binding_hooks HWLOC_NAME(binding_hooks)
#define hwloc_set_native_binding_hooks HWLOC_NAME(set_native_binding_hooks) #define hwloc_set_native_binding_hooks HWLOC_NAME(set_native_binding_hooks)
@ -764,6 +821,24 @@ extern "C" {
#define hwloc_internal_distances_add_by_index HWLOC_NAME(internal_distances_add_by_index) #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_distances_invalidate_cached_objs HWLOC_NAME(hwloc_internal_distances_invalidate_cached_objs)
#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_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_encode_to_base64 HWLOC_NAME(encode_to_base64)
#define hwloc_decode_from_base64 HWLOC_NAME(decode_from_base64) #define hwloc_decode_from_base64 HWLOC_NAME(decode_from_base64)

View file

@ -1,8 +1,8 @@
/* /*
* Copyright © 2009, 2011, 2012 CNRS. All rights reserved. * Copyright © 2009, 2011, 2012 CNRS. All rights reserved.
* Copyright © 2009-2018 Inria. All rights reserved. * Copyright © 2009-2020 Inria. All rights reserved.
* Copyright © 2009, 2011, 2012, 2015 Université Bordeaux. All rights reserved. * Copyright © 2009, 2011, 2012, 2015 Université Bordeaux. All rights reserved.
* Copyright © 2009 Cisco Systems, Inc. All rights reserved. * Copyright © 2009-2020 Cisco Systems, Inc. All rights reserved.
* $COPYRIGHT$ * $COPYRIGHT$
* *
* Additional copyrights may follow * Additional copyrights may follow
@ -575,7 +575,7 @@
#define PACKAGE "hwloc" #define PACKAGE "hwloc"
/* Define to the address where bug reports for this package should be sent. */ /* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT "http://www.open-mpi.org/projects/hwloc/" #define PACKAGE_BUGREPORT "https://www.open-mpi.org/projects/hwloc/"
/* Define to the full name of this package. */ /* Define to the full name of this package. */
#define PACKAGE_NAME "hwloc" #define PACKAGE_NAME "hwloc"
@ -668,5 +668,9 @@
/* Define this to the thread ID type */ /* Define this to the thread ID type */
#define hwloc_thread_t HANDLE #define hwloc_thread_t HANDLE
/* Define to 1 if you have the declaration of `GetModuleFileName', and to 0 if
you don't. */
#define HAVE_DECL_GETMODULEFILENAME 1
#endif /* HWLOC_CONFIGURE_H */ #endif /* HWLOC_CONFIGURE_H */

View file

@ -1,6 +1,6 @@
/* /*
* Copyright © 2009 CNRS * Copyright © 2009 CNRS
* Copyright © 2009-2017 Inria. All rights reserved. * Copyright © 2009-2020 Inria. All rights reserved.
* Copyright © 2009, 2011 Université Bordeaux * Copyright © 2009, 2011 Université Bordeaux
* Copyright © 2011 Cisco Systems, Inc. All rights reserved. * Copyright © 2011 Cisco Systems, Inc. All rights reserved.
* See COPYING in top-level directory. * See COPYING in top-level directory.
@ -19,6 +19,10 @@
#include <stdio.h> #include <stdio.h>
#endif #endif
#ifdef ANDROID
extern void JNIDebug(char *text);
#endif
/* Compile-time assertion */ /* Compile-time assertion */
#define HWLOC_BUILD_ASSERT(condition) ((void)sizeof(char[1 - 2*!(condition)])) #define HWLOC_BUILD_ASSERT(condition) ((void)sizeof(char[1 - 2*!(condition)]))
@ -44,9 +48,17 @@ static __hwloc_inline void hwloc_debug(const char *s __hwloc_attribute_unused, .
{ {
#ifdef HWLOC_DEBUG #ifdef HWLOC_DEBUG
if (hwloc_debug_enabled()) { if (hwloc_debug_enabled()) {
#ifdef ANDROID
char buffer[256];
#endif
va_list ap; va_list ap;
va_start(ap, s); va_start(ap, s);
#ifdef ANDROID
vsprintf(buffer, s, ap);
JNIDebug(buffer);
#else
vfprintf(stderr, s, ap); vfprintf(stderr, s, ap);
#endif
va_end(ap); va_end(ap);
} }
#endif #endif
@ -57,21 +69,21 @@ static __hwloc_inline void hwloc_debug(const char *s __hwloc_attribute_unused, .
if (hwloc_debug_enabled()) { \ if (hwloc_debug_enabled()) { \
char *s; \ char *s; \
hwloc_bitmap_asprintf(&s, bitmap); \ hwloc_bitmap_asprintf(&s, bitmap); \
fprintf(stderr, fmt, s); \ hwloc_debug(fmt, s); \
free(s); \ free(s); \
} } while (0) } } while (0)
#define hwloc_debug_1arg_bitmap(fmt, arg1, bitmap) do { \ #define hwloc_debug_1arg_bitmap(fmt, arg1, bitmap) do { \
if (hwloc_debug_enabled()) { \ if (hwloc_debug_enabled()) { \
char *s; \ char *s; \
hwloc_bitmap_asprintf(&s, bitmap); \ hwloc_bitmap_asprintf(&s, bitmap); \
fprintf(stderr, fmt, arg1, s); \ hwloc_debug(fmt, arg1, s); \
free(s); \ free(s); \
} } while (0) } } while (0)
#define hwloc_debug_2args_bitmap(fmt, arg1, arg2, bitmap) do { \ #define hwloc_debug_2args_bitmap(fmt, arg1, arg2, bitmap) do { \
if (hwloc_debug_enabled()) { \ if (hwloc_debug_enabled()) { \
char *s; \ char *s; \
hwloc_bitmap_asprintf(&s, bitmap); \ hwloc_bitmap_asprintf(&s, bitmap); \
fprintf(stderr, fmt, arg1, arg2, s); \ hwloc_debug(fmt, arg1, arg2, s); \
free(s); \ free(s); \
} } while (0) } } while (0)
#else #else

View file

@ -30,6 +30,7 @@ HWLOC_DECLSPEC extern const struct hwloc_component hwloc_x86_component;
HWLOC_DECLSPEC extern const struct hwloc_component hwloc_cuda_component; HWLOC_DECLSPEC extern const struct hwloc_component hwloc_cuda_component;
HWLOC_DECLSPEC extern const struct hwloc_component hwloc_gl_component; HWLOC_DECLSPEC extern const struct hwloc_component hwloc_gl_component;
HWLOC_DECLSPEC extern const struct hwloc_component hwloc_nvml_component; HWLOC_DECLSPEC extern const struct hwloc_component hwloc_nvml_component;
HWLOC_DECLSPEC extern const struct hwloc_component hwloc_rsmi_component;
HWLOC_DECLSPEC extern const struct hwloc_component hwloc_opencl_component; HWLOC_DECLSPEC extern const struct hwloc_component hwloc_opencl_component;
HWLOC_DECLSPEC extern const struct hwloc_component hwloc_pci_component; HWLOC_DECLSPEC extern const struct hwloc_component hwloc_pci_component;

View file

@ -1,6 +1,6 @@
/* /*
* Copyright © 2009 CNRS * Copyright © 2009 CNRS
* Copyright © 2009-2019 Inria. All rights reserved. * Copyright © 2009-2020 Inria. All rights reserved.
* Copyright © 2009-2012, 2020 Université Bordeaux * Copyright © 2009-2012, 2020 Université Bordeaux
* Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved. * Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved.
* *
@ -40,7 +40,19 @@
#endif #endif
#include <string.h> #include <string.h>
#define HWLOC_TOPOLOGY_ABI 0x20100 /* version of the layout of struct topology */ #define HWLOC_TOPOLOGY_ABI 0x20400 /* version of the layout of struct topology */
struct hwloc_internal_location_s {
enum hwloc_location_type_e type;
union {
struct {
hwloc_obj_t obj; /* cached between refreshes */
uint64_t gp_index;
hwloc_obj_type_t type;
} object; /* if type == HWLOC_LOCATION_TYPE_OBJECT */
hwloc_cpuset_t cpuset; /* if type == HWLOC_LOCATION_TYPE_CPUSET */
} location;
};
/***************************************************** /*****************************************************
* WARNING: * WARNING:
@ -163,6 +175,50 @@ struct hwloc_topology {
} *first_dist, *last_dist; } *first_dist, *last_dist;
unsigned next_dist_id; unsigned next_dist_id;
/* memory attributes */
unsigned nr_memattrs;
struct hwloc_internal_memattr_s {
/* memattr info */
char *name; /* TODO unit is implicit, in the documentation of standard attributes, or in the name? */
unsigned long flags;
#define HWLOC_IMATTR_FLAG_STATIC_NAME (1U<<0) /* no need to free name */
#define HWLOC_IMATTR_FLAG_CACHE_VALID (1U<<1) /* target and initiator are valid */
#define HWLOC_IMATTR_FLAG_CONVENIENCE (1U<<2) /* convenience attribute reporting values from non-memattr attributes (R/O and no actual targets stored) */
unsigned iflags;
/* array of values */
unsigned nr_targets;
struct hwloc_internal_memattr_target_s {
/* target object */
hwloc_obj_t obj; /* cached between refreshes */
hwloc_obj_type_t type;
unsigned os_index; /* only used temporarily during discovery when there's no obj/gp_index yet */
hwloc_uint64_t gp_index;
/* value if there are no initiator for this attr */
hwloc_uint64_t noinitiator_value;
/* initiators otherwise */
unsigned nr_initiators;
struct hwloc_internal_memattr_initiator_s {
struct hwloc_internal_location_s initiator;
hwloc_uint64_t value;
} *initiators;
} *targets;
} *memattrs;
/* hybridcpus */
unsigned nr_cpukinds;
unsigned nr_cpukinds_allocated;
struct hwloc_internal_cpukind_s {
hwloc_cpuset_t cpuset;
#define HWLOC_CPUKIND_EFFICIENCY_UNKNOWN -1
int efficiency;
int forced_efficiency; /* returned by the hardware or OS if any */
hwloc_uint64_t ranking_value; /* internal value for ranking */
unsigned nr_infos;
struct hwloc_info_s *infos;
} *cpukinds;
int grouping; int grouping;
int grouping_verbose; int grouping_verbose;
unsigned grouping_nbaccuracies; unsigned grouping_nbaccuracies;
@ -240,8 +296,9 @@ extern void hwloc_topology_clear(struct hwloc_topology *topology);
/* insert memory object as memory child of normal parent */ /* insert memory object as memory child of normal parent */
extern struct hwloc_obj * hwloc__attach_memory_object(struct hwloc_topology *topology, hwloc_obj_t parent, extern struct hwloc_obj * hwloc__attach_memory_object(struct hwloc_topology *topology, hwloc_obj_t parent,
hwloc_obj_t obj, hwloc_obj_t obj, const char *reason);
hwloc_report_error_t report_error);
extern hwloc_obj_t hwloc_get_obj_by_type_and_gp_index(hwloc_topology_t topology, hwloc_obj_type_t type, uint64_t gp_index);
extern void hwloc_pci_discovery_init(struct hwloc_topology *topology); extern void hwloc_pci_discovery_init(struct hwloc_topology *topology);
extern void hwloc_pci_discovery_prepare(struct hwloc_topology *topology); extern void hwloc_pci_discovery_prepare(struct hwloc_topology *topology);
@ -261,6 +318,7 @@ extern hwloc_obj_t hwloc_find_insert_io_parent_by_complete_cpuset(struct hwloc_t
extern int hwloc__add_info(struct hwloc_info_s **infosp, unsigned *countp, const char *name, const char *value); extern int hwloc__add_info(struct hwloc_info_s **infosp, unsigned *countp, const char *name, const char *value);
extern int hwloc__add_info_nodup(struct hwloc_info_s **infosp, unsigned *countp, const char *name, const char *value, int replace); extern int hwloc__add_info_nodup(struct hwloc_info_s **infosp, unsigned *countp, const char *name, const char *value, int replace);
extern int hwloc__move_infos(struct hwloc_info_s **dst_infosp, unsigned *dst_countp, struct hwloc_info_s **src_infosp, unsigned *src_countp); extern int hwloc__move_infos(struct hwloc_info_s **dst_infosp, unsigned *dst_countp, struct hwloc_info_s **src_infosp, unsigned *src_countp);
extern int hwloc__tma_dup_infos(struct hwloc_tma *tma, struct hwloc_info_s **dst_infosp, unsigned *dst_countp, struct hwloc_info_s *src_infos, unsigned src_count);
extern void hwloc__free_infos(struct hwloc_info_s *infos, unsigned count); extern void hwloc__free_infos(struct hwloc_info_s *infos, unsigned count);
/* set native OS binding hooks */ /* set native OS binding hooks */
@ -354,6 +412,22 @@ extern int hwloc_internal_distances_add(hwloc_topology_t topology, const char *n
extern int hwloc_internal_distances_add_by_index(hwloc_topology_t topology, const char *name, hwloc_obj_type_t unique_type, hwloc_obj_type_t *different_types, unsigned nbobjs, uint64_t *indexes, uint64_t *values, unsigned long kind, unsigned long flags); extern int hwloc_internal_distances_add_by_index(hwloc_topology_t topology, const char *name, hwloc_obj_type_t unique_type, hwloc_obj_type_t *different_types, unsigned nbobjs, uint64_t *indexes, uint64_t *values, unsigned long kind, unsigned long flags);
extern void hwloc_internal_distances_invalidate_cached_objs(hwloc_topology_t topology); extern void hwloc_internal_distances_invalidate_cached_objs(hwloc_topology_t topology);
extern void hwloc_internal_memattrs_init(hwloc_topology_t topology);
extern void hwloc_internal_memattrs_prepare(hwloc_topology_t topology);
extern void hwloc_internal_memattrs_destroy(hwloc_topology_t topology);
extern void hwloc_internal_memattrs_need_refresh(hwloc_topology_t topology);
extern void hwloc_internal_memattrs_refresh(hwloc_topology_t topology);
extern int hwloc_internal_memattrs_dup(hwloc_topology_t new, hwloc_topology_t old);
extern int hwloc_internal_memattr_set_value(hwloc_topology_t topology, hwloc_memattr_id_t id, hwloc_obj_type_t target_type, hwloc_uint64_t target_gp_index, unsigned target_os_index, struct hwloc_internal_location_s *initiator, hwloc_uint64_t value);
extern void hwloc_internal_cpukinds_init(hwloc_topology_t topology);
extern int hwloc_internal_cpukinds_rank(hwloc_topology_t topology);
extern void hwloc_internal_cpukinds_destroy(hwloc_topology_t topology);
extern int hwloc_internal_cpukinds_dup(hwloc_topology_t new, hwloc_topology_t old);
#define HWLOC_CPUKINDS_REGISTER_FLAG_OVERWRITE_FORCED_EFFICIENCY (1<<0)
extern int hwloc_internal_cpukinds_register(hwloc_topology_t topology, hwloc_cpuset_t cpuset, int forced_efficiency, const struct hwloc_info_s *infos, unsigned nr_infos, unsigned long flags);
extern void hwloc_internal_cpukinds_restrict(hwloc_topology_t topology);
/* encode src buffer into target buffer. /* encode src buffer into target buffer.
* targsize must be at least 4*((srclength+2)/3)+1. * targsize must be at least 4*((srclength+2)/3)+1.
* target will be 0-terminated. * target will be 0-terminated.

View file

@ -46,7 +46,7 @@ struct hwloc_xml_backend_data_s {
int (*find_child)(struct hwloc__xml_import_state_s * state, struct hwloc__xml_import_state_s * childstate, char **tagp); int (*find_child)(struct hwloc__xml_import_state_s * state, struct hwloc__xml_import_state_s * childstate, char **tagp);
int (*close_tag)(struct hwloc__xml_import_state_s * state); /* look for an explicit closing tag </name> */ int (*close_tag)(struct hwloc__xml_import_state_s * state); /* look for an explicit closing tag </name> */
void (*close_child)(struct hwloc__xml_import_state_s * state); void (*close_child)(struct hwloc__xml_import_state_s * state);
int (*get_content)(struct hwloc__xml_import_state_s * state, char **beginp, size_t expected_length); /* return 0 on empty content (and sets beginp to empty string), 1 on actual content, -1 on error or unexpected content length */ int (*get_content)(struct hwloc__xml_import_state_s * state, const char **beginp, size_t expected_length); /* return 0 on empty content (and sets beginp to empty string), 1 on actual content, -1 on error or unexpected content length */
void (*close_content)(struct hwloc__xml_import_state_s * state); void (*close_content)(struct hwloc__xml_import_state_s * state);
char * msgprefix; char * msgprefix;
void *data; /* libxml2 doc, or nolibxml buffer */ void *data; /* libxml2 doc, or nolibxml buffer */

View file

@ -1,6 +1,6 @@
/* /*
* Copyright © 2009 CNRS * Copyright © 2009 CNRS
* Copyright © 2009-2019 Inria. All rights reserved. * Copyright © 2009-2020 Inria. All rights reserved.
* Copyright © 2009-2010, 2012 Université Bordeaux * Copyright © 2009-2010, 2012 Université Bordeaux
* Copyright © 2011-2015 Cisco Systems, Inc. All rights reserved. * Copyright © 2011-2015 Cisco Systems, Inc. All rights reserved.
* See COPYING in top-level directory. * See COPYING in top-level directory.
@ -921,5 +921,6 @@ hwloc_set_binding_hooks(struct hwloc_topology *topology)
DO(mem,get_area_membind); DO(mem,get_area_membind);
DO(mem,get_area_memlocation); DO(mem,get_area_memlocation);
DO(mem,alloc_membind); DO(mem,alloc_membind);
#undef DO
} }
} }

View file

@ -1,6 +1,6 @@
/* /*
* Copyright © 2009 CNRS * Copyright © 2009 CNRS
* Copyright © 2009-2018 Inria. All rights reserved. * Copyright © 2009-2020 Inria. All rights reserved.
* Copyright © 2009-2011 Université Bordeaux * Copyright © 2009-2011 Université Bordeaux
* Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved. * Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved.
* See COPYING in top-level directory. * See COPYING in top-level directory.
@ -818,7 +818,7 @@ int hwloc_bitmap_nr_ulongs(const struct hwloc_bitmap_s *set)
return -1; return -1;
last = hwloc_bitmap_last(set); last = hwloc_bitmap_last(set);
return (last + HWLOC_BITS_PER_LONG-1)/HWLOC_BITS_PER_LONG; return (last + HWLOC_BITS_PER_LONG)/HWLOC_BITS_PER_LONG;
} }
int hwloc_bitmap_only(struct hwloc_bitmap_s * set, unsigned cpu) int hwloc_bitmap_only(struct hwloc_bitmap_s * set, unsigned cpu)

649
src/3rdparty/hwloc/src/cpukinds.c vendored Normal file
View file

@ -0,0 +1,649 @@
/*
* Copyright © 2020 Inria. All rights reserved.
* See COPYING in top-level directory.
*/
#include "private/autogen/config.h"
#include "hwloc.h"
#include "private/private.h"
#include "private/debug.h"
/*****************
* Basics
*/
void
hwloc_internal_cpukinds_init(struct hwloc_topology *topology)
{
topology->cpukinds = NULL;
topology->nr_cpukinds = 0;
topology->nr_cpukinds_allocated = 0;
}
void
hwloc_internal_cpukinds_destroy(struct hwloc_topology *topology)
{
unsigned i;
for(i=0; i<topology->nr_cpukinds; i++) {
struct hwloc_internal_cpukind_s *kind = &topology->cpukinds[i];
hwloc_bitmap_free(kind->cpuset);
hwloc__free_infos(kind->infos, kind->nr_infos);
}
free(topology->cpukinds);
topology->cpukinds = NULL;
topology->nr_cpukinds = 0;
}
int
hwloc_internal_cpukinds_dup(hwloc_topology_t new, hwloc_topology_t old)
{
struct hwloc_tma *tma = new->tma;
struct hwloc_internal_cpukind_s *kinds;
unsigned i;
kinds = hwloc_tma_malloc(tma, old->nr_cpukinds * sizeof(*kinds));
if (!kinds)
return -1;
new->cpukinds = kinds;
new->nr_cpukinds = old->nr_cpukinds;
memcpy(kinds, old->cpukinds, old->nr_cpukinds * sizeof(*kinds));
for(i=0;i<old->nr_cpukinds; i++) {
kinds[i].cpuset = hwloc_bitmap_tma_dup(tma, old->cpukinds[i].cpuset);
if (!kinds[i].cpuset) {
new->nr_cpukinds = i;
goto failed;
}
if (hwloc__tma_dup_infos(tma,
&kinds[i].infos, &kinds[i].nr_infos,
old->cpukinds[i].infos, old->cpukinds[i].nr_infos) < 0) {
assert(!tma || !tma->dontfree); /* this tma cannot fail to allocate */
hwloc_bitmap_free(kinds[i].cpuset);
new->nr_cpukinds = i;
goto failed;
}
}
return 0;
failed:
hwloc_internal_cpukinds_destroy(new);
return -1;
}
void
hwloc_internal_cpukinds_restrict(hwloc_topology_t topology)
{
unsigned i;
int removed = 0;
for(i=0; i<topology->nr_cpukinds; i++) {
struct hwloc_internal_cpukind_s *kind = &topology->cpukinds[i];
hwloc_bitmap_and(kind->cpuset, kind->cpuset, hwloc_get_root_obj(topology)->cpuset);
if (hwloc_bitmap_iszero(kind->cpuset)) {
hwloc_bitmap_free(kind->cpuset);
hwloc__free_infos(kind->infos, kind->nr_infos);
memmove(kind, kind+1, (topology->nr_cpukinds - i - 1)*sizeof(*kind));
i--;
topology->nr_cpukinds--;
removed = 1;
}
}
if (removed)
hwloc_internal_cpukinds_rank(topology);
}
/********************
* Registering
*/
static __hwloc_inline int
hwloc__cpukind_check_duplicate_info(struct hwloc_internal_cpukind_s *kind,
const char *name, const char *value)
{
unsigned i;
for(i=0; i<kind->nr_infos; i++)
if (!strcmp(kind->infos[i].name, name)
&& !strcmp(kind->infos[i].value, value))
return 1;
return 0;
}
static __hwloc_inline void
hwloc__cpukind_add_infos(struct hwloc_internal_cpukind_s *kind,
const struct hwloc_info_s *infos, unsigned nr_infos)
{
unsigned i;
for(i=0; i<nr_infos; i++) {
if (hwloc__cpukind_check_duplicate_info(kind, infos[i].name, infos[i].value))
continue;
hwloc__add_info(&kind->infos, &kind->nr_infos, infos[i].name, infos[i].value);
}
}
int
hwloc_internal_cpukinds_register(hwloc_topology_t topology, hwloc_cpuset_t cpuset,
int forced_efficiency,
const struct hwloc_info_s *infos, unsigned nr_infos,
unsigned long flags)
{
struct hwloc_internal_cpukind_s *kinds;
unsigned i, max, bits, oldnr, newnr;
if (hwloc_bitmap_iszero(cpuset)) {
hwloc_bitmap_free(cpuset);
errno = EINVAL;
return -1;
}
if (flags & ~HWLOC_CPUKINDS_REGISTER_FLAG_OVERWRITE_FORCED_EFFICIENCY) {
errno = EINVAL;
return -1;
}
/* TODO: for now, only windows provides a forced efficiency.
* if another backend ever provides a conflicting value, the first backend value will be kept.
* (user-provided values are not an issue, they are meant to overwrite)
*/
/* If we have N kinds currently, we may need 2N+1 kinds after inserting the new one:
* - each existing kind may get split into which PUs are in the new kind and which aren't.
* - some PUs might not have been in any kind yet.
*/
max = 2 * topology->nr_cpukinds + 1;
/* Allocate the power-of-two above 2N+1. */
bits = hwloc_flsl(max-1) + 1;
max = 1U<<bits;
/* Allocate 8 minimum to avoid multiple reallocs */
if (max < 8)
max = 8;
/* Create or enlarge the array of kinds if needed */
kinds = topology->cpukinds;
if (max > topology->nr_cpukinds_allocated) {
kinds = realloc(kinds, max * sizeof(*kinds));
if (!kinds) {
hwloc_bitmap_free(cpuset);
return -1;
}
memset(&kinds[topology->nr_cpukinds_allocated], 0, (max - topology->nr_cpukinds_allocated) * sizeof(*kinds));
topology->nr_cpukinds_allocated = max;
topology->cpukinds = kinds;
}
newnr = oldnr = topology->nr_cpukinds;
for(i=0; i<oldnr; i++) {
int res = hwloc_bitmap_compare_inclusion(cpuset, kinds[i].cpuset);
if (res == HWLOC_BITMAP_INTERSECTS || res == HWLOC_BITMAP_INCLUDED) {
/* new kind with intersection of cpusets and union of infos */
kinds[newnr].cpuset = hwloc_bitmap_alloc();
kinds[newnr].efficiency = HWLOC_CPUKIND_EFFICIENCY_UNKNOWN;
kinds[newnr].forced_efficiency = forced_efficiency;
hwloc_bitmap_and(kinds[newnr].cpuset, cpuset, kinds[i].cpuset);
hwloc__cpukind_add_infos(&kinds[newnr], kinds[i].infos, kinds[i].nr_infos);
hwloc__cpukind_add_infos(&kinds[newnr], infos, nr_infos);
/* remove cpuset PUs from the existing kind that we just split */
hwloc_bitmap_andnot(kinds[i].cpuset, kinds[i].cpuset, kinds[newnr].cpuset);
/* clear cpuset PUs that were taken care of */
hwloc_bitmap_andnot(cpuset, cpuset, kinds[newnr].cpuset);
newnr++;
} else if (res == HWLOC_BITMAP_CONTAINS
|| res == HWLOC_BITMAP_EQUAL) {
/* append new info to existing smaller (or equal) kind */
hwloc__cpukind_add_infos(&kinds[i], infos, nr_infos);
if ((flags & HWLOC_CPUKINDS_REGISTER_FLAG_OVERWRITE_FORCED_EFFICIENCY)
|| kinds[i].forced_efficiency == HWLOC_CPUKIND_EFFICIENCY_UNKNOWN)
kinds[i].forced_efficiency = forced_efficiency;
/* clear cpuset PUs that were taken care of */
hwloc_bitmap_andnot(cpuset, cpuset, kinds[i].cpuset);
} else {
assert(res == HWLOC_BITMAP_DIFFERENT);
/* nothing to do */
}
/* don't compare with anything else if already empty */
if (hwloc_bitmap_iszero(cpuset))
break;
}
/* add a final kind with remaining PUs if any */
if (!hwloc_bitmap_iszero(cpuset)) {
kinds[newnr].cpuset = cpuset;
kinds[newnr].efficiency = HWLOC_CPUKIND_EFFICIENCY_UNKNOWN;
kinds[newnr].forced_efficiency = forced_efficiency;
hwloc__cpukind_add_infos(&kinds[newnr], infos, nr_infos);
newnr++;
} else {
hwloc_bitmap_free(cpuset);
}
topology->nr_cpukinds = newnr;
return 0;
}
int
hwloc_cpukinds_register(hwloc_topology_t topology, hwloc_cpuset_t _cpuset,
int forced_efficiency,
unsigned nr_infos, struct hwloc_info_s *infos,
unsigned long flags)
{
hwloc_bitmap_t cpuset;
int err;
if (flags) {
errno = EINVAL;
return -1;
}
if (!_cpuset || hwloc_bitmap_iszero(_cpuset)) {
errno = EINVAL;
return -1;
}
cpuset = hwloc_bitmap_dup(_cpuset);
if (!cpuset)
return -1;
if (forced_efficiency < 0)
forced_efficiency = HWLOC_CPUKIND_EFFICIENCY_UNKNOWN;
err = hwloc_internal_cpukinds_register(topology, cpuset, forced_efficiency, infos, nr_infos, HWLOC_CPUKINDS_REGISTER_FLAG_OVERWRITE_FORCED_EFFICIENCY);
if (err < 0)
return err;
hwloc_internal_cpukinds_rank(topology);
return 0;
}
/*********************
* Ranking
*/
static int
hwloc__cpukinds_check_duplicate_rankings(struct hwloc_topology *topology)
{
unsigned i,j;
for(i=0; i<topology->nr_cpukinds; i++)
for(j=i+1; j<topology->nr_cpukinds; j++)
if (topology->cpukinds[i].forced_efficiency == topology->cpukinds[j].forced_efficiency)
/* if any duplicate, fail */
return -1;
return 0;
}
static int
hwloc__cpukinds_try_rank_by_forced_efficiency(struct hwloc_topology *topology)
{
unsigned i;
hwloc_debug("Trying to rank cpukinds by forced efficiency...\n");
for(i=0; i<topology->nr_cpukinds; i++) {
if (topology->cpukinds[i].forced_efficiency == HWLOC_CPUKIND_EFFICIENCY_UNKNOWN)
/* if any unknown, fail */
return -1;
topology->cpukinds[i].ranking_value = topology->cpukinds[i].forced_efficiency;
}
return hwloc__cpukinds_check_duplicate_rankings(topology);
}
struct hwloc_cpukinds_info_summary {
int have_max_freq;
int have_base_freq;
int have_intel_core_type;
struct hwloc_cpukind_info_summary {
unsigned intel_core_type; /* 1 for atom, 2 for core */
unsigned max_freq, base_freq; /* MHz, hence < 100000 */
} * summaries;
};
static void
hwloc__cpukinds_summarize_info(struct hwloc_topology *topology,
struct hwloc_cpukinds_info_summary *summary)
{
unsigned i, j;
summary->have_max_freq = 1;
summary->have_base_freq = 1;
summary->have_intel_core_type = 1;
for(i=0; i<topology->nr_cpukinds; i++) {
struct hwloc_internal_cpukind_s *kind = &topology->cpukinds[i];
for(j=0; j<kind->nr_infos; j++) {
struct hwloc_info_s *info = &kind->infos[j];
if (!strcmp(info->name, "FrequencyMaxMHz")) {
summary->summaries[i].max_freq = atoi(info->value);
} else if (!strcmp(info->name, "FrequencyBaseMHz")) {
summary->summaries[i].base_freq = atoi(info->value);
} else if (!strcmp(info->name, "CoreType")) {
if (!strcmp(info->value, "IntelAtom"))
summary->summaries[i].intel_core_type = 1;
else if (!strcmp(info->value, "IntelCore"))
summary->summaries[i].intel_core_type = 2;
}
}
hwloc_debug("cpukind #%u has intel_core_type %u max_freq %u base_freq %u\n",
i, summary->summaries[i].intel_core_type,
summary->summaries[i].max_freq, summary->summaries[i].base_freq);
if (!summary->summaries[i].base_freq)
summary->have_base_freq = 0;
if (!summary->summaries[i].max_freq)
summary->have_max_freq = 0;
if (!summary->summaries[i].intel_core_type)
summary->have_intel_core_type = 0;
}
}
enum hwloc_cpukinds_ranking {
HWLOC_CPUKINDS_RANKING_DEFAULT, /* forced + frequency on ARM, forced + coretype_frequency otherwise */
HWLOC_CPUKINDS_RANKING_NO_FORCED_EFFICIENCY, /* default without forced */
HWLOC_CPUKINDS_RANKING_FORCED_EFFICIENCY,
HWLOC_CPUKINDS_RANKING_CORETYPE_FREQUENCY,
HWLOC_CPUKINDS_RANKING_CORETYPE,
HWLOC_CPUKINDS_RANKING_FREQUENCY,
HWLOC_CPUKINDS_RANKING_FREQUENCY_MAX,
HWLOC_CPUKINDS_RANKING_FREQUENCY_BASE,
HWLOC_CPUKINDS_RANKING_NONE
};
static int
hwloc__cpukinds_try_rank_by_info(struct hwloc_topology *topology,
enum hwloc_cpukinds_ranking heuristics,
struct hwloc_cpukinds_info_summary *summary)
{
unsigned i;
if (HWLOC_CPUKINDS_RANKING_CORETYPE_FREQUENCY == heuristics) {
hwloc_debug("Trying to rank cpukinds by coretype+frequency...\n");
/* we need intel_core_type + (base or max freq) for all kinds */
if (!summary->have_intel_core_type
|| (!summary->have_max_freq && !summary->have_base_freq))
return -1;
/* rank first by coretype (Core>>Atom) then by frequency, base if available, max otherwise */
for(i=0; i<topology->nr_cpukinds; i++) {
struct hwloc_internal_cpukind_s *kind = &topology->cpukinds[i];
if (summary->have_base_freq)
kind->ranking_value = (summary->summaries[i].intel_core_type << 20) + summary->summaries[i].base_freq;
else
kind->ranking_value = (summary->summaries[i].intel_core_type << 20) + summary->summaries[i].max_freq;
}
} else if (HWLOC_CPUKINDS_RANKING_CORETYPE == heuristics) {
hwloc_debug("Trying to rank cpukinds by coretype...\n");
/* we need intel_core_type */
if (!summary->have_intel_core_type)
return -1;
/* rank by coretype (Core>>Atom) */
for(i=0; i<topology->nr_cpukinds; i++) {
struct hwloc_internal_cpukind_s *kind = &topology->cpukinds[i];
kind->ranking_value = (summary->summaries[i].intel_core_type << 20);
}
} else if (HWLOC_CPUKINDS_RANKING_FREQUENCY == heuristics) {
hwloc_debug("Trying to rank cpukinds by frequency...\n");
/* we need base or max freq for all kinds */
if (!summary->have_max_freq && !summary->have_base_freq)
return -1;
/* rank first by frequency, base if available, max otherwise */
for(i=0; i<topology->nr_cpukinds; i++) {
struct hwloc_internal_cpukind_s *kind = &topology->cpukinds[i];
if (summary->have_base_freq)
kind->ranking_value = summary->summaries[i].base_freq;
else
kind->ranking_value = summary->summaries[i].max_freq;
}
} else if (HWLOC_CPUKINDS_RANKING_FREQUENCY_MAX == heuristics) {
hwloc_debug("Trying to rank cpukinds by frequency max...\n");
/* we need max freq for all kinds */
if (!summary->have_max_freq)
return -1;
/* rank first by frequency, base if available, max otherwise */
for(i=0; i<topology->nr_cpukinds; i++) {
struct hwloc_internal_cpukind_s *kind = &topology->cpukinds[i];
kind->ranking_value = summary->summaries[i].max_freq;
}
} else if (HWLOC_CPUKINDS_RANKING_FREQUENCY_BASE == heuristics) {
hwloc_debug("Trying to rank cpukinds by frequency base...\n");
/* we need max freq for all kinds */
if (!summary->have_base_freq)
return -1;
/* rank first by frequency, base if available, max otherwise */
for(i=0; i<topology->nr_cpukinds; i++) {
struct hwloc_internal_cpukind_s *kind = &topology->cpukinds[i];
kind->ranking_value = summary->summaries[i].base_freq;
}
} else assert(0);
return hwloc__cpukinds_check_duplicate_rankings(topology);
}
static int hwloc__cpukinds_compare_ranking_values(const void *_a, const void *_b)
{
const struct hwloc_internal_cpukind_s *a = _a;
const struct hwloc_internal_cpukind_s *b = _b;
return a->ranking_value - b->ranking_value;
}
/* this function requires ranking values to be unique */
static void
hwloc__cpukinds_finalize_ranking(struct hwloc_topology *topology)
{
unsigned i;
/* sort */
qsort(topology->cpukinds, topology->nr_cpukinds, sizeof(*topology->cpukinds), hwloc__cpukinds_compare_ranking_values);
/* define our own efficiency between 0 and N-1 */
for(i=0; i<topology->nr_cpukinds; i++)
topology->cpukinds[i].efficiency = i;
}
int
hwloc_internal_cpukinds_rank(struct hwloc_topology *topology)
{
enum hwloc_cpukinds_ranking heuristics;
char *env;
unsigned i;
int err;
if (!topology->nr_cpukinds)
return 0;
if (topology->nr_cpukinds == 1) {
topology->cpukinds[0].efficiency = 0;
return 0;
}
heuristics = HWLOC_CPUKINDS_RANKING_DEFAULT;
env = getenv("HWLOC_CPUKINDS_RANKING");
if (env) {
if (!strcmp(env, "default"))
heuristics = HWLOC_CPUKINDS_RANKING_DEFAULT;
else if (!strcmp(env, "none"))
heuristics = HWLOC_CPUKINDS_RANKING_NONE;
else if (!strcmp(env, "coretype+frequency"))
heuristics = HWLOC_CPUKINDS_RANKING_CORETYPE_FREQUENCY;
else if (!strcmp(env, "coretype"))
heuristics = HWLOC_CPUKINDS_RANKING_CORETYPE;
else if (!strcmp(env, "frequency"))
heuristics = HWLOC_CPUKINDS_RANKING_FREQUENCY;
else if (!strcmp(env, "frequency_max"))
heuristics = HWLOC_CPUKINDS_RANKING_FREQUENCY_MAX;
else if (!strcmp(env, "frequency_base"))
heuristics = HWLOC_CPUKINDS_RANKING_FREQUENCY_BASE;
else if (!strcmp(env, "forced_efficiency"))
heuristics = HWLOC_CPUKINDS_RANKING_FORCED_EFFICIENCY;
else if (!strcmp(env, "no_forced_efficiency"))
heuristics = HWLOC_CPUKINDS_RANKING_NO_FORCED_EFFICIENCY;
else if (!hwloc_hide_errors())
fprintf(stderr, "Failed to recognize HWLOC_CPUKINDS_RANKING value %s\n", env);
}
if (heuristics == HWLOC_CPUKINDS_RANKING_DEFAULT
|| heuristics == HWLOC_CPUKINDS_RANKING_NO_FORCED_EFFICIENCY) {
/* default is forced_efficiency first */
struct hwloc_cpukinds_info_summary summary;
enum hwloc_cpukinds_ranking subheuristics;
const char *arch;
if (heuristics == HWLOC_CPUKINDS_RANKING_DEFAULT)
hwloc_debug("Using default ranking strategy...\n");
else
hwloc_debug("Using custom ranking strategy from HWLOC_CPUKINDS_RANKING=%s\n", env);
if (heuristics != HWLOC_CPUKINDS_RANKING_NO_FORCED_EFFICIENCY) {
err = hwloc__cpukinds_try_rank_by_forced_efficiency(topology);
if (!err)
goto ready;
}
summary.summaries = calloc(topology->nr_cpukinds, sizeof(*summary.summaries));
if (!summary.summaries)
goto failed;
hwloc__cpukinds_summarize_info(topology, &summary);
arch = hwloc_obj_get_info_by_name(topology->levels[0][0], "Architecture");
/* TODO: rather coretype_frequency only on x86/Intel? */
if (arch && (!strncmp(arch, "arm", 3) || !strncmp(arch, "aarch", 5)))
/* then frequency on ARM */
subheuristics = HWLOC_CPUKINDS_RANKING_FREQUENCY;
else
/* or coretype+frequency otherwise */
subheuristics = HWLOC_CPUKINDS_RANKING_CORETYPE_FREQUENCY;
err = hwloc__cpukinds_try_rank_by_info(topology, subheuristics, &summary);
free(summary.summaries);
if (!err)
goto ready;
} else if (heuristics == HWLOC_CPUKINDS_RANKING_FORCED_EFFICIENCY) {
hwloc_debug("Using custom ranking strategy from HWLOC_CPUKINDS_RANKING=%s\n", env);
err = hwloc__cpukinds_try_rank_by_forced_efficiency(topology);
if (!err)
goto ready;
} else if (heuristics != HWLOC_CPUKINDS_RANKING_NONE) {
/* custom heuristics */
struct hwloc_cpukinds_info_summary summary;
hwloc_debug("Using custom ranking strategy from HWLOC_CPUKINDS_RANKING=%s\n", env);
summary.summaries = calloc(topology->nr_cpukinds, sizeof(*summary.summaries));
if (!summary.summaries)
goto failed;
hwloc__cpukinds_summarize_info(topology, &summary);
err = hwloc__cpukinds_try_rank_by_info(topology, heuristics, &summary);
free(summary.summaries);
if (!err)
goto ready;
}
failed:
/* failed to rank, clear efficiencies */
for(i=0; i<topology->nr_cpukinds; i++)
topology->cpukinds[i].efficiency = HWLOC_CPUKIND_EFFICIENCY_UNKNOWN;
hwloc_debug("Failed to rank cpukinds.\n\n");
return 0;
ready:
for(i=0; i<topology->nr_cpukinds; i++)
hwloc_debug("cpukind #%u got ranking value %llu\n", i, (unsigned long long) topology->cpukinds[i].ranking_value);
hwloc__cpukinds_finalize_ranking(topology);
#ifdef HWLOC_DEBUG
for(i=0; i<topology->nr_cpukinds; i++)
assert(topology->cpukinds[i].efficiency == (int) i);
#endif
hwloc_debug("\n");
return 0;
}
/*****************
* Consulting
*/
int
hwloc_cpukinds_get_nr(hwloc_topology_t topology, unsigned long flags)
{
if (flags) {
errno = EINVAL;
return -1;
}
return topology->nr_cpukinds;
}
int
hwloc_cpukinds_get_info(hwloc_topology_t topology,
unsigned id,
hwloc_bitmap_t cpuset,
int *efficiencyp,
unsigned *nr_infosp, struct hwloc_info_s **infosp,
unsigned long flags)
{
struct hwloc_internal_cpukind_s *kind;
if (flags) {
errno = EINVAL;
return -1;
}
if (id >= topology->nr_cpukinds) {
errno = ENOENT;
return -1;
}
kind = &topology->cpukinds[id];
if (cpuset)
hwloc_bitmap_copy(cpuset, kind->cpuset);
if (efficiencyp)
*efficiencyp = kind->efficiency;
if (nr_infosp && infosp) {
*nr_infosp = kind->nr_infos;
*infosp = kind->infos;
}
return 0;
}
int
hwloc_cpukinds_get_by_cpuset(hwloc_topology_t topology,
hwloc_const_bitmap_t cpuset,
unsigned long flags)
{
unsigned id;
if (flags) {
errno = EINVAL;
return -1;
}
if (!cpuset || hwloc_bitmap_iszero(cpuset)) {
errno = EINVAL;
return -1;
}
for(id=0; id<topology->nr_cpukinds; id++) {
struct hwloc_internal_cpukind_s *kind = &topology->cpukinds[id];
int res = hwloc_bitmap_compare_inclusion(cpuset, kind->cpuset);
if (res == HWLOC_BITMAP_EQUAL || res == HWLOC_BITMAP_INCLUDED) {
return (int) id;
} else if (res == HWLOC_BITMAP_INTERSECTS || res == HWLOC_BITMAP_CONTAINS) {
errno = EXDEV;
return -1;
}
}
errno = ENOENT;
return -1;
}

View file

@ -1,5 +1,5 @@
/* /*
* Copyright © 2013-2019 Inria. All rights reserved. * Copyright © 2013-2020 Inria. All rights reserved.
* See COPYING in top-level directory. * See COPYING in top-level directory.
*/ */
@ -333,10 +333,8 @@ int hwloc_topology_diff_build(hwloc_topology_t topo1,
if (!err) { if (!err) {
if (SETS_DIFFERENT(allowed_cpuset, topo1, topo2) if (SETS_DIFFERENT(allowed_cpuset, topo1, topo2)
|| SETS_DIFFERENT(allowed_nodeset, topo1, topo2)) { || SETS_DIFFERENT(allowed_nodeset, topo1, topo2))
hwloc_append_diff_too_complex(hwloc_get_root_obj(topo1), diffp, &lastdiff); goto roottoocomplex;
err = 1;
}
} }
if (!err) { if (!err) {
@ -346,33 +344,78 @@ int hwloc_topology_diff_build(hwloc_topology_t topo1,
dist1 = topo1->first_dist; dist1 = topo1->first_dist;
dist2 = topo2->first_dist; dist2 = topo2->first_dist;
while (dist1 || dist2) { while (dist1 || dist2) {
if (!!dist1 != !!dist2) { if (!!dist1 != !!dist2)
hwloc_append_diff_too_complex(hwloc_get_root_obj(topo1), diffp, &lastdiff); goto roottoocomplex;
err = 1;
break;
}
if (dist1->unique_type != dist2->unique_type if (dist1->unique_type != dist2->unique_type
|| dist1->different_types || dist2->different_types /* too lazy to support this case */ || dist1->different_types || dist2->different_types /* too lazy to support this case */
|| dist1->nbobjs != dist2->nbobjs || dist1->nbobjs != dist2->nbobjs
|| dist1->kind != dist2->kind || dist1->kind != dist2->kind
|| memcmp(dist1->values, dist2->values, dist1->nbobjs * dist1->nbobjs * sizeof(*dist1->values))) { || memcmp(dist1->values, dist2->values, dist1->nbobjs * dist1->nbobjs * sizeof(*dist1->values)))
hwloc_append_diff_too_complex(hwloc_get_root_obj(topo1), diffp, &lastdiff); goto roottoocomplex;
err = 1;
break;
}
for(i=0; i<dist1->nbobjs; i++) for(i=0; i<dist1->nbobjs; i++)
/* gp_index isn't enforced above. so compare logical_index instead, which is enforced. requires distances refresh() above */ /* gp_index isn't enforced above. so compare logical_index instead, which is enforced. requires distances refresh() above */
if (dist1->objs[i]->logical_index != dist2->objs[i]->logical_index) { if (dist1->objs[i]->logical_index != dist2->objs[i]->logical_index)
hwloc_append_diff_too_complex(hwloc_get_root_obj(topo1), diffp, &lastdiff); goto roottoocomplex;
err = 1;
break;
}
dist1 = dist1->next; dist1 = dist1->next;
dist2 = dist2->next; dist2 = dist2->next;
} }
} }
if (!err) {
/* memattrs */
hwloc_internal_memattrs_refresh(topo1);
hwloc_internal_memattrs_refresh(topo2);
if (topo1->nr_memattrs != topo2->nr_memattrs)
goto roottoocomplex;
for(i=0; i<topo1->nr_memattrs; i++) {
struct hwloc_internal_memattr_s *imattr1 = &topo1->memattrs[i], *imattr2 = &topo2->memattrs[i];
unsigned j;
if (strcmp(imattr1->name, imattr2->name)
|| imattr1->flags != imattr2->flags
|| imattr1->nr_targets != imattr2->nr_targets)
goto roottoocomplex;
if (i == HWLOC_MEMATTR_ID_CAPACITY
|| i == HWLOC_MEMATTR_ID_LOCALITY)
/* no need to check virtual attributes, there were refreshed from other topology attributes, checked above */
continue;
for(j=0; j<imattr1->nr_targets; j++) {
struct hwloc_internal_memattr_target_s *imtg1 = &imattr1->targets[j], *imtg2 = &imattr2->targets[j];
if (imtg1->type != imtg2->type)
goto roottoocomplex;
if (imtg1->obj->logical_index != imtg2->obj->logical_index)
goto roottoocomplex;
if (imattr1->flags & HWLOC_MEMATTR_FLAG_NEED_INITIATOR) {
unsigned k;
for(k=0; k<imtg1->nr_initiators; k++) {
struct hwloc_internal_memattr_initiator_s *imi1 = &imtg1->initiators[k], *imi2 = &imtg2->initiators[k];
if (imi1->value != imi2->value
|| imi1->initiator.type != imi2->initiator.type)
goto roottoocomplex;
if (imi1->initiator.type == HWLOC_LOCATION_TYPE_CPUSET) {
if (!hwloc_bitmap_isequal(imi1->initiator.location.cpuset, imi2->initiator.location.cpuset))
goto roottoocomplex;
} else if (imi1->initiator.type == HWLOC_LOCATION_TYPE_OBJECT) {
if (imi1->initiator.location.object.type != imi2->initiator.location.object.type)
goto roottoocomplex;
if (imi1->initiator.location.object.obj->logical_index != imi2->initiator.location.object.obj->logical_index)
goto roottoocomplex;
} else {
assert(0);
}
}
} else {
if (imtg1->noinitiator_value != imtg2->noinitiator_value)
goto roottoocomplex;
}
}
}
}
return err; return err;
roottoocomplex:
hwloc_append_diff_too_complex(hwloc_get_root_obj(topo1), diffp, &lastdiff);
return 1;
} }
/******************** /********************

View file

@ -1,5 +1,5 @@
/* /*
* Copyright © 2010-2019 Inria. All rights reserved. * Copyright © 2010-2020 Inria. All rights reserved.
* Copyright © 2011-2012 Université Bordeaux * Copyright © 2011-2012 Université Bordeaux
* Copyright © 2011 Cisco Systems, Inc. All rights reserved. * Copyright © 2011 Cisco Systems, Inc. All rights reserved.
* See COPYING in top-level directory. * See COPYING in top-level directory.
@ -526,36 +526,6 @@ int hwloc_distances_add(hwloc_topology_t topology,
* Refresh objects in distances * Refresh objects in distances
*/ */
static hwloc_obj_t hwloc_find_obj_by_depth_and_gp_index(hwloc_topology_t topology, unsigned depth, uint64_t gp_index)
{
hwloc_obj_t obj = hwloc_get_obj_by_depth(topology, depth, 0);
while (obj) {
if (obj->gp_index == gp_index)
return obj;
obj = obj->next_cousin;
}
return NULL;
}
static hwloc_obj_t hwloc_find_obj_by_type_and_gp_index(hwloc_topology_t topology, hwloc_obj_type_t type, uint64_t gp_index)
{
int depth = hwloc_get_type_depth(topology, type);
if (depth == HWLOC_TYPE_DEPTH_UNKNOWN)
return NULL;
if (depth == HWLOC_TYPE_DEPTH_MULTIPLE) {
int topodepth = hwloc_topology_get_depth(topology);
for(depth=0; depth<topodepth; depth++) {
if (hwloc_get_depth_type(topology, depth) == type) {
hwloc_obj_t obj = hwloc_find_obj_by_depth_and_gp_index(topology, depth, gp_index);
if (obj)
return obj;
}
}
return NULL;
}
return hwloc_find_obj_by_depth_and_gp_index(topology, depth, gp_index);
}
static void static void
hwloc_internal_distances_restrict(hwloc_obj_t *objs, hwloc_internal_distances_restrict(hwloc_obj_t *objs,
uint64_t *indexes, uint64_t *indexes,
@ -612,7 +582,7 @@ hwloc_internal_distances_refresh_one(hwloc_topology_t topology,
else else
abort(); abort();
} else { } else {
obj = hwloc_find_obj_by_type_and_gp_index(topology, different_types ? different_types[i] : unique_type, indexes[i]); obj = hwloc_get_obj_by_type_and_gp_index(topology, different_types ? different_types[i] : unique_type, indexes[i]);
} }
objs[i] = obj; objs[i] = obj;
if (!obj) if (!obj)
@ -874,26 +844,6 @@ hwloc_distances_get_by_type(hwloc_topology_t topology, hwloc_obj_type_t type,
* Grouping objects according to distances * Grouping objects according to distances
*/ */
static void hwloc_report_user_distance_error(const char *msg, int line)
{
static int reported = 0;
if (!reported && !hwloc_hide_errors()) {
fprintf(stderr, "****************************************************************************\n");
fprintf(stderr, "* hwloc %s was given invalid distances by the user.\n", HWLOC_VERSION);
fprintf(stderr, "*\n");
fprintf(stderr, "* %s\n", msg);
fprintf(stderr, "* Error occurred in topology.c line %d\n", line);
fprintf(stderr, "*\n");
fprintf(stderr, "* Please make sure that distances given through the programming API\n");
fprintf(stderr, "* do not contradict any other topology information.\n");
fprintf(stderr, "* \n");
fprintf(stderr, "* hwloc will now ignore this invalid topology information and continue.\n");
fprintf(stderr, "****************************************************************************\n");
reported = 1;
}
}
static int hwloc_compare_values(uint64_t a, uint64_t b, float accuracy) static int hwloc_compare_values(uint64_t a, uint64_t b, float accuracy)
{ {
if (accuracy != 0.0f && fabsf((float)a-(float)b) < (float)a * accuracy) if (accuracy != 0.0f && fabsf((float)a-(float)b) < (float)a * accuracy)
@ -1086,7 +1036,7 @@ hwloc__groups_by_distances(struct hwloc_topology *topology,
hwloc_debug_1arg_bitmap("adding Group object with %u objects and cpuset %s\n", hwloc_debug_1arg_bitmap("adding Group object with %u objects and cpuset %s\n",
groupsizes[i], group_obj->cpuset); groupsizes[i], group_obj->cpuset);
res_obj = hwloc__insert_object_by_cpuset(topology, NULL, group_obj, res_obj = hwloc__insert_object_by_cpuset(topology, NULL, group_obj,
(kind & HWLOC_DISTANCES_KIND_FROM_USER) ? hwloc_report_user_distance_error : hwloc_report_os_error); (kind & HWLOC_DISTANCES_KIND_FROM_USER) ? "distances:fromuser:group" : "distances:group");
/* res_obj may be NULL on failure to insert. */ /* res_obj may be NULL on failure to insert. */
if (!res_obj) if (!res_obj)
failed++; failed++;

1197
src/3rdparty/hwloc/src/memattrs.c vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
/* /*
* Copyright © 2009 CNRS * Copyright © 2009 CNRS
* Copyright © 2009-2018 Inria. All rights reserved. * Copyright © 2009-2020 Inria. All rights reserved.
* Copyright © 2009-2010 Université Bordeaux * Copyright © 2009-2010 Université Bordeaux
* Copyright © 2009-2018 Cisco Systems, Inc. All rights reserved. * Copyright © 2009-2018 Cisco Systems, Inc. All rights reserved.
* See COPYING in top-level directory. * See COPYING in top-level directory.
@ -114,7 +114,7 @@ void hwloc_add_uname_info(struct hwloc_topology *topology __hwloc_attribute_unus
char * char *
hwloc_progname(struct hwloc_topology *topology __hwloc_attribute_unused) hwloc_progname(struct hwloc_topology *topology __hwloc_attribute_unused)
{ {
#if HAVE_DECL_GETMODULEFILENAME #if (defined HAVE_DECL_GETMODULEFILENAME) && HAVE_DECL_GETMODULEFILENAME
char name[256], *local_basename; char name[256], *local_basename;
unsigned res = GetModuleFileName(NULL, name, sizeof(name)); unsigned res = GetModuleFileName(NULL, name, sizeof(name));
if (res == sizeof(name) || !res) if (res == sizeof(name) || !res)

View file

@ -232,7 +232,8 @@ enum hwloc_pci_busid_comparison_e {
HWLOC_PCI_BUSID_LOWER, HWLOC_PCI_BUSID_LOWER,
HWLOC_PCI_BUSID_HIGHER, HWLOC_PCI_BUSID_HIGHER,
HWLOC_PCI_BUSID_INCLUDED, HWLOC_PCI_BUSID_INCLUDED,
HWLOC_PCI_BUSID_SUPERSET HWLOC_PCI_BUSID_SUPERSET,
HWLOC_PCI_BUSID_EQUAL
}; };
static enum hwloc_pci_busid_comparison_e static enum hwloc_pci_busid_comparison_e
@ -274,11 +275,8 @@ hwloc_pci_compare_busids(struct hwloc_obj *a, struct hwloc_obj *b)
if (a->attr->pcidev.func > b->attr->pcidev.func) if (a->attr->pcidev.func > b->attr->pcidev.func)
return HWLOC_PCI_BUSID_HIGHER; return HWLOC_PCI_BUSID_HIGHER;
/* Should never reach here. Abort on both debug builds and /* Should never reach here. */
non-debug builds */ return HWLOC_PCI_BUSID_EQUAL;
assert(0);
fprintf(stderr, "Bad assertion in hwloc %s:%d (aborting)\n", __FILE__, __LINE__);
exit(1);
} }
static void static void
@ -329,6 +327,23 @@ hwloc_pci_add_object(struct hwloc_obj *parent, struct hwloc_obj **parent_io_firs
} }
return; return;
} }
case HWLOC_PCI_BUSID_EQUAL: {
static int reported = 0;
if (!reported && !hwloc_hide_errors()) {
fprintf(stderr, "*********************************************************\n");
fprintf(stderr, "* hwloc %s received invalid PCI information.\n", HWLOC_VERSION);
fprintf(stderr, "*\n");
fprintf(stderr, "* Trying to insert PCI object %04x:%02x:%02x.%01x at %04x:%02x:%02x.%01x\n",
new->attr->pcidev.domain, new->attr->pcidev.bus, new->attr->pcidev.dev, new->attr->pcidev.func,
(*curp)->attr->pcidev.domain, (*curp)->attr->pcidev.bus, (*curp)->attr->pcidev.dev, (*curp)->attr->pcidev.func);
fprintf(stderr, "*\n");
fprintf(stderr, "* hwloc will now ignore this object and continue.\n");
fprintf(stderr, "*********************************************************\n");
reported = 1;
}
hwloc_free_unlinked_object(new);
return;
}
} }
} }
/* add to the end of the list if higher than everybody */ /* add to the end of the list if higher than everybody */
@ -425,39 +440,10 @@ hwloc_pcidisc_add_hostbridges(struct hwloc_topology *topology,
static struct hwloc_obj * static struct hwloc_obj *
hwloc_pci_fixup_busid_parent(struct hwloc_topology *topology __hwloc_attribute_unused, hwloc_pci_fixup_busid_parent(struct hwloc_topology *topology __hwloc_attribute_unused,
struct hwloc_pcidev_attr_s *busid, struct hwloc_pcidev_attr_s *busid __hwloc_attribute_unused,
struct hwloc_obj *parent) struct hwloc_obj *parent __hwloc_attribute_unused)
{ {
/* Xeon E5v3 in cluster-on-die mode only have PCI on the first NUMA node of each package. /* no quirk for now */
* but many dual-processor host report the second PCI hierarchy on 2nd NUMA of first package.
*/
if (parent->depth >= 2
&& parent->type == HWLOC_OBJ_NUMANODE
&& parent->sibling_rank == 1 && parent->parent->arity == 2
&& parent->parent->type == HWLOC_OBJ_PACKAGE
&& parent->parent->sibling_rank == 0 && parent->parent->parent->arity == 2) {
const char *cpumodel = hwloc_obj_get_info_by_name(parent->parent, "CPUModel");
if (cpumodel && strstr(cpumodel, "Xeon")) {
if (!hwloc_hide_errors()) {
fprintf(stderr, "****************************************************************************\n");
fprintf(stderr, "* hwloc %s has encountered an incorrect PCI locality information.\n", HWLOC_VERSION);
fprintf(stderr, "* PCI bus %04x:%02x is supposedly close to 2nd NUMA node of 1st package,\n",
busid->domain, busid->bus);
fprintf(stderr, "* however hwloc believes this is impossible on this architecture.\n");
fprintf(stderr, "* Therefore the PCI bus will be moved to 1st NUMA node of 2nd package.\n");
fprintf(stderr, "*\n");
fprintf(stderr, "* If you feel this fixup is wrong, disable it by setting in your environment\n");
fprintf(stderr, "* HWLOC_PCI_%04x_%02x_LOCALCPUS= (empty value), and report the problem\n",
busid->domain, busid->bus);
fprintf(stderr, "* to the hwloc's user mailing list together with the XML output of lstopo.\n");
fprintf(stderr, "*\n");
fprintf(stderr, "* You may silence this message by setting HWLOC_HIDE_ERRORS=1 in your environment.\n");
fprintf(stderr, "****************************************************************************\n");
}
return parent->parent->next_sibling->first_child;
}
}
return parent; return parent;
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright © 2017-2019 Inria. All rights reserved. * Copyright © 2017-2020 Inria. All rights reserved.
* See COPYING in top-level directory. * See COPYING in top-level directory.
*/ */
@ -97,6 +97,7 @@ hwloc_shmem_topology_write(hwloc_topology_t topology,
* without being able to free() them. * without being able to free() them.
*/ */
hwloc_internal_distances_refresh(topology); hwloc_internal_distances_refresh(topology);
hwloc_internal_memattrs_refresh(topology);
header.header_version = HWLOC_SHMEM_HEADER_VERSION; header.header_version = HWLOC_SHMEM_HEADER_VERSION;
header.header_length = sizeof(header); header.header_length = sizeof(header);
@ -134,8 +135,9 @@ hwloc_shmem_topology_write(hwloc_topology_t topology,
assert((char *)mmap_res <= (char *)mmap_address + length); assert((char *)mmap_res <= (char *)mmap_address + length);
/* now refresh the new distances so that adopters can use them without refreshing the R/O shmem mapping */ /* now refresh the new distances/memattrs so that adopters can use them without refreshing the R/O shmem mapping */
hwloc_internal_distances_refresh(new); hwloc_internal_distances_refresh(new);
hwloc_internal_memattrs_refresh(topology);
/* topology is saved, release resources now */ /* topology is saved, release resources now */
munmap(mmap_address, length); munmap(mmap_address, length);
@ -214,11 +216,13 @@ hwloc_shmem_topology_adopt(hwloc_topology_t *topologyp,
new->support.discovery = malloc(sizeof(*new->support.discovery)); new->support.discovery = malloc(sizeof(*new->support.discovery));
new->support.cpubind = malloc(sizeof(*new->support.cpubind)); new->support.cpubind = malloc(sizeof(*new->support.cpubind));
new->support.membind = malloc(sizeof(*new->support.membind)); new->support.membind = malloc(sizeof(*new->support.membind));
if (!new->support.discovery || !new->support.cpubind || !new->support.membind) new->support.misc = malloc(sizeof(*new->support.misc));
if (!new->support.discovery || !new->support.cpubind || !new->support.membind || !new->support.misc)
goto out_with_support; goto out_with_support;
memcpy(new->support.discovery, old->support.discovery, sizeof(*new->support.discovery)); memcpy(new->support.discovery, old->support.discovery, sizeof(*new->support.discovery));
memcpy(new->support.cpubind, old->support.cpubind, sizeof(*new->support.cpubind)); memcpy(new->support.cpubind, old->support.cpubind, sizeof(*new->support.cpubind));
memcpy(new->support.membind, old->support.membind, sizeof(*new->support.membind)); memcpy(new->support.membind, old->support.membind, sizeof(*new->support.membind));
memcpy(new->support.misc, old->support.misc, sizeof(*new->support.misc));
hwloc_set_binding_hooks(new); hwloc_set_binding_hooks(new);
/* clear userdata callbacks pointing to the writer process' functions */ /* clear userdata callbacks pointing to the writer process' functions */
new->userdata_export_cb = NULL; new->userdata_export_cb = NULL;
@ -236,6 +240,7 @@ hwloc_shmem_topology_adopt(hwloc_topology_t *topologyp,
free(new->support.discovery); free(new->support.discovery);
free(new->support.cpubind); free(new->support.cpubind);
free(new->support.membind); free(new->support.membind);
free(new->support.misc);
free(new); free(new);
out_with_components: out_with_components:
hwloc_components_fini(); hwloc_components_fini();
@ -252,6 +257,7 @@ hwloc__topology_disadopt(hwloc_topology_t topology)
free(topology->support.discovery); free(topology->support.discovery);
free(topology->support.cpubind); free(topology->support.cpubind);
free(topology->support.membind); free(topology->support.membind);
free(topology->support.misc);
free(topology); free(topology);
} }

View file

@ -1,9 +1,4 @@
HWLOC_DECLSPEC extern const struct hwloc_component hwloc_noos_component; #include <private/internal-components.h>
HWLOC_DECLSPEC extern const struct hwloc_component hwloc_xml_component;
HWLOC_DECLSPEC extern const struct hwloc_component hwloc_synthetic_component;
HWLOC_DECLSPEC extern const struct hwloc_component hwloc_xml_nolibxml_component;
HWLOC_DECLSPEC extern const struct hwloc_component hwloc_windows_component;
HWLOC_DECLSPEC extern const struct hwloc_component hwloc_x86_component;
static const struct hwloc_component * hwloc_static_components[] = { static const struct hwloc_component * hwloc_static_components[] = {
&hwloc_noos_component, &hwloc_noos_component,
&hwloc_xml_component, &hwloc_xml_component,

View file

@ -1,6 +1,6 @@
/* /*
* Copyright © 2009 CNRS * Copyright © 2009 CNRS
* Copyright © 2009-2019 Inria. All rights reserved. * Copyright © 2009-2020 Inria. All rights reserved.
* Copyright © 2009-2010 Université Bordeaux * Copyright © 2009-2010 Université Bordeaux
* Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved. * Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved.
* See COPYING in top-level directory. * See COPYING in top-level directory.
@ -471,7 +471,7 @@ hwloc_backend_synthetic_init(struct hwloc_synthetic_backend_data_s *data,
/* initialize parent arity to 0 so that the levels are not infinite */ /* initialize parent arity to 0 so that the levels are not infinite */
data->level[count-1].arity = 0; data->level[count-1].arity = 0;
while (*pos == ' ') while (*pos == ' ' || *pos == '\n')
pos++; pos++;
if (!*pos) if (!*pos)
@ -912,7 +912,7 @@ hwloc_synthetic_insert_attached(struct hwloc_topology *topology,
hwloc_synthetic_set_attr(&attached->attr, child); hwloc_synthetic_set_attr(&attached->attr, child);
hwloc_insert_object_by_cpuset(topology, child); hwloc__insert_object_by_cpuset(topology, NULL, child, "synthetic:attached");
hwloc_synthetic_insert_attached(topology, data, attached->next, set); hwloc_synthetic_insert_attached(topology, data, attached->next, set);
} }
@ -964,7 +964,7 @@ hwloc__look_synthetic(struct hwloc_topology *topology,
hwloc_synthetic_set_attr(&curlevel->attr, obj); hwloc_synthetic_set_attr(&curlevel->attr, obj);
hwloc_insert_object_by_cpuset(topology, obj); hwloc__insert_object_by_cpuset(topology, NULL, obj, "synthetic");
} }
hwloc_synthetic_insert_attached(topology, data, curlevel->attached, set); hwloc_synthetic_insert_attached(topology, data, curlevel->attached, set);

View file

@ -93,9 +93,10 @@ typedef struct _GROUP_AFFINITY {
#endif #endif
#ifndef HAVE_PROCESSOR_RELATIONSHIP #ifndef HAVE_PROCESSOR_RELATIONSHIP
typedef struct _PROCESSOR_RELATIONSHIP { typedef struct HWLOC_PROCESSOR_RELATIONSHIP {
BYTE Flags; BYTE Flags;
BYTE Reserved[21]; BYTE EfficiencyClass; /* for RelationProcessorCore, higher means greater performance but less efficiency, only available in Win10+ */
BYTE Reserved[20];
WORD GroupCount; WORD GroupCount;
GROUP_AFFINITY GroupMask[ANYSIZE_ARRAY]; GROUP_AFFINITY GroupMask[ANYSIZE_ARRAY];
} PROCESSOR_RELATIONSHIP, *PPROCESSOR_RELATIONSHIP; } PROCESSOR_RELATIONSHIP, *PPROCESSOR_RELATIONSHIP;
@ -228,9 +229,12 @@ static PFN_VIRTUALFREEEX VirtualFreeExProc;
typedef BOOL (WINAPI *PFN_QUERYWORKINGSETEX)(HANDLE hProcess, PVOID pv, DWORD cb); typedef BOOL (WINAPI *PFN_QUERYWORKINGSETEX)(HANDLE hProcess, PVOID pv, DWORD cb);
static PFN_QUERYWORKINGSETEX QueryWorkingSetExProc; static PFN_QUERYWORKINGSETEX QueryWorkingSetExProc;
typedef NTSTATUS (WINAPI *PFN_RTLGETVERSION)(OSVERSIONINFOEX*);
PFN_RTLGETVERSION RtlGetVersionProc;
static void hwloc_win_get_function_ptrs(void) static void hwloc_win_get_function_ptrs(void)
{ {
HMODULE kernel32; HMODULE kernel32, ntdll;
#if HWLOC_HAVE_GCC_W_CAST_FUNCTION_TYPE #if HWLOC_HAVE_GCC_W_CAST_FUNCTION_TYPE
#pragma GCC diagnostic ignored "-Wcast-function-type" #pragma GCC diagnostic ignored "-Wcast-function-type"
@ -275,6 +279,9 @@ static void hwloc_win_get_function_ptrs(void)
QueryWorkingSetExProc = (PFN_QUERYWORKINGSETEX) GetProcAddress(psapi, "QueryWorkingSetEx"); QueryWorkingSetExProc = (PFN_QUERYWORKINGSETEX) GetProcAddress(psapi, "QueryWorkingSetEx");
} }
ntdll = GetModuleHandle("ntdll");
RtlGetVersionProc = (PFN_RTLGETVERSION) GetProcAddress(ntdll, "RtlGetVersion");
#if HWLOC_HAVE_GCC_W_CAST_FUNCTION_TYPE #if HWLOC_HAVE_GCC_W_CAST_FUNCTION_TYPE
#pragma GCC diagnostic warning "-Wcast-function-type" #pragma GCC diagnostic warning "-Wcast-function-type"
#endif #endif
@ -734,6 +741,88 @@ hwloc_win_get_area_memlocation(hwloc_topology_t topology __hwloc_attribute_unuse
} }
/*************************
* Efficiency classes
*/
struct hwloc_win_efficiency_classes {
unsigned nr_classes;
unsigned nr_classes_allocated;
struct hwloc_win_efficiency_class {
unsigned value;
hwloc_bitmap_t cpuset;
} *classes;
};
static void
hwloc_win_efficiency_classes_init(struct hwloc_win_efficiency_classes *classes)
{
classes->classes = NULL;
classes->nr_classes_allocated = 0;
classes->nr_classes = 0;
}
static int
hwloc_win_efficiency_classes_add(struct hwloc_win_efficiency_classes *classes,
hwloc_const_bitmap_t cpuset,
unsigned value)
{
unsigned i;
/* look for existing class with that efficiency value */
for(i=0; i<classes->nr_classes; i++) {
if (classes->classes[i].value == value) {
hwloc_bitmap_or(classes->classes[i].cpuset, classes->classes[i].cpuset, cpuset);
return 0;
}
}
/* extend the array if needed */
if (classes->nr_classes == classes->nr_classes_allocated) {
struct hwloc_win_efficiency_class *tmp;
unsigned new_nr_allocated = 2*classes->nr_classes_allocated;
if (!new_nr_allocated) {
#define HWLOC_WIN_EFFICIENCY_CLASSES_DEFAULT_MAX 4 /* 2 should be enough is most cases */
new_nr_allocated = HWLOC_WIN_EFFICIENCY_CLASSES_DEFAULT_MAX;
}
tmp = realloc(classes->classes, new_nr_allocated * sizeof(*classes->classes));
if (!tmp)
return -1;
classes->classes = tmp;
classes->nr_classes_allocated = new_nr_allocated;
}
/* add new class */
classes->classes[classes->nr_classes].cpuset = hwloc_bitmap_alloc();
if (!classes->classes[classes->nr_classes].cpuset)
return -1;
classes->classes[classes->nr_classes].value = value;
hwloc_bitmap_copy(classes->classes[classes->nr_classes].cpuset, cpuset);
classes->nr_classes++;
return 0;
}
static void
hwloc_win_efficiency_classes_register(hwloc_topology_t topology,
struct hwloc_win_efficiency_classes *classes)
{
unsigned i;
for(i=0; i<classes->nr_classes; i++) {
hwloc_internal_cpukinds_register(topology, classes->classes[i].cpuset, classes->classes[i].value, NULL, 0, 0);
classes->classes[i].cpuset = NULL; /* given to cpukinds */
}
}
static void
hwloc_win_efficiency_classes_destroy(struct hwloc_win_efficiency_classes *classes)
{
unsigned i;
for(i=0; i<classes->nr_classes; i++)
hwloc_bitmap_free(classes->classes[i].cpuset);
free(classes->classes);
}
/************************* /*************************
* discovery * discovery
*/ */
@ -753,6 +842,12 @@ hwloc_look_windows(struct hwloc_backend *backend, struct hwloc_disc_status *dsta
DWORD length; DWORD length;
int gotnuma = 0; int gotnuma = 0;
int gotnumamemory = 0; int gotnumamemory = 0;
OSVERSIONINFOEX osvi;
char versionstr[20];
char hostname[122] = "";
unsigned hostname_size = sizeof(hostname);
int has_efficiencyclass = 0;
struct hwloc_win_efficiency_classes eclasses;
assert(dstatus->phase == HWLOC_DISC_PHASE_CPU); assert(dstatus->phase == HWLOC_DISC_PHASE_CPU);
@ -760,6 +855,25 @@ hwloc_look_windows(struct hwloc_backend *backend, struct hwloc_disc_status *dsta
/* somebody discovered things */ /* somebody discovered things */
return -1; return -1;
ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
if (RtlGetVersionProc) {
/* RtlGetVersion() returns the currently-running Windows version */
RtlGetVersionProc(&osvi);
} else {
/* GetVersionEx() and isWindows10OrGreater() depend on what the manifest says
* (manifest of the program, not of libhwloc.dll), they may return old versions
* if the currently-running Windows is not listed in the manifest.
*/
GetVersionEx((LPOSVERSIONINFO)&osvi);
}
if (osvi.dwMajorVersion >= 10) {
has_efficiencyclass = 1;
hwloc_win_efficiency_classes_init(&eclasses);
}
hwloc_alloc_root_sets(topology->levels[0][0]); hwloc_alloc_root_sets(topology->levels[0][0]);
GetSystemInfo(&SystemInfo); GetSystemInfo(&SystemInfo);
@ -887,7 +1001,7 @@ hwloc_look_windows(struct hwloc_backend *backend, struct hwloc_disc_status *dsta
default: default:
break; break;
} }
hwloc_insert_object_by_cpuset(topology, obj); hwloc__insert_object_by_cpuset(topology, NULL, obj, "windows:GetLogicalProcessorInformation");
} }
free(procInfo); free(procInfo);
@ -919,6 +1033,7 @@ hwloc_look_windows(struct hwloc_backend *backend, struct hwloc_disc_status *dsta
(void*) procInfo < (void*) ((uintptr_t) procInfoTotal + length); (void*) procInfo < (void*) ((uintptr_t) procInfoTotal + length);
procInfo = (void*) ((uintptr_t) procInfo + procInfo->Size)) { procInfo = (void*) ((uintptr_t) procInfo + procInfo->Size)) {
unsigned num, i; unsigned num, i;
unsigned efficiency_class = 0;
GROUP_AFFINITY *GroupMask; GROUP_AFFINITY *GroupMask;
/* Ignore unknown caches */ /* Ignore unknown caches */
@ -953,6 +1068,11 @@ hwloc_look_windows(struct hwloc_backend *backend, struct hwloc_disc_status *dsta
type = HWLOC_OBJ_CORE; type = HWLOC_OBJ_CORE;
num = procInfo->Processor.GroupCount; num = procInfo->Processor.GroupCount;
GroupMask = procInfo->Processor.GroupMask; GroupMask = procInfo->Processor.GroupMask;
if (has_efficiencyclass)
/* the EfficiencyClass field didn't exist before Windows10 and recent MSVC headers,
* so just access it manually instead of trying to detect it.
*/
efficiency_class = * ((&procInfo->Processor.Flags) + 1);
break; break;
case RelationGroup: case RelationGroup:
/* So strange an interface... */ /* So strange an interface... */
@ -981,7 +1101,7 @@ hwloc_look_windows(struct hwloc_backend *backend, struct hwloc_disc_status *dsta
obj = hwloc_alloc_setup_object(topology, HWLOC_OBJ_GROUP, id); obj = hwloc_alloc_setup_object(topology, HWLOC_OBJ_GROUP, id);
obj->cpuset = set; obj->cpuset = set;
obj->attr->group.kind = HWLOC_GROUP_KIND_WINDOWS_PROCESSOR_GROUP; obj->attr->group.kind = HWLOC_GROUP_KIND_WINDOWS_PROCESSOR_GROUP;
hwloc_insert_object_by_cpuset(topology, obj); hwloc__insert_object_by_cpuset(topology, NULL, obj, "windows:GetLogicalProcessorInformation:ProcessorGroup");
} else } else
hwloc_bitmap_free(set); hwloc_bitmap_free(set);
} }
@ -1005,6 +1125,11 @@ hwloc_look_windows(struct hwloc_backend *backend, struct hwloc_disc_status *dsta
} }
hwloc_debug_2args_bitmap("%s#%u bitmap %s\n", hwloc_obj_type_string(type), id, obj->cpuset); hwloc_debug_2args_bitmap("%s#%u bitmap %s\n", hwloc_obj_type_string(type), id, obj->cpuset);
switch (type) { switch (type) {
case HWLOC_OBJ_CORE: {
if (has_efficiencyclass)
hwloc_win_efficiency_classes_add(&eclasses, obj->cpuset, efficiency_class);
break;
}
case HWLOC_OBJ_NUMANODE: case HWLOC_OBJ_NUMANODE:
{ {
ULONGLONG avail; ULONGLONG avail;
@ -1055,7 +1180,7 @@ hwloc_look_windows(struct hwloc_backend *backend, struct hwloc_disc_status *dsta
default: default:
break; break;
} }
hwloc_insert_object_by_cpuset(topology, obj); hwloc__insert_object_by_cpuset(topology, NULL, obj, "windows:GetLogicalProcessorInformationEx");
} }
free(procInfoTotal); free(procInfoTotal);
} }
@ -1076,29 +1201,88 @@ hwloc_look_windows(struct hwloc_backend *backend, struct hwloc_disc_status *dsta
hwloc_bitmap_only(obj->cpuset, idx); hwloc_bitmap_only(obj->cpuset, idx);
hwloc_debug_1arg_bitmap("cpu %u has cpuset %s\n", hwloc_debug_1arg_bitmap("cpu %u has cpuset %s\n",
idx, obj->cpuset); idx, obj->cpuset);
hwloc_insert_object_by_cpuset(topology, obj); hwloc__insert_object_by_cpuset(topology, NULL, obj, "windows:ProcessorGroup:pu");
} hwloc_bitmap_foreach_end(); } hwloc_bitmap_foreach_end();
hwloc_bitmap_free(groups_pu_set); hwloc_bitmap_free(groups_pu_set);
} else { } else {
/* no processor groups */ /* no processor groups */
SYSTEM_INFO sysinfo;
hwloc_obj_t obj; hwloc_obj_t obj;
unsigned idx; unsigned idx;
GetSystemInfo(&sysinfo);
for(idx=0; idx<32; idx++) for(idx=0; idx<32; idx++)
if (sysinfo.dwActiveProcessorMask & (((DWORD_PTR)1)<<idx)) { if (SystemInfo.dwActiveProcessorMask & (((DWORD_PTR)1)<<idx)) {
obj = hwloc_alloc_setup_object(topology, HWLOC_OBJ_PU, idx); obj = hwloc_alloc_setup_object(topology, HWLOC_OBJ_PU, idx);
obj->cpuset = hwloc_bitmap_alloc(); obj->cpuset = hwloc_bitmap_alloc();
hwloc_bitmap_only(obj->cpuset, idx); hwloc_bitmap_only(obj->cpuset, idx);
hwloc_debug_1arg_bitmap("cpu %u has cpuset %s\n", hwloc_debug_1arg_bitmap("cpu %u has cpuset %s\n",
idx, obj->cpuset); idx, obj->cpuset);
hwloc_insert_object_by_cpuset(topology, obj); hwloc__insert_object_by_cpuset(topology, NULL, obj, "windows:pu");
} }
} }
if (has_efficiencyclass) {
topology->support.discovery->cpukind_efficiency = 1;
hwloc_win_efficiency_classes_register(topology, &eclasses);
}
out: out:
if (has_efficiencyclass)
hwloc_win_efficiency_classes_destroy(&eclasses);
/* emulate uname instead of calling hwloc_add_uname_info() */
hwloc_obj_add_info(topology->levels[0][0], "Backend", "Windows"); hwloc_obj_add_info(topology->levels[0][0], "Backend", "Windows");
hwloc_add_uname_info(topology, NULL); hwloc_obj_add_info(topology->levels[0][0], "OSName", "Windows");
#if defined(__CYGWIN__)
hwloc_obj_add_info(topology->levels[0][0], "WindowsBuildEnvironment", "Cygwin");
#elif defined(__MINGW32__)
hwloc_obj_add_info(topology->levels[0][0], "WindowsBuildEnvironment", "MinGW");
#endif
/* see https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-osversioninfoexa */
if (osvi.dwMajorVersion == 10) {
if (osvi.dwMinorVersion == 0)
hwloc_obj_add_info(topology->levels[0][0], "OSRelease", "10");
} else if (osvi.dwMajorVersion == 6) {
if (osvi.dwMinorVersion == 3)
hwloc_obj_add_info(topology->levels[0][0], "OSRelease", "8.1"); /* or "Server 2012 R2" */
else if (osvi.dwMinorVersion == 2)
hwloc_obj_add_info(topology->levels[0][0], "OSRelease", "8"); /* or "Server 2012" */
else if (osvi.dwMinorVersion == 1)
hwloc_obj_add_info(topology->levels[0][0], "OSRelease", "7"); /* or "Server 2008 R2" */
else if (osvi.dwMinorVersion == 0)
hwloc_obj_add_info(topology->levels[0][0], "OSRelease", "Vista"); /* or "Server 2008" */
} /* earlier versions are ignored */
snprintf(versionstr, sizeof(versionstr), "%u.%u.%u", osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber);
hwloc_obj_add_info(topology->levels[0][0], "OSVersion", versionstr);
#if !defined(__CYGWIN__)
GetComputerName(hostname, &hostname_size);
#else
gethostname(hostname, hostname_size);
#endif
if (*hostname)
hwloc_obj_add_info(topology->levels[0][0], "Hostname", hostname);
/* convert to unix-like architecture strings */
switch (SystemInfo.wProcessorArchitecture) {
case 0:
hwloc_obj_add_info(topology->levels[0][0], "Architecture", "i686");
break;
case 9:
hwloc_obj_add_info(topology->levels[0][0], "Architecture", "x86_64");
break;
case 5:
hwloc_obj_add_info(topology->levels[0][0], "Architecture", "arm");
break;
case 12:
hwloc_obj_add_info(topology->levels[0][0], "Architecture", "arm64");
break;
case 6:
hwloc_obj_add_info(topology->levels[0][0], "Architecture", "ia64");
break;
}
return 0; return 0;
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright © 2010-2019 Inria. All rights reserved. * Copyright © 2010-2020 Inria. All rights reserved.
* Copyright © 2010-2013 Université Bordeaux * Copyright © 2010-2013 Université Bordeaux
* Copyright © 2010-2011 Cisco Systems, Inc. All rights reserved. * Copyright © 2010-2011 Cisco Systems, Inc. All rights reserved.
* See COPYING in top-level directory. * See COPYING in top-level directory.
@ -181,6 +181,7 @@ enum hwloc_x86_disc_flags {
#define has_topoext(features) ((features)[6] & (1 << 22)) #define has_topoext(features) ((features)[6] & (1 << 22))
#define has_x2apic(features) ((features)[4] & (1 << 21)) #define has_x2apic(features) ((features)[4] & (1 << 21))
#define has_hybrid(features) ((features)[18] & (1 << 15))
struct cacheinfo { struct cacheinfo {
hwloc_obj_cache_type_t type; hwloc_obj_cache_type_t type;
@ -217,6 +218,9 @@ struct procinfo {
unsigned cpustepping; unsigned cpustepping;
unsigned cpumodelnumber; unsigned cpumodelnumber;
unsigned cpufamilynumber; unsigned cpufamilynumber;
unsigned hybridcoretype;
unsigned hybridnativemodel;
}; };
enum cpuid_type { enum cpuid_type {
@ -681,6 +685,15 @@ static void look_proc(struct hwloc_backend *backend, struct procinfo *infos, uns
} }
} }
if (highest_cpuid >= 0x1a && has_hybrid(features)) {
/* Get hybrid cpu information from cpuid 0x1a */
eax = 0x1a;
ecx = 0;
cpuid_or_from_dump(&eax, &ebx, &ecx, &edx, src_cpuiddump);
infos->hybridcoretype = eax >> 24;
infos->hybridnativemodel = eax & 0xffffff;
}
/********************************************************************************* /*********************************************************************************
* Get the hierarchy of thread, core, die, package, etc. from CPU-specific leaves * Get the hierarchy of thread, core, die, package, etc. from CPU-specific leaves
*/ */
@ -751,7 +764,13 @@ static void look_proc(struct hwloc_backend *backend, struct procinfo *infos, uns
/* default cacheid value */ /* default cacheid value */
cache->cacheid = infos->apicid / cache->nbthreads_sharing; cache->cacheid = infos->apicid / cache->nbthreads_sharing;
if (cpuid_type == amd) { if (cpuid_type == intel) {
/* round nbthreads_sharing to nearest power of two to build a mask (for clearing lower bits) */
unsigned bits = hwloc_flsl(cache->nbthreads_sharing-1);
unsigned mask = ~((1U<<bits) - 1);
cache->cacheid = infos->apicid & mask;
} else if (cpuid_type == amd) {
/* AMD quirks */ /* AMD quirks */
if (infos->cpufamilynumber == 0x17 if (infos->cpufamilynumber == 0x17
&& cache->level == 3 && cache->nbthreads_sharing == 6) { && cache->level == 3 && cache->nbthreads_sharing == 6) {
@ -872,7 +891,7 @@ hwloc_x86_add_groups(hwloc_topology_t topology,
obj->attr->group.dont_merge = dont_merge; obj->attr->group.dont_merge = dont_merge;
hwloc_debug_2args_bitmap("os %s %u has cpuset %s\n", hwloc_debug_2args_bitmap("os %s %u has cpuset %s\n",
subtype, id, obj_cpuset); subtype, id, obj_cpuset);
hwloc_insert_object_by_cpuset(topology, obj); hwloc__insert_object_by_cpuset(topology, NULL, obj, "x86:group");
} }
} }
@ -930,7 +949,7 @@ static void summarize(struct hwloc_backend *backend, struct procinfo *infos, uns
hwloc_debug_1arg_bitmap("os package %u has cpuset %s\n", hwloc_debug_1arg_bitmap("os package %u has cpuset %s\n",
packageid, package_cpuset); packageid, package_cpuset);
hwloc_insert_object_by_cpuset(topology, package); hwloc__insert_object_by_cpuset(topology, NULL, package, "x86:package");
} else { } else {
/* Annotate packages previously-existing packages */ /* Annotate packages previously-existing packages */
@ -986,7 +1005,7 @@ static void summarize(struct hwloc_backend *backend, struct procinfo *infos, uns
hwloc_bitmap_set(node->nodeset, nodeid); hwloc_bitmap_set(node->nodeset, nodeid);
hwloc_debug_1arg_bitmap("os node %u has cpuset %s\n", hwloc_debug_1arg_bitmap("os node %u has cpuset %s\n",
nodeid, node_cpuset); nodeid, node_cpuset);
hwloc_insert_object_by_cpuset(topology, node); hwloc__insert_object_by_cpuset(topology, NULL, node, "x86:numa");
gotnuma++; gotnuma++;
} }
} }
@ -1033,7 +1052,7 @@ static void summarize(struct hwloc_backend *backend, struct procinfo *infos, uns
unknown_obj->attr->group.subkind = level; unknown_obj->attr->group.subkind = level;
hwloc_debug_2args_bitmap("os unknown%u %u has cpuset %s\n", hwloc_debug_2args_bitmap("os unknown%u %u has cpuset %s\n",
level, unknownid, unknown_cpuset); level, unknownid, unknown_cpuset);
hwloc_insert_object_by_cpuset(topology, unknown_obj); hwloc__insert_object_by_cpuset(topology, NULL, unknown_obj, "x86:group:unknown");
} }
} }
} }
@ -1073,7 +1092,7 @@ static void summarize(struct hwloc_backend *backend, struct procinfo *infos, uns
die->cpuset = die_cpuset; die->cpuset = die_cpuset;
hwloc_debug_1arg_bitmap("os die %u has cpuset %s\n", hwloc_debug_1arg_bitmap("os die %u has cpuset %s\n",
dieid, die_cpuset); dieid, die_cpuset);
hwloc_insert_object_by_cpuset(topology, die); hwloc__insert_object_by_cpuset(topology, NULL, die, "x86:die");
} }
} }
} }
@ -1111,7 +1130,7 @@ static void summarize(struct hwloc_backend *backend, struct procinfo *infos, uns
core->cpuset = core_cpuset; core->cpuset = core_cpuset;
hwloc_debug_1arg_bitmap("os core %u has cpuset %s\n", hwloc_debug_1arg_bitmap("os core %u has cpuset %s\n",
coreid, core_cpuset); coreid, core_cpuset);
hwloc_insert_object_by_cpuset(topology, core); hwloc__insert_object_by_cpuset(topology, NULL, core, "x86:core");
} }
} }
} }
@ -1125,7 +1144,7 @@ static void summarize(struct hwloc_backend *backend, struct procinfo *infos, uns
obj->cpuset = hwloc_bitmap_alloc(); obj->cpuset = hwloc_bitmap_alloc();
hwloc_bitmap_only(obj->cpuset, i); hwloc_bitmap_only(obj->cpuset, i);
hwloc_debug_1arg_bitmap("PU %u has cpuset %s\n", i, obj->cpuset); hwloc_debug_1arg_bitmap("PU %u has cpuset %s\n", i, obj->cpuset);
hwloc_insert_object_by_cpuset(topology, obj); hwloc__insert_object_by_cpuset(topology, NULL, obj, "x86:pu");
} }
} }
@ -1208,7 +1227,7 @@ static void summarize(struct hwloc_backend *backend, struct procinfo *infos, uns
hwloc_obj_add_info(cache, "Inclusive", infos[i].cache[l].inclusive ? "1" : "0"); hwloc_obj_add_info(cache, "Inclusive", infos[i].cache[l].inclusive ? "1" : "0");
hwloc_debug_2args_bitmap("os L%u cache %u has cpuset %s\n", hwloc_debug_2args_bitmap("os L%u cache %u has cpuset %s\n",
level, cacheid, cache_cpuset); level, cacheid, cache_cpuset);
hwloc_insert_object_by_cpuset(topology, cache); hwloc__insert_object_by_cpuset(topology, NULL, cache, "x86:cache");
} }
} }
} }
@ -1274,8 +1293,41 @@ look_procs(struct hwloc_backend *backend, struct procinfo *infos, unsigned long
hwloc_bitmap_free(orig_cpuset); hwloc_bitmap_free(orig_cpuset);
} }
if (data->apicid_unique) if (data->apicid_unique) {
summarize(backend, infos, flags); summarize(backend, infos, flags);
if (has_hybrid(features)) {
/* use hybrid info for cpukinds */
hwloc_bitmap_t atomset = hwloc_bitmap_alloc();
hwloc_bitmap_t coreset = hwloc_bitmap_alloc();
for(i=0; i<nbprocs; i++) {
if (infos[i].hybridcoretype == 0x20)
hwloc_bitmap_set(atomset, i);
else if (infos[i].hybridcoretype == 0x40)
hwloc_bitmap_set(coreset, i);
}
/* register IntelAtom set if any */
if (!hwloc_bitmap_iszero(atomset)) {
struct hwloc_info_s infoattr;
infoattr.name = (char *) "CoreType";
infoattr.value = (char *) "IntelAtom";
hwloc_internal_cpukinds_register(topology, atomset, HWLOC_CPUKIND_EFFICIENCY_UNKNOWN, &infoattr, 1, 0);
/* the cpuset is given to the callee */
} else {
hwloc_bitmap_free(atomset);
}
/* register IntelCore set if any */
if (!hwloc_bitmap_iszero(coreset)) {
struct hwloc_info_s infoattr;
infoattr.name = (char *) "CoreType";
infoattr.value = (char *) "IntelCore";
hwloc_internal_cpukinds_register(topology, coreset, HWLOC_CPUKIND_EFFICIENCY_UNKNOWN, &infoattr, 1, 0);
/* the cpuset is given to the callee */
} else {
hwloc_bitmap_free(coreset);
}
}
}
/* if !data->apicid_unique, do nothing and return success, so that the caller does nothing either */ /* if !data->apicid_unique, do nothing and return success, so that the caller does nothing either */
return 0; return 0;
@ -1354,7 +1406,7 @@ int hwloc_look_x86(struct hwloc_backend *backend, unsigned long flags)
unsigned highest_cpuid; unsigned highest_cpuid;
unsigned highest_ext_cpuid; unsigned highest_ext_cpuid;
/* This stores cpuid features with the same indexing as Linux */ /* This stores cpuid features with the same indexing as Linux */
unsigned features[10] = { 0 }; unsigned features[19] = { 0 };
struct procinfo *infos = NULL; struct procinfo *infos = NULL;
enum cpuid_type cpuid_type = unknown; enum cpuid_type cpuid_type = unknown;
hwloc_x86_os_state_t os_state; hwloc_x86_os_state_t os_state;
@ -1381,6 +1433,9 @@ int hwloc_look_x86(struct hwloc_backend *backend, unsigned long flags)
/* check if binding works */ /* check if binding works */
memset(&hooks, 0, sizeof(hooks)); memset(&hooks, 0, sizeof(hooks));
support.membind = &memsupport; support.membind = &memsupport;
/* We could just copy the main hooks (except in some corner cases),
* but the current overhead is negligible, so just always reget them.
*/
hwloc_set_native_binding_hooks(&hooks, &support); hwloc_set_native_binding_hooks(&hooks, &support);
if (hooks.get_thisthread_cpubind && hooks.set_thisthread_cpubind) { if (hooks.get_thisthread_cpubind && hooks.set_thisthread_cpubind) {
get_cpubind = hooks.get_thisthread_cpubind; get_cpubind = hooks.get_thisthread_cpubind;
@ -1451,6 +1506,7 @@ int hwloc_look_x86(struct hwloc_backend *backend, unsigned long flags)
ecx = 0; ecx = 0;
cpuid_or_from_dump(&eax, &ebx, &ecx, &edx, src_cpuiddump); cpuid_or_from_dump(&eax, &ebx, &ecx, &edx, src_cpuiddump);
features[9] = ebx; features[9] = ebx;
features[18] = edx;
} }
if (cpuid_type != intel && highest_ext_cpuid >= 0x80000001) { if (cpuid_type != intel && highest_ext_cpuid >= 0x80000001) {

View file

@ -213,7 +213,7 @@ hwloc__nolibxml_import_close_child(hwloc__xml_import_state_t state)
static int static int
hwloc__nolibxml_import_get_content(hwloc__xml_import_state_t state, hwloc__nolibxml_import_get_content(hwloc__xml_import_state_t state,
char **beginp, size_t expected_length) const char **beginp, size_t expected_length)
{ {
hwloc__nolibxml_import_state_data_t nstate = (void*) state->data; hwloc__nolibxml_import_state_data_t nstate = (void*) state->data;
char *buffer = nstate->tagbuffer; char *buffer = nstate->tagbuffer;
@ -224,7 +224,7 @@ hwloc__nolibxml_import_get_content(hwloc__xml_import_state_t state,
if (nstate->closed) { if (nstate->closed) {
if (expected_length) if (expected_length)
return -1; return -1;
*beginp = (char *) ""; *beginp = "";
return 0; return 0;
} }

View file

@ -1,7 +1,7 @@
/* /*
* Copyright © 2009 CNRS * Copyright © 2009 CNRS
* Copyright © 2009-2020 Inria. All rights reserved. * Copyright © 2009-2020 Inria. All rights reserved.
* Copyright © 2009-2011 Université Bordeaux * Copyright © 2009-2011, 2020 Université Bordeaux
* Copyright © 2009-2018 Cisco Systems, Inc. All rights reserved. * Copyright © 2009-2018 Cisco Systems, Inc. All rights reserved.
* See COPYING in top-level directory. * See COPYING in top-level directory.
*/ */
@ -481,11 +481,9 @@ hwloc__xml_import_object_attr(struct hwloc_topology *topology,
} }
} }
static int static int
hwloc__xml_import_info(struct hwloc_xml_backend_data_s *data, hwloc___xml_import_info(char **infonamep, char **infovaluep,
hwloc_obj_t obj, hwloc__xml_import_state_t state)
hwloc__xml_import_state_t state)
{ {
char *infoname = NULL; char *infoname = NULL;
char *infovalue = NULL; char *infovalue = NULL;
@ -502,6 +500,25 @@ hwloc__xml_import_info(struct hwloc_xml_backend_data_s *data,
return -1; return -1;
} }
*infonamep = infoname;
*infovaluep = infovalue;
return state->global->close_tag(state);
}
static int
hwloc__xml_import_obj_info(struct hwloc_xml_backend_data_s *data,
hwloc_obj_t obj,
hwloc__xml_import_state_t state)
{
char *infoname = NULL;
char *infovalue = NULL;
int err;
err = hwloc___xml_import_info(&infoname, &infovalue, state);
if (err < 0)
return err;
if (infoname) { if (infoname) {
/* empty strings are ignored by libxml */ /* empty strings are ignored by libxml */
if (data->version_major < 2 && if (data->version_major < 2 &&
@ -518,7 +535,7 @@ hwloc__xml_import_info(struct hwloc_xml_backend_data_s *data,
} }
} }
return state->global->close_tag(state); return err;
} }
static int static int
@ -694,14 +711,15 @@ hwloc__xml_import_userdata(hwloc_topology_t topology __hwloc_attribute_unused, h
} }
if (!topology->userdata_import_cb) { if (!topology->userdata_import_cb) {
char *buffer; const char *buffer;
size_t reallength = encoded ? BASE64_ENCODED_LENGTH(length) : length; size_t reallength = encoded ? BASE64_ENCODED_LENGTH(length) : length;
ret = state->global->get_content(state, &buffer, reallength); ret = state->global->get_content(state, &buffer, reallength);
if (ret < 0) if (ret < 0)
return -1; return -1;
} else if (topology->userdata_not_decoded) { } else if (topology->userdata_not_decoded) {
char *buffer, *fakename; const char *buffer;
char *fakename;
size_t reallength = encoded ? BASE64_ENCODED_LENGTH(length) : length; size_t reallength = encoded ? BASE64_ENCODED_LENGTH(length) : length;
ret = state->global->get_content(state, &buffer, reallength); ret = state->global->get_content(state, &buffer, reallength);
if (ret < 0) if (ret < 0)
@ -714,7 +732,7 @@ hwloc__xml_import_userdata(hwloc_topology_t topology __hwloc_attribute_unused, h
free(fakename); free(fakename);
} else if (encoded && length) { } else if (encoded && length) {
char *encoded_buffer; const char *encoded_buffer;
size_t encoded_length = BASE64_ENCODED_LENGTH(length); size_t encoded_length = BASE64_ENCODED_LENGTH(length);
ret = state->global->get_content(state, &encoded_buffer, encoded_length); ret = state->global->get_content(state, &encoded_buffer, encoded_length);
if (ret < 0) if (ret < 0)
@ -734,7 +752,7 @@ hwloc__xml_import_userdata(hwloc_topology_t topology __hwloc_attribute_unused, h
} }
} else { /* always handle length==0 in the non-encoded case */ } else { /* always handle length==0 in the non-encoded case */
char *buffer = (char *) ""; const char *buffer = "";
if (length) { if (length) {
ret = state->global->get_content(state, &buffer, length); ret = state->global->get_content(state, &buffer, length);
if (ret < 0) if (ret < 0)
@ -888,7 +906,7 @@ hwloc__xml_import_object(hwloc_topology_t topology,
} }
} else if (!strcmp(tag, "info")) { } else if (!strcmp(tag, "info")) {
ret = hwloc__xml_import_info(data, obj, &childstate); ret = hwloc__xml_import_obj_info(data, obj, &childstate);
} else if (data->version_major < 2 && !strcmp(tag, "distances")) { } else if (data->version_major < 2 && !strcmp(tag, "distances")) {
ret = hwloc__xml_v1import_distances(data, obj, &childstate); ret = hwloc__xml_v1import_distances(data, obj, &childstate);
} else if (!strcmp(tag, "userdata")) { } else if (!strcmp(tag, "userdata")) {
@ -1238,6 +1256,80 @@ hwloc__xml_import_object(hwloc_topology_t topology,
return -1; return -1;
} }
static int
hwloc__xml_v2import_support(hwloc_topology_t topology,
hwloc__xml_import_state_t state)
{
char *name = NULL;
int value = 1; /* value is optional */
while (1) {
char *attrname, *attrvalue;
if (state->global->next_attr(state, &attrname, &attrvalue) < 0)
break;
if (!strcmp(attrname, "name"))
name = attrvalue;
else if (!strcmp(attrname, "value"))
value = atoi(attrvalue);
else {
if (hwloc__xml_verbose())
fprintf(stderr, "%s: ignoring unknown support attribute %s\n",
state->global->msgprefix, attrname);
}
}
if (name && topology->flags & HWLOC_TOPOLOGY_FLAG_IMPORT_SUPPORT) {
#ifdef HWLOC_DEBUG
HWLOC_BUILD_ASSERT(sizeof(struct hwloc_topology_support) == 4*sizeof(void*));
HWLOC_BUILD_ASSERT(sizeof(struct hwloc_topology_discovery_support) == 6);
HWLOC_BUILD_ASSERT(sizeof(struct hwloc_topology_cpubind_support) == 11);
HWLOC_BUILD_ASSERT(sizeof(struct hwloc_topology_membind_support) == 15);
HWLOC_BUILD_ASSERT(sizeof(struct hwloc_topology_misc_support) == 1);
#endif
#define DO(_cat,_name) if (!strcmp(#_cat "." #_name, name)) topology->support._cat->_name = value
DO(discovery,pu);
else DO(discovery,numa);
else DO(discovery,numa_memory);
else DO(discovery,disallowed_pu);
else DO(discovery,disallowed_numa);
else DO(discovery,cpukind_efficiency);
else DO(cpubind,set_thisproc_cpubind);
else DO(cpubind,get_thisproc_cpubind);
else DO(cpubind,set_proc_cpubind);
else DO(cpubind,get_proc_cpubind);
else DO(cpubind,set_thisthread_cpubind);
else DO(cpubind,get_thisthread_cpubind);
else DO(cpubind,set_thread_cpubind);
else DO(cpubind,get_thread_cpubind);
else DO(cpubind,get_thisproc_last_cpu_location);
else DO(cpubind,get_proc_last_cpu_location);
else DO(cpubind,get_thisthread_last_cpu_location);
else DO(membind,set_thisproc_membind);
else DO(membind,get_thisproc_membind);
else DO(membind,set_proc_membind);
else DO(membind,get_proc_membind);
else DO(membind,set_thisthread_membind);
else DO(membind,get_thisthread_membind);
else DO(membind,set_area_membind);
else DO(membind,get_area_membind);
else DO(membind,alloc_membind);
else DO(membind,firsttouch_membind);
else DO(membind,bind_membind);
else DO(membind,interleave_membind);
else DO(membind,nexttouch_membind);
else DO(membind,migrate_membind);
else DO(membind,get_area_memlocation);
else if (!strcmp("custom.exported_support", name))
/* support was exported in a custom/fake field, mark it as imported here */
topology->support.misc->imported_support = 1;
#undef DO
}
return 0;
}
static int static int
hwloc__xml_v2import_distances(hwloc_topology_t topology, hwloc__xml_v2import_distances(hwloc_topology_t topology,
hwloc__xml_import_state_t state, hwloc__xml_import_state_t state,
@ -1317,7 +1409,8 @@ hwloc__xml_v2import_distances(hwloc_topology_t topology,
nr_u64values = 0; nr_u64values = 0;
while (1) { while (1) {
struct hwloc__xml_import_state_s childstate; struct hwloc__xml_import_state_s childstate;
char *attrname, *attrvalue, *tag, *buffer; char *attrname, *attrvalue, *tag;
const char *buffer;
int length; int length;
int is_index = 0; int is_index = 0;
int is_u64values = 0; int is_u64values = 0;
@ -1356,7 +1449,7 @@ hwloc__xml_v2import_distances(hwloc_topology_t topology,
if (is_index) { if (is_index) {
/* get indexes */ /* get indexes */
char *tmp, *tmp2; const char *tmp, *tmp2;
if (nr_indexes >= nbobjs) { if (nr_indexes >= nbobjs) {
if (hwloc__xml_verbose()) if (hwloc__xml_verbose())
fprintf(stderr, "%s: %s with more than %u indexes\n", fprintf(stderr, "%s: %s with more than %u indexes\n",
@ -1398,7 +1491,7 @@ hwloc__xml_v2import_distances(hwloc_topology_t topology,
} else if (is_u64values) { } else if (is_u64values) {
/* get uint64_t values */ /* get uint64_t values */
char *tmp; const char *tmp;
if (nr_u64values >= nbobjs*nbobjs) { if (nr_u64values >= nbobjs*nbobjs) {
if (hwloc__xml_verbose()) if (hwloc__xml_verbose())
fprintf(stderr, "%s: %s with more than %u u64values\n", fprintf(stderr, "%s: %s with more than %u u64values\n",
@ -1491,6 +1584,259 @@ hwloc__xml_v2import_distances(hwloc_topology_t topology,
#undef _TAG_NAME #undef _TAG_NAME
} }
static int
hwloc__xml_import_memattr_value(hwloc_topology_t topology,
hwloc_memattr_id_t id,
unsigned long flags,
hwloc__xml_import_state_t state)
{
char *target_obj_gp_index_s = NULL;
char *target_obj_type_s = NULL;
hwloc_uint64_t target_obj_gp_index;
char *value_s = NULL;
hwloc_uint64_t value;
char *initiator_cpuset_s = NULL;
char *initiator_obj_gp_index_s = NULL;
char *initiator_obj_type_s = NULL;
hwloc_obj_type_t target_obj_type = HWLOC_OBJ_TYPE_NONE;
while (1) {
char *attrname, *attrvalue;
if (state->global->next_attr(state, &attrname, &attrvalue) < 0)
break;
if (!strcmp(attrname, "target_obj_gp_index"))
target_obj_gp_index_s = attrvalue;
else if (!strcmp(attrname, "target_obj_type"))
target_obj_type_s = attrvalue;
else if (!strcmp(attrname, "value"))
value_s = attrvalue;
else if (!strcmp(attrname, "initiator_cpuset"))
initiator_cpuset_s = attrvalue;
else if (!strcmp(attrname, "initiator_obj_gp_index"))
initiator_obj_gp_index_s = attrvalue;
else if (!strcmp(attrname, "initiator_obj_type"))
initiator_obj_type_s = attrvalue;
else {
if (hwloc__xml_verbose())
fprintf(stderr, "%s: ignoring unknown memattr_value attribute %s\n",
state->global->msgprefix, attrname);
return -1;
}
}
if (!target_obj_type_s) {
if (hwloc__xml_verbose())
fprintf(stderr, "%s: ignoring memattr_value without target_obj_type.\n",
state->global->msgprefix);
return -1;
}
if (hwloc_type_sscanf(target_obj_type_s, &target_obj_type, NULL, 0) < 0) {
if (hwloc__xml_verbose())
fprintf(stderr, "%s: failed to identify memattr_value target object type %s\n",
state->global->msgprefix, target_obj_type_s);
return -1;
}
if (!value_s || !target_obj_gp_index_s) {
if (hwloc__xml_verbose())
fprintf(stderr, "%s: ignoring memattr_value without value and target_obj_gp_index\n",
state->global->msgprefix);
return -1;
}
target_obj_gp_index = strtoull(target_obj_gp_index_s, NULL, 10);
value = strtoull(value_s, NULL, 10);
if (flags & HWLOC_MEMATTR_FLAG_NEED_INITIATOR) {
/* add a value with initiator */
struct hwloc_internal_location_s loc;
if (!initiator_cpuset_s && (!initiator_obj_gp_index_s || !initiator_obj_type_s)) {
if (hwloc__xml_verbose())
fprintf(stderr, "%s: ignoring memattr_value without initiator attributes\n",
state->global->msgprefix);
return -1;
}
/* setup the initiator */
if (initiator_cpuset_s) {
loc.type = HWLOC_LOCATION_TYPE_CPUSET;
loc.location.cpuset = hwloc_bitmap_alloc();
if (!loc.location.cpuset) {
if (hwloc__xml_verbose())
fprintf(stderr, "%s: failed to allocated memattr_value initiator cpuset\n",
state->global->msgprefix);
return -1;
}
hwloc_bitmap_sscanf(loc.location.cpuset, initiator_cpuset_s);
} else {
loc.type = HWLOC_LOCATION_TYPE_OBJECT;
loc.location.object.gp_index = strtoull(initiator_obj_gp_index_s, NULL, 10);
if (hwloc_type_sscanf(initiator_obj_type_s, &loc.location.object.type, NULL, 0) < 0) {
if (hwloc__xml_verbose())
fprintf(stderr, "%s: failed to identify memattr_value initiator object type %s\n",
state->global->msgprefix, initiator_obj_type_s);
return -1;
}
}
hwloc_internal_memattr_set_value(topology, id, target_obj_type, target_obj_gp_index, (unsigned)-1, &loc, value);
if (loc.type == HWLOC_LOCATION_TYPE_CPUSET)
hwloc_bitmap_free(loc.location.cpuset);
} else {
/* add a value without initiator */
hwloc_internal_memattr_set_value(topology, id, target_obj_type, target_obj_gp_index, (unsigned)-1, NULL, value);
}
return 0;
}
static int
hwloc__xml_import_memattr(hwloc_topology_t topology,
hwloc__xml_import_state_t state)
{
char *name = NULL;
unsigned long flags = (unsigned long) -1;
hwloc_memattr_id_t id = (hwloc_memattr_id_t) -1;
int ret;
while (1) {
char *attrname, *attrvalue;
if (state->global->next_attr(state, &attrname, &attrvalue) < 0)
break;
if (!strcmp(attrname, "name"))
name = attrvalue;
else if (!strcmp(attrname, "flags"))
flags = strtoul(attrvalue, NULL, 10);
else {
if (hwloc__xml_verbose())
fprintf(stderr, "%s: ignoring unknown memattr attribute %s\n",
state->global->msgprefix, attrname);
return -1;
}
}
if (name && flags != (unsigned long) -1) {
hwloc_memattr_id_t _id;
ret = hwloc_memattr_get_by_name(topology, name, &_id);
if (ret < 0) {
/* register a new attribute */
ret = hwloc_memattr_register(topology, name, flags, &_id);
if (!ret)
id = _id;
} else {
/* check the flags of the existing attribute */
unsigned long mflags;
ret = hwloc_memattr_get_flags(topology, _id, &mflags);
if (!ret && mflags == flags)
id = _id;
}
/* if there's no matching attribute, id is -1 and values will be ignored below */
}
while (1) {
struct hwloc__xml_import_state_s childstate;
char *tag;
ret = state->global->find_child(state, &childstate, &tag);
if (ret <= 0)
break;
if (!strcmp(tag, "memattr_value")) {
ret = hwloc__xml_import_memattr_value(topology, id, flags, &childstate);
} else {
if (hwloc__xml_verbose())
fprintf(stderr, "%s: memattr with unrecognized child %s\n",
state->global->msgprefix, tag);
ret = -1;
}
if (ret < 0)
goto error;
state->global->close_child(&childstate);
}
return state->global->close_tag(state);
error:
return -1;
}
static int
hwloc__xml_import_cpukind(hwloc_topology_t topology,
hwloc__xml_import_state_t state)
{
hwloc_bitmap_t cpuset = NULL;
int forced_efficiency = HWLOC_CPUKIND_EFFICIENCY_UNKNOWN;
unsigned nr_infos = 0;
struct hwloc_info_s *infos = NULL;
int ret;
while (1) {
char *attrname, *attrvalue;
if (state->global->next_attr(state, &attrname, &attrvalue) < 0)
break;
if (!strcmp(attrname, "cpuset")) {
if (!cpuset)
cpuset = hwloc_bitmap_alloc();
hwloc_bitmap_sscanf(cpuset, attrvalue);
} else if (!strcmp(attrname, "forced_efficiency")) {
forced_efficiency = atoi(attrvalue);
} else {
if (hwloc__xml_verbose())
fprintf(stderr, "%s: ignoring unknown cpukind attribute %s\n",
state->global->msgprefix, attrname);
hwloc_bitmap_free(cpuset);
return -1;
}
}
while (1) {
struct hwloc__xml_import_state_s childstate;
char *tag;
ret = state->global->find_child(state, &childstate, &tag);
if (ret <= 0)
break;
if (!strcmp(tag, "info")) {
char *infoname = NULL;
char *infovalue = NULL;
ret = hwloc___xml_import_info(&infoname, &infovalue, &childstate);
if (!ret && infoname && infovalue)
hwloc__add_info(&infos, &nr_infos, infoname, infovalue);
} else {
if (hwloc__xml_verbose())
fprintf(stderr, "%s: cpukind with unrecognized child %s\n",
state->global->msgprefix, tag);
ret = -1;
}
if (ret < 0)
goto error;
state->global->close_child(&childstate);
}
if (!cpuset) {
if (hwloc__xml_verbose())
fprintf(stderr, "%s: ignoring cpukind without cpuset\n",
state->global->msgprefix);
goto error;
}
hwloc_internal_cpukinds_register(topology, cpuset, forced_efficiency, infos, nr_infos, HWLOC_CPUKINDS_REGISTER_FLAG_OVERWRITE_FORCED_EFFICIENCY);
return state->global->close_tag(state);
error:
hwloc__free_infos(infos, nr_infos);
hwloc_bitmap_free(cpuset);
return -1;
}
static int static int
hwloc__xml_import_diff_one(hwloc__xml_import_state_t state, hwloc__xml_import_diff_one(hwloc__xml_import_state_t state,
hwloc_topology_diff_t *firstdiffp, hwloc_topology_diff_t *firstdiffp,
@ -1759,6 +2105,18 @@ hwloc_look_xml(struct hwloc_backend *backend, struct hwloc_disc_status *dstatus)
ret = hwloc__xml_v2import_distances(topology, &childstate, 1); ret = hwloc__xml_v2import_distances(topology, &childstate, 1);
if (ret < 0) if (ret < 0)
goto failed; goto failed;
} else if (!strcmp(tag, "support")) {
ret = hwloc__xml_v2import_support(topology, &childstate);
if (ret < 0)
goto failed;
} else if (!strcmp(tag, "memattr")) {
ret = hwloc__xml_import_memattr(topology, &childstate);
if (ret < 0)
goto failed;
} else if (!strcmp(tag, "cpukind")) {
ret = hwloc__xml_import_cpukind(topology, &childstate);
if (ret < 0)
goto failed;
} else { } else {
if (hwloc__xml_verbose()) if (hwloc__xml_verbose())
fprintf(stderr, "%s: ignoring unknown tag `%s' after root object.\n", fprintf(stderr, "%s: ignoring unknown tag `%s' after root object.\n",
@ -1864,12 +2222,14 @@ done:
/* keep the "Backend" information intact */ /* keep the "Backend" information intact */
/* we could add "BackendSource=XML" to notify that XML was used between the actual backend and here */ /* we could add "BackendSource=XML" to notify that XML was used between the actual backend and here */
topology->support.discovery->pu = 1; if (!(topology->flags & HWLOC_TOPOLOGY_FLAG_IMPORT_SUPPORT)) {
topology->support.discovery->disallowed_pu = 1; topology->support.discovery->pu = 1;
if (data->nbnumanodes) { topology->support.discovery->disallowed_pu = 1;
topology->support.discovery->numa = 1; if (data->nbnumanodes) {
topology->support.discovery->numa_memory = 1; // FIXME topology->support.discovery->numa = 1;
topology->support.discovery->disallowed_numa = 1; topology->support.discovery->numa_memory = 1; // FIXME
topology->support.discovery->disallowed_numa = 1;
}
} }
if (data->look_done) if (data->look_done)
@ -2620,9 +2980,199 @@ hwloc__xml_v2export_distances(hwloc__xml_export_state_t parentstate, hwloc_topol
hwloc___xml_v2export_distances(parentstate, dist); hwloc___xml_v2export_distances(parentstate, dist);
} }
static void
hwloc__xml_v2export_support(hwloc__xml_export_state_t parentstate, hwloc_topology_t topology)
{
struct hwloc__xml_export_state_s state;
char tmp[11];
#ifdef HWLOC_DEBUG
HWLOC_BUILD_ASSERT(sizeof(struct hwloc_topology_support) == 4*sizeof(void*));
HWLOC_BUILD_ASSERT(sizeof(struct hwloc_topology_discovery_support) == 6);
HWLOC_BUILD_ASSERT(sizeof(struct hwloc_topology_cpubind_support) == 11);
HWLOC_BUILD_ASSERT(sizeof(struct hwloc_topology_membind_support) == 15);
HWLOC_BUILD_ASSERT(sizeof(struct hwloc_topology_misc_support) == 1);
#endif
#define DO(_cat,_name) do { \
if (topology->support._cat->_name) { \
parentstate->new_child(parentstate, &state, "support"); \
state.new_prop(&state, "name", #_cat "." #_name); \
if (topology->support._cat->_name != 1) { \
sprintf(tmp, "%u", topology->support._cat->_name); \
state.new_prop(&state, "value", tmp); \
} \
state.end_object(&state, "support"); \
} \
} while (0)
DO(discovery,pu);
DO(discovery,numa);
DO(discovery,numa_memory);
DO(discovery,disallowed_pu);
DO(discovery,disallowed_numa);
DO(discovery,cpukind_efficiency);
DO(cpubind,set_thisproc_cpubind);
DO(cpubind,get_thisproc_cpubind);
DO(cpubind,set_proc_cpubind);
DO(cpubind,get_proc_cpubind);
DO(cpubind,set_thisthread_cpubind);
DO(cpubind,get_thisthread_cpubind);
DO(cpubind,set_thread_cpubind);
DO(cpubind,get_thread_cpubind);
DO(cpubind,get_thisproc_last_cpu_location);
DO(cpubind,get_proc_last_cpu_location);
DO(cpubind,get_thisthread_last_cpu_location);
DO(membind,set_thisproc_membind);
DO(membind,get_thisproc_membind);
DO(membind,set_proc_membind);
DO(membind,get_proc_membind);
DO(membind,set_thisthread_membind);
DO(membind,get_thisthread_membind);
DO(membind,set_area_membind);
DO(membind,get_area_membind);
DO(membind,alloc_membind);
DO(membind,firsttouch_membind);
DO(membind,bind_membind);
DO(membind,interleave_membind);
DO(membind,nexttouch_membind);
DO(membind,migrate_membind);
DO(membind,get_area_memlocation);
/* misc.imported_support would be meaningless in the remote importer,
* but the importer needs to know whether we exported support or not
* (in case there are no support bit set at all),
* use a custom/fake field to do so.
*/
parentstate->new_child(parentstate, &state, "support");
state.new_prop(&state, "name", "custom.exported_support");
state.end_object(&state, "support");
#undef DO
}
static void
hwloc__xml_export_memattr_target(hwloc__xml_export_state_t state,
struct hwloc_internal_memattr_s *imattr,
struct hwloc_internal_memattr_target_s *imtg)
{
struct hwloc__xml_export_state_s vstate;
char tmp[255];
if (imattr->flags & HWLOC_MEMATTR_FLAG_NEED_INITIATOR) {
/* export all initiators */
unsigned k;
for(k=0; k<imtg->nr_initiators; k++) {
struct hwloc_internal_memattr_initiator_s *imi = &imtg->initiators[k];
state->new_child(state, &vstate, "memattr_value");
vstate.new_prop(&vstate, "target_obj_type", hwloc_obj_type_string(imtg->type));
snprintf(tmp, sizeof(tmp), "%llu", (unsigned long long) imtg->gp_index);
vstate.new_prop(&vstate, "target_obj_gp_index", tmp);
snprintf(tmp, sizeof(tmp), "%llu", (unsigned long long) imi->value);
vstate.new_prop(&vstate, "value", tmp);
switch (imi->initiator.type) {
case HWLOC_LOCATION_TYPE_OBJECT:
snprintf(tmp, sizeof(tmp), "%llu", (unsigned long long) imi->initiator.location.object.gp_index);
vstate.new_prop(&vstate, "initiator_obj_gp_index", tmp);
vstate.new_prop(&vstate, "initiator_obj_type", hwloc_obj_type_string(imi->initiator.location.object.type));
break;
case HWLOC_LOCATION_TYPE_CPUSET: {
char *setstring;
hwloc_bitmap_asprintf(&setstring, imi->initiator.location.cpuset);
if (setstring)
vstate.new_prop(&vstate, "initiator_cpuset", setstring);
free(setstring);
break;
}
default:
assert(0);
}
vstate.end_object(&vstate, "memattr_value");
}
} else {
/* just export the global value */
state->new_child(state, &vstate, "memattr_value");
vstate.new_prop(&vstate, "target_obj_type", hwloc_obj_type_string(imtg->type));
snprintf(tmp, sizeof(tmp), "%llu", (unsigned long long) imtg->gp_index);
vstate.new_prop(&vstate, "target_obj_gp_index", tmp);
snprintf(tmp, sizeof(tmp), "%llu", (unsigned long long) imtg->noinitiator_value);
vstate.new_prop(&vstate, "value", tmp);
vstate.end_object(&vstate, "memattr_value");
}
}
static void
hwloc__xml_export_memattrs(hwloc__xml_export_state_t state, hwloc_topology_t topology)
{
unsigned id;
for(id=0; id<topology->nr_memattrs; id++) {
struct hwloc_internal_memattr_s *imattr;
struct hwloc__xml_export_state_s mstate;
char tmp[255];
unsigned j;
if (id == HWLOC_MEMATTR_ID_CAPACITY || id == HWLOC_MEMATTR_ID_LOCALITY)
/* no need to export virtual memattrs */
continue;
imattr = &topology->memattrs[id];
if ((id == HWLOC_MEMATTR_ID_LATENCY || id == HWLOC_MEMATTR_ID_BANDWIDTH)
&& !imattr->nr_targets)
/* no need to export target-less attributes for initial attributes, no release support attributes without those definitions */
continue;
state->new_child(state, &mstate, "memattr");
mstate.new_prop(&mstate, "name", imattr->name);
snprintf(tmp, sizeof(tmp), "%lu", imattr->flags);
mstate.new_prop(&mstate, "flags", tmp);
for(j=0; j<imattr->nr_targets; j++)
hwloc__xml_export_memattr_target(&mstate, imattr, &imattr->targets[j]);
mstate.end_object(&mstate, "memattr");
}
}
static void
hwloc__xml_export_cpukinds(hwloc__xml_export_state_t state, hwloc_topology_t topology)
{
unsigned i;
for(i=0; i<topology->nr_cpukinds; i++) {
struct hwloc_internal_cpukind_s *kind = &topology->cpukinds[i];
struct hwloc__xml_export_state_s cstate;
char *setstring;
unsigned j;
state->new_child(state, &cstate, "cpukind");
hwloc_bitmap_asprintf(&setstring, kind->cpuset);
cstate.new_prop(&cstate, "cpuset", setstring);
free(setstring);
if (kind->forced_efficiency != HWLOC_CPUKIND_EFFICIENCY_UNKNOWN) {
char tmp[11];
snprintf(tmp, sizeof(tmp), "%d", kind->forced_efficiency);
cstate.new_prop(&cstate, "forced_efficiency", tmp);
}
for(j=0; j<kind->nr_infos; j++) {
char *name = hwloc__xml_export_safestrdup(kind->infos[j].name);
char *value = hwloc__xml_export_safestrdup(kind->infos[j].value);
struct hwloc__xml_export_state_s istate;
cstate.new_child(&cstate, &istate, "info");
istate.new_prop(&istate, "name", name);
istate.new_prop(&istate, "value", value);
istate.end_object(&istate, "info");
free(name);
free(value);
}
cstate.end_object(&cstate, "cpukind");
}
}
void void
hwloc__xml_export_topology(hwloc__xml_export_state_t state, hwloc_topology_t topology, unsigned long flags) hwloc__xml_export_topology(hwloc__xml_export_state_t state, hwloc_topology_t topology, unsigned long flags)
{ {
char *env;
hwloc_obj_t root = hwloc_get_root_obj(topology); hwloc_obj_t root = hwloc_get_root_obj(topology);
if (flags & HWLOC_TOPOLOGY_EXPORT_XML_FLAG_V1) { if (flags & HWLOC_TOPOLOGY_EXPORT_XML_FLAG_V1) {
@ -2665,6 +3215,11 @@ hwloc__xml_export_topology(hwloc__xml_export_state_t state, hwloc_topology_t top
} else { } else {
hwloc__xml_v2export_object (state, topology, root, flags); hwloc__xml_v2export_object (state, topology, root, flags);
hwloc__xml_v2export_distances (state, topology); hwloc__xml_v2export_distances (state, topology);
env = getenv("HWLOC_XML_EXPORT_SUPPORT");
if (!env || atoi(env))
hwloc__xml_v2export_support(state, topology);
hwloc__xml_export_memattrs(state, topology);
hwloc__xml_export_cpukinds(state, topology);
} }
} }

View file

@ -1,6 +1,6 @@
/* /*
* Copyright © 2009 CNRS * Copyright © 2009 CNRS
* Copyright © 2009-2019 Inria. All rights reserved. * Copyright © 2009-2020 Inria. All rights reserved.
* Copyright © 2009-2012, 2020 Université Bordeaux * Copyright © 2009-2012, 2020 Université Bordeaux
* Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved. * Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved.
* See COPYING in top-level directory. * See COPYING in top-level directory.
@ -75,16 +75,49 @@ int hwloc_hide_errors(void)
return hide; return hide;
} }
void hwloc_report_os_error(const char *msg, int line)
/* format the obj info to print in error messages */
static void
report_insert_error_format_obj(char *buf, size_t buflen, hwloc_obj_t obj)
{
char typestr[64];
char *cpusetstr;
char *nodesetstr = NULL;
hwloc_obj_type_snprintf(typestr, sizeof(typestr), obj, 0);
hwloc_bitmap_asprintf(&cpusetstr, obj->cpuset);
if (obj->nodeset) /* may be missing during insert */
hwloc_bitmap_asprintf(&nodesetstr, obj->nodeset);
if (obj->os_index != HWLOC_UNKNOWN_INDEX)
snprintf(buf, buflen, "%s (P#%u cpuset %s%s%s)",
typestr, obj->os_index, cpusetstr,
nodesetstr ? " nodeset " : "",
nodesetstr ? nodesetstr : "");
else
snprintf(buf, buflen, "%s (cpuset %s%s%s)",
typestr, cpusetstr,
nodesetstr ? " nodeset " : "",
nodesetstr ? nodesetstr : "");
free(cpusetstr);
free(nodesetstr);
}
static void report_insert_error(hwloc_obj_t new, hwloc_obj_t old, const char *msg, const char *reason)
{ {
static int reported = 0; static int reported = 0;
if (!reported && !hwloc_hide_errors()) { if (reason && !reported && !hwloc_hide_errors()) {
char newstr[512];
char oldstr[512];
report_insert_error_format_obj(newstr, sizeof(newstr), new);
report_insert_error_format_obj(oldstr, sizeof(oldstr), old);
fprintf(stderr, "****************************************************************************\n"); fprintf(stderr, "****************************************************************************\n");
fprintf(stderr, "* hwloc %s received invalid information from the operating system.\n", HWLOC_VERSION); fprintf(stderr, "* hwloc %s received invalid information from the operating system.\n", HWLOC_VERSION);
fprintf(stderr, "*\n"); fprintf(stderr, "*\n");
fprintf(stderr, "* %s\n", msg); fprintf(stderr, "* Failed with: %s\n", msg);
fprintf(stderr, "* Error occurred in topology.c line %d\n", line); fprintf(stderr, "* while inserting %s at %s\n", newstr, oldstr);
fprintf(stderr, "* coming from: %s\n", reason);
fprintf(stderr, "*\n"); fprintf(stderr, "*\n");
fprintf(stderr, "* The following FAQ entry in the hwloc documentation may help:\n"); fprintf(stderr, "* The following FAQ entry in the hwloc documentation may help:\n");
fprintf(stderr, "* What should I do when hwloc reports \"operating system\" warnings?\n"); fprintf(stderr, "* What should I do when hwloc reports \"operating system\" warnings?\n");
@ -264,7 +297,7 @@ hwloc_setup_pu_level(struct hwloc_topology *topology,
hwloc_debug_2args_bitmap("cpu %u (os %u) has cpuset %s\n", hwloc_debug_2args_bitmap("cpu %u (os %u) has cpuset %s\n",
cpu, oscpu, obj->cpuset); cpu, oscpu, obj->cpuset);
hwloc_insert_object_by_cpuset(topology, obj); hwloc__insert_object_by_cpuset(topology, NULL, obj, "core:pulevel");
cpu++; cpu++;
} }
@ -347,16 +380,18 @@ hwloc_debug_print_object(int indent __hwloc_attribute_unused, hwloc_obj_t obj)
static void static void
hwloc_debug_print_objects(int indent __hwloc_attribute_unused, hwloc_obj_t obj) hwloc_debug_print_objects(int indent __hwloc_attribute_unused, hwloc_obj_t obj)
{ {
hwloc_obj_t child; if (hwloc_debug_enabled() >= 2) {
hwloc_debug_print_object(indent, obj); hwloc_obj_t child;
for_each_child (child, obj) hwloc_debug_print_object(indent, obj);
hwloc_debug_print_objects(indent + 1, child); for_each_child (child, obj)
for_each_memory_child (child, obj) hwloc_debug_print_objects(indent + 1, child);
hwloc_debug_print_objects(indent + 1, child); for_each_memory_child (child, obj)
for_each_io_child (child, obj) hwloc_debug_print_objects(indent + 1, child);
hwloc_debug_print_objects(indent + 1, child); for_each_io_child (child, obj)
for_each_misc_child (child, obj) hwloc_debug_print_objects(indent + 1, child);
hwloc_debug_print_objects(indent + 1, child); for_each_misc_child (child, obj)
hwloc_debug_print_objects(indent + 1, child);
}
} }
#else /* !HWLOC_DEBUG */ #else /* !HWLOC_DEBUG */
#define hwloc_debug_print_object(indent, obj) do { /* nothing */ } while (0) #define hwloc_debug_print_object(indent, obj) do { /* nothing */ } while (0)
@ -472,29 +507,33 @@ int hwloc_obj_add_info(hwloc_obj_t obj, const char *name, const char *value)
} }
/* This function may be called with topology->tma set, it cannot free() or realloc() */ /* This function may be called with topology->tma set, it cannot free() or realloc() */
static int hwloc__tma_dup_infos(struct hwloc_tma *tma, hwloc_obj_t new, hwloc_obj_t src) int hwloc__tma_dup_infos(struct hwloc_tma *tma,
struct hwloc_info_s **newip, unsigned *newcp,
struct hwloc_info_s *oldi, unsigned oldc)
{ {
struct hwloc_info_s *newi;
unsigned i, j; unsigned i, j;
new->infos = hwloc_tma_calloc(tma, src->infos_count * sizeof(*src->infos)); newi = hwloc_tma_calloc(tma, oldc * sizeof(*newi));
if (!new->infos) if (!newi)
return -1; return -1;
for(i=0; i<src->infos_count; i++) { for(i=0; i<oldc; i++) {
new->infos[i].name = hwloc_tma_strdup(tma, src->infos[i].name); newi[i].name = hwloc_tma_strdup(tma, oldi[i].name);
new->infos[i].value = hwloc_tma_strdup(tma, src->infos[i].value); newi[i].value = hwloc_tma_strdup(tma, oldi[i].value);
if (!new->infos[i].name || !new->infos[i].value) if (!newi[i].name || !newi[i].value)
goto failed; goto failed;
} }
new->infos_count = src->infos_count; *newip = newi;
*newcp = oldc;
return 0; return 0;
failed: failed:
assert(!tma || !tma->dontfree); /* this tma cannot fail to allocate */ assert(!tma || !tma->dontfree); /* this tma cannot fail to allocate */
for(j=0; j<=i; j++) { for(j=0; j<=i; j++) {
free(new->infos[i].name); free(newi[i].name);
free(new->infos[i].value); free(newi[i].value);
} }
free(new->infos); free(newi);
new->infos = NULL; *newip = NULL;
return -1; return -1;
} }
@ -812,7 +851,7 @@ hwloc__duplicate_object(struct hwloc_topology *newtopology,
newobj->nodeset = hwloc_bitmap_tma_dup(tma, src->nodeset); newobj->nodeset = hwloc_bitmap_tma_dup(tma, src->nodeset);
newobj->complete_nodeset = hwloc_bitmap_tma_dup(tma, src->complete_nodeset); newobj->complete_nodeset = hwloc_bitmap_tma_dup(tma, src->complete_nodeset);
hwloc__tma_dup_infos(tma, newobj, src); hwloc__tma_dup_infos(tma, &newobj->infos, &newobj->infos_count, src->infos, src->infos_count);
/* find our level */ /* find our level */
if (src->depth < 0) { if (src->depth < 0) {
@ -970,6 +1009,7 @@ hwloc__topology_dup(hwloc_topology_t *newp,
memcpy(new->support.discovery, old->support.discovery, sizeof(*old->support.discovery)); memcpy(new->support.discovery, old->support.discovery, sizeof(*old->support.discovery));
memcpy(new->support.cpubind, old->support.cpubind, sizeof(*old->support.cpubind)); memcpy(new->support.cpubind, old->support.cpubind, sizeof(*old->support.cpubind));
memcpy(new->support.membind, old->support.membind, sizeof(*old->support.membind)); memcpy(new->support.membind, old->support.membind, sizeof(*old->support.membind));
memcpy(new->support.misc, old->support.misc, sizeof(*old->support.misc));
new->allowed_cpuset = hwloc_bitmap_tma_dup(tma, old->allowed_cpuset); new->allowed_cpuset = hwloc_bitmap_tma_dup(tma, old->allowed_cpuset);
new->allowed_nodeset = hwloc_bitmap_tma_dup(tma, old->allowed_nodeset); new->allowed_nodeset = hwloc_bitmap_tma_dup(tma, old->allowed_nodeset);
@ -1008,6 +1048,14 @@ hwloc__topology_dup(hwloc_topology_t *newp,
if (err < 0) if (err < 0)
goto out_with_topology; goto out_with_topology;
err = hwloc_internal_memattrs_dup(new, old);
if (err < 0)
goto out_with_topology;
err = hwloc_internal_cpukinds_dup(new, old);
if (err < 0)
goto out_with_topology;
/* we connected everything during duplication */ /* we connected everything during duplication */
new->modified = 0; new->modified = 0;
@ -1229,31 +1277,6 @@ hwloc__object_cpusets_compare_first(hwloc_obj_t obj1, hwloc_obj_t obj2)
return 0; return 0;
} }
/* format the obj info to print in error messages */
static void
hwloc__report_error_format_obj(char *buf, size_t buflen, hwloc_obj_t obj)
{
char typestr[64];
char *cpusetstr;
char *nodesetstr = NULL;
hwloc_obj_type_snprintf(typestr, sizeof(typestr), obj, 0);
hwloc_bitmap_asprintf(&cpusetstr, obj->cpuset);
if (obj->nodeset) /* may be missing during insert */
hwloc_bitmap_asprintf(&nodesetstr, obj->nodeset);
if (obj->os_index != HWLOC_UNKNOWN_INDEX)
snprintf(buf, buflen, "%s (P#%u cpuset %s%s%s)",
typestr, obj->os_index, cpusetstr,
nodesetstr ? " nodeset " : "",
nodesetstr ? nodesetstr : "");
else
snprintf(buf, buflen, "%s (cpuset %s%s%s)",
typestr, cpusetstr,
nodesetstr ? " nodeset " : "",
nodesetstr ? nodesetstr : "");
free(cpusetstr);
free(nodesetstr);
}
/* /*
* How to insert objects into the topology. * How to insert objects into the topology.
* *
@ -1390,9 +1413,9 @@ hwloc__insert_try_merge_group(hwloc_obj_t old, hwloc_obj_t new)
*/ */
static struct hwloc_obj * static struct hwloc_obj *
hwloc___insert_object_by_cpuset(struct hwloc_topology *topology, hwloc_obj_t cur, hwloc_obj_t obj, hwloc___insert_object_by_cpuset(struct hwloc_topology *topology, hwloc_obj_t cur, hwloc_obj_t obj,
hwloc_report_error_t report_error) const char *reason)
{ {
hwloc_obj_t child, next_child = NULL; hwloc_obj_t child, next_child = NULL, tmp;
/* These will always point to the pointer to their next last child. */ /* These will always point to the pointer to their next last child. */
hwloc_obj_t *cur_children = &cur->first_child; hwloc_obj_t *cur_children = &cur->first_child;
hwloc_obj_t *obj_children = &obj->first_child; hwloc_obj_t *obj_children = &obj->first_child;
@ -1430,18 +1453,10 @@ hwloc___insert_object_by_cpuset(struct hwloc_topology *topology, hwloc_obj_t cur
case HWLOC_OBJ_INCLUDED: case HWLOC_OBJ_INCLUDED:
/* OBJ is strictly contained is some child of CUR, go deeper. */ /* OBJ is strictly contained is some child of CUR, go deeper. */
return hwloc___insert_object_by_cpuset(topology, child, obj, report_error); return hwloc___insert_object_by_cpuset(topology, child, obj, reason);
case HWLOC_OBJ_INTERSECTS: case HWLOC_OBJ_INTERSECTS:
if (report_error) { report_insert_error(obj, child, "intersection without inclusion", reason);
char childstr[512];
char objstr[512];
char msg[1100];
hwloc__report_error_format_obj(objstr, sizeof(objstr), obj);
hwloc__report_error_format_obj(childstr, sizeof(childstr), child);
snprintf(msg, sizeof(msg), "%s intersects with %s without inclusion!", objstr, childstr);
report_error(msg, __LINE__);
}
goto putback; goto putback;
case HWLOC_OBJ_DIFFERENT: case HWLOC_OBJ_DIFFERENT:
@ -1464,6 +1479,8 @@ hwloc___insert_object_by_cpuset(struct hwloc_topology *topology, hwloc_obj_t cur
if (setres == HWLOC_OBJ_EQUAL) { if (setres == HWLOC_OBJ_EQUAL) {
obj->memory_first_child = child->memory_first_child; obj->memory_first_child = child->memory_first_child;
child->memory_first_child = NULL; child->memory_first_child = NULL;
for(tmp=obj->memory_first_child; tmp; tmp = tmp->next_sibling)
tmp->parent = obj;
} }
break; break;
} }
@ -1483,7 +1500,9 @@ hwloc___insert_object_by_cpuset(struct hwloc_topology *topology, hwloc_obj_t cur
return obj; return obj;
putback: putback:
/* Put-back OBJ children in CUR and return an error. */ /* OBJ cannot be inserted.
* Put-back OBJ children in CUR and return an error.
*/
if (putp) if (putp)
cur_children = putp; /* No need to try to insert before where OBJ was supposed to go */ cur_children = putp; /* No need to try to insert before where OBJ was supposed to go */
else else
@ -1492,12 +1511,12 @@ hwloc___insert_object_by_cpuset(struct hwloc_topology *topology, hwloc_obj_t cur
while ((child = obj->first_child) != NULL) { while ((child = obj->first_child) != NULL) {
/* Remove from OBJ */ /* Remove from OBJ */
obj->first_child = child->next_sibling; obj->first_child = child->next_sibling;
obj->parent = cur; /* Find child position in CUR, and reinsert it. */
/* Find child position in CUR, and insert. */
while (*cur_children && hwloc__object_cpusets_compare_first(*cur_children, child) < 0) while (*cur_children && hwloc__object_cpusets_compare_first(*cur_children, child) < 0)
cur_children = &(*cur_children)->next_sibling; cur_children = &(*cur_children)->next_sibling;
child->next_sibling = *cur_children; child->next_sibling = *cur_children;
*cur_children = child; *cur_children = child;
child->parent = cur;
} }
return NULL; return NULL;
} }
@ -1521,7 +1540,7 @@ hwloc__find_obj_covering_memory_cpuset(struct hwloc_topology *topology, hwloc_ob
static struct hwloc_obj * static struct hwloc_obj *
hwloc__find_insert_memory_parent(struct hwloc_topology *topology, hwloc_obj_t obj, hwloc__find_insert_memory_parent(struct hwloc_topology *topology, hwloc_obj_t obj,
hwloc_report_error_t report_error) const char *reason)
{ {
hwloc_obj_t parent, group, result; hwloc_obj_t parent, group, result;
@ -1573,7 +1592,7 @@ hwloc__find_insert_memory_parent(struct hwloc_topology *topology, hwloc_obj_t ob
return parent; return parent;
} }
result = hwloc__insert_object_by_cpuset(topology, parent, group, report_error); result = hwloc__insert_object_by_cpuset(topology, parent, group, reason);
if (!result) { if (!result) {
/* failed to insert, fallback to larger parent */ /* failed to insert, fallback to larger parent */
return parent; return parent;
@ -1586,8 +1605,7 @@ hwloc__find_insert_memory_parent(struct hwloc_topology *topology, hwloc_obj_t ob
/* only works for MEMCACHE and NUMAnode with a single bit in nodeset */ /* only works for MEMCACHE and NUMAnode with a single bit in nodeset */
static hwloc_obj_t static hwloc_obj_t
hwloc___attach_memory_object_by_nodeset(struct hwloc_topology *topology, hwloc_obj_t parent, hwloc___attach_memory_object_by_nodeset(struct hwloc_topology *topology, hwloc_obj_t parent,
hwloc_obj_t obj, hwloc_obj_t obj, const char *reason)
hwloc_report_error_t report_error)
{ {
hwloc_obj_t *curp = &parent->memory_first_child; hwloc_obj_t *curp = &parent->memory_first_child;
unsigned first = hwloc_bitmap_first(obj->nodeset); unsigned first = hwloc_bitmap_first(obj->nodeset);
@ -1611,20 +1629,12 @@ hwloc___attach_memory_object_by_nodeset(struct hwloc_topology *topology, hwloc_o
if (obj->type == HWLOC_OBJ_NUMANODE) { if (obj->type == HWLOC_OBJ_NUMANODE) {
if (cur->type == HWLOC_OBJ_NUMANODE) { if (cur->type == HWLOC_OBJ_NUMANODE) {
/* identical NUMA nodes? ignore the new one */ /* identical NUMA nodes? ignore the new one */
if (report_error) { report_insert_error(obj, cur, "NUMAnodes with identical nodesets", reason);
char curstr[512];
char objstr[512];
char msg[1100];
hwloc__report_error_format_obj(curstr, sizeof(curstr), cur);
hwloc__report_error_format_obj(objstr, sizeof(objstr), obj);
snprintf(msg, sizeof(msg), "%s and %s have identical nodesets!", objstr, curstr);
report_error(msg, __LINE__);
}
return NULL; return NULL;
} }
assert(cur->type == HWLOC_OBJ_MEMCACHE); assert(cur->type == HWLOC_OBJ_MEMCACHE);
/* insert the new NUMA node below that existing memcache */ /* insert the new NUMA node below that existing memcache */
return hwloc___attach_memory_object_by_nodeset(topology, cur, obj, report_error); return hwloc___attach_memory_object_by_nodeset(topology, cur, obj, reason);
} else { } else {
assert(obj->type == HWLOC_OBJ_MEMCACHE); assert(obj->type == HWLOC_OBJ_MEMCACHE);
@ -1637,7 +1647,7 @@ hwloc___attach_memory_object_by_nodeset(struct hwloc_topology *topology, hwloc_o
* (depth starts from the NUMA node). * (depth starts from the NUMA node).
* insert the new memcache below the existing one * insert the new memcache below the existing one
*/ */
return hwloc___attach_memory_object_by_nodeset(topology, cur, obj, report_error); return hwloc___attach_memory_object_by_nodeset(topology, cur, obj, reason);
} }
/* insert the memcache above the existing memcache or numa node */ /* insert the memcache above the existing memcache or numa node */
obj->next_sibling = cur->next_sibling; obj->next_sibling = cur->next_sibling;
@ -1673,8 +1683,7 @@ hwloc___attach_memory_object_by_nodeset(struct hwloc_topology *topology, hwloc_o
*/ */
struct hwloc_obj * struct hwloc_obj *
hwloc__attach_memory_object(struct hwloc_topology *topology, hwloc_obj_t parent, hwloc__attach_memory_object(struct hwloc_topology *topology, hwloc_obj_t parent,
hwloc_obj_t obj, hwloc_obj_t obj, const char *reason)
hwloc_report_error_t report_error)
{ {
hwloc_obj_t result; hwloc_obj_t result;
@ -1704,7 +1713,7 @@ hwloc__attach_memory_object(struct hwloc_topology *topology, hwloc_obj_t parent,
hwloc_bitmap_copy(obj->complete_cpuset, parent->complete_cpuset); hwloc_bitmap_copy(obj->complete_cpuset, parent->complete_cpuset);
#endif #endif
result = hwloc___attach_memory_object_by_nodeset(topology, parent, obj, report_error); result = hwloc___attach_memory_object_by_nodeset(topology, parent, obj, reason);
if (result == obj) { if (result == obj) {
/* Add the bit to the top sets, and to the parent CPU-side object */ /* Add the bit to the top sets, and to the parent CPU-side object */
if (obj->type == HWLOC_OBJ_NUMANODE) { if (obj->type == HWLOC_OBJ_NUMANODE) {
@ -1722,8 +1731,7 @@ hwloc__attach_memory_object(struct hwloc_topology *topology, hwloc_obj_t parent,
/* insertion routine that lets you change the error reporting callback */ /* insertion routine that lets you change the error reporting callback */
struct hwloc_obj * struct hwloc_obj *
hwloc__insert_object_by_cpuset(struct hwloc_topology *topology, hwloc_obj_t root, hwloc__insert_object_by_cpuset(struct hwloc_topology *topology, hwloc_obj_t root,
hwloc_obj_t obj, hwloc_obj_t obj, const char *reason)
hwloc_report_error_t report_error)
{ {
struct hwloc_obj *result; struct hwloc_obj *result;
@ -1740,20 +1748,20 @@ hwloc__insert_object_by_cpuset(struct hwloc_topology *topology, hwloc_obj_t root
if (hwloc__obj_type_is_memory(obj->type)) { if (hwloc__obj_type_is_memory(obj->type)) {
if (!root) { if (!root) {
root = hwloc__find_insert_memory_parent(topology, obj, report_error); root = hwloc__find_insert_memory_parent(topology, obj, reason);
if (!root) { if (!root) {
hwloc_free_unlinked_object(obj); hwloc_free_unlinked_object(obj);
return NULL; return NULL;
} }
} }
return hwloc__attach_memory_object(topology, root, obj, report_error); return hwloc__attach_memory_object(topology, root, obj, reason);
} }
if (!root) if (!root)
/* Start at the top. */ /* Start at the top. */
root = topology->levels[0][0]; root = topology->levels[0][0];
result = hwloc___insert_object_by_cpuset(topology, root, obj, report_error); result = hwloc___insert_object_by_cpuset(topology, root, obj, reason);
if (result && result->type == HWLOC_OBJ_PU) { if (result && result->type == HWLOC_OBJ_PU) {
/* Add the bit to the top sets */ /* Add the bit to the top sets */
if (hwloc_bitmap_isset(result->cpuset, result->os_index)) if (hwloc_bitmap_isset(result->cpuset, result->os_index))
@ -1769,12 +1777,6 @@ hwloc__insert_object_by_cpuset(struct hwloc_topology *topology, hwloc_obj_t root
/* the default insertion routine warns in case of error. /* the default insertion routine warns in case of error.
* it's used by most backends */ * it's used by most backends */
struct hwloc_obj *
hwloc_insert_object_by_cpuset(struct hwloc_topology *topology, hwloc_obj_t obj)
{
return hwloc__insert_object_by_cpuset(topology, NULL, obj, hwloc_report_os_error);
}
void void
hwloc_insert_object_by_parent(struct hwloc_topology *topology, hwloc_obj_t parent, hwloc_obj_t obj) hwloc_insert_object_by_parent(struct hwloc_topology *topology, hwloc_obj_t parent, hwloc_obj_t obj)
{ {
@ -1917,6 +1919,7 @@ hwloc_topology_insert_group_object(struct hwloc_topology *topology, hwloc_obj_t
if (hwloc_bitmap_isset(nodeset, numa->os_index)) if (hwloc_bitmap_isset(nodeset, numa->os_index))
hwloc_bitmap_or(obj->cpuset, obj->cpuset, numa->cpuset); hwloc_bitmap_or(obj->cpuset, obj->cpuset, numa->cpuset);
} }
/* FIXME insert by nodeset to group NUMAs even if CPUless? */
cmp = hwloc_obj_cmp_sets(obj, root); cmp = hwloc_obj_cmp_sets(obj, root);
if (cmp == HWLOC_OBJ_INCLUDED) { if (cmp == HWLOC_OBJ_INCLUDED) {
@ -2047,7 +2050,7 @@ hwloc_find_insert_io_parent_by_complete_cpuset(struct hwloc_topology *topology,
hwloc_bitmap_and(cpuset, cpuset, hwloc_topology_get_topology_cpuset(topology)); hwloc_bitmap_and(cpuset, cpuset, hwloc_topology_get_topology_cpuset(topology));
group_obj->cpuset = hwloc_bitmap_dup(cpuset); group_obj->cpuset = hwloc_bitmap_dup(cpuset);
group_obj->attr->group.kind = HWLOC_GROUP_KIND_IO; group_obj->attr->group.kind = HWLOC_GROUP_KIND_IO;
parent = hwloc__insert_object_by_cpuset(topology, largeparent, group_obj, hwloc_report_os_error); parent = hwloc__insert_object_by_cpuset(topology, largeparent, group_obj, "topology:io_parent");
if (!parent) if (!parent)
/* Failed to insert the Group, maybe a conflicting cpuset */ /* Failed to insert the Group, maybe a conflicting cpuset */
return largeparent; return largeparent;
@ -3251,7 +3254,7 @@ hwloc_discover(struct hwloc_topology *topology,
* produced by hwloc_setup_pu_level() * produced by hwloc_setup_pu_level()
*/ */
/* To be able to just use hwloc_insert_object_by_cpuset to insert the object /* To be able to just use hwloc__insert_object_by_cpuset to insert the object
* in the topology according to the cpuset, the cpuset field must be * in the topology according to the cpuset, the cpuset field must be
* initialized. * initialized.
*/ */
@ -3356,7 +3359,7 @@ hwloc_discover(struct hwloc_topology *topology,
hwloc_bitmap_set(node->nodeset, 0); hwloc_bitmap_set(node->nodeset, 0);
memcpy(&node->attr->numanode, &topology->machine_memory, sizeof(topology->machine_memory)); memcpy(&node->attr->numanode, &topology->machine_memory, sizeof(topology->machine_memory));
memset(&topology->machine_memory, 0, sizeof(topology->machine_memory)); memset(&topology->machine_memory, 0, sizeof(topology->machine_memory));
hwloc_insert_object_by_cpuset(topology, node); hwloc__insert_object_by_cpuset(topology, NULL, node, "core:defaultnumanode");
} else { } else {
/* if we're sure we found all NUMA nodes without their sizes (x86 backend?), /* if we're sure we found all NUMA nodes without their sizes (x86 backend?),
* we could split topology->total_memory in all of them. * we could split topology->total_memory in all of them.
@ -3514,6 +3517,7 @@ hwloc_topology_setup_defaults(struct hwloc_topology *topology)
memset(topology->support.discovery, 0, sizeof(*topology->support.discovery)); memset(topology->support.discovery, 0, sizeof(*topology->support.discovery));
memset(topology->support.cpubind, 0, sizeof(*topology->support.cpubind)); memset(topology->support.cpubind, 0, sizeof(*topology->support.cpubind));
memset(topology->support.membind, 0, sizeof(*topology->support.membind)); memset(topology->support.membind, 0, sizeof(*topology->support.membind));
memset(topology->support.misc, 0, sizeof(*topology->support.misc));
/* Only the System object on top by default */ /* Only the System object on top by default */
topology->next_gp_index = 1; /* keep 0 as an invalid value */ topology->next_gp_index = 1; /* keep 0 as an invalid value */
@ -3590,6 +3594,7 @@ hwloc__topology_init (struct hwloc_topology **topologyp,
topology->support.discovery = hwloc_tma_malloc(tma, sizeof(*topology->support.discovery)); topology->support.discovery = hwloc_tma_malloc(tma, sizeof(*topology->support.discovery));
topology->support.cpubind = hwloc_tma_malloc(tma, sizeof(*topology->support.cpubind)); topology->support.cpubind = hwloc_tma_malloc(tma, sizeof(*topology->support.cpubind));
topology->support.membind = hwloc_tma_malloc(tma, sizeof(*topology->support.membind)); topology->support.membind = hwloc_tma_malloc(tma, sizeof(*topology->support.membind));
topology->support.misc = hwloc_tma_malloc(tma, sizeof(*topology->support.misc));
topology->nb_levels_allocated = nblevels; /* enough for default 10 levels = Mach+Pack+Die+NUMA+L3+L2+L1d+L1i+Co+PU */ topology->nb_levels_allocated = nblevels; /* enough for default 10 levels = Mach+Pack+Die+NUMA+L3+L2+L1d+L1i+Co+PU */
topology->levels = hwloc_tma_calloc(tma, topology->nb_levels_allocated * sizeof(*topology->levels)); topology->levels = hwloc_tma_calloc(tma, topology->nb_levels_allocated * sizeof(*topology->levels));
@ -3598,6 +3603,8 @@ hwloc__topology_init (struct hwloc_topology **topologyp,
hwloc__topology_filter_init(topology); hwloc__topology_filter_init(topology);
hwloc_internal_distances_init(topology); hwloc_internal_distances_init(topology);
hwloc_internal_memattrs_init(topology);
hwloc_internal_cpukinds_init(topology);
topology->userdata_export_cb = NULL; topology->userdata_export_cb = NULL;
topology->userdata_import_cb = NULL; topology->userdata_import_cb = NULL;
@ -3691,7 +3698,7 @@ hwloc_topology_set_flags (struct hwloc_topology *topology, unsigned long flags)
return -1; return -1;
} }
if (flags & ~(HWLOC_TOPOLOGY_FLAG_INCLUDE_DISALLOWED|HWLOC_TOPOLOGY_FLAG_IS_THISSYSTEM|HWLOC_TOPOLOGY_FLAG_THISSYSTEM_ALLOWED_RESOURCES)) { if (flags & ~(HWLOC_TOPOLOGY_FLAG_INCLUDE_DISALLOWED|HWLOC_TOPOLOGY_FLAG_IS_THISSYSTEM|HWLOC_TOPOLOGY_FLAG_THISSYSTEM_ALLOWED_RESOURCES|HWLOC_TOPOLOGY_FLAG_IMPORT_SUPPORT)) {
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
@ -3827,7 +3834,9 @@ hwloc_topology_clear (struct hwloc_topology *topology)
{ {
/* no need to set to NULL after free() since callers will call setup_defaults() or just destroy the rest of the topology */ /* no need to set to NULL after free() since callers will call setup_defaults() or just destroy the rest of the topology */
unsigned l; unsigned l;
hwloc_internal_cpukinds_destroy(topology);
hwloc_internal_distances_destroy(topology); hwloc_internal_distances_destroy(topology);
hwloc_internal_memattrs_destroy(topology);
hwloc_free_object_and_children(topology->levels[0][0]); hwloc_free_object_and_children(topology->levels[0][0]);
hwloc_bitmap_free(topology->allowed_cpuset); hwloc_bitmap_free(topology->allowed_cpuset);
hwloc_bitmap_free(topology->allowed_nodeset); hwloc_bitmap_free(topology->allowed_nodeset);
@ -3858,6 +3867,7 @@ hwloc_topology_destroy (struct hwloc_topology *topology)
free(topology->support.discovery); free(topology->support.discovery);
free(topology->support.cpubind); free(topology->support.cpubind);
free(topology->support.membind); free(topology->support.membind);
free(topology->support.misc);
free(topology); free(topology);
} }
@ -3873,7 +3883,9 @@ hwloc_topology_load (struct hwloc_topology *topology)
return -1; return -1;
} }
/* initialize envvar-related things */
hwloc_internal_distances_prepare(topology); hwloc_internal_distances_prepare(topology);
hwloc_internal_memattrs_prepare(topology);
if (getenv("HWLOC_XML_USERDATA_NOT_DECODED")) if (getenv("HWLOC_XML_USERDATA_NOT_DECODED"))
topology->userdata_not_decoded = 1; topology->userdata_not_decoded = 1;
@ -3954,6 +3966,9 @@ hwloc_topology_load (struct hwloc_topology *topology)
#endif #endif
hwloc_topology_check(topology); hwloc_topology_check(topology);
/* Rank cpukinds */
hwloc_internal_cpukinds_rank(topology);
/* Mark distances objs arrays as invalid since we may have removed objects /* Mark distances objs arrays as invalid since we may have removed objects
* from the topology after adding the distances (remove_empty, etc). * from the topology after adding the distances (remove_empty, etc).
* It would be hard to actually verify whether it's needed. * It would be hard to actually verify whether it's needed.
@ -3964,6 +3979,10 @@ hwloc_topology_load (struct hwloc_topology *topology)
*/ */
hwloc_internal_distances_refresh(topology); hwloc_internal_distances_refresh(topology);
/* Same for memattrs */
hwloc_internal_memattrs_need_refresh(topology);
hwloc_internal_memattrs_refresh(topology);
topology->is_loaded = 1; topology->is_loaded = 1;
if (topology->backend_phases & HWLOC_DISC_PHASE_TWEAK) { if (topology->backend_phases & HWLOC_DISC_PHASE_TWEAK) {
@ -4246,10 +4265,12 @@ hwloc_topology_restrict(struct hwloc_topology *topology, hwloc_const_bitmap_t se
/* some objects may have disappeared, we need to update distances objs arrays */ /* some objects may have disappeared, we need to update distances objs arrays */
hwloc_internal_distances_invalidate_cached_objs(topology); hwloc_internal_distances_invalidate_cached_objs(topology);
hwloc_internal_memattrs_need_refresh(topology);
hwloc_filter_levels_keep_structure(topology); hwloc_filter_levels_keep_structure(topology);
hwloc_propagate_symmetric_subtree(topology, topology->levels[0][0]); hwloc_propagate_symmetric_subtree(topology, topology->levels[0][0]);
propagate_total_memory(topology->levels[0][0]); propagate_total_memory(topology->levels[0][0]);
hwloc_internal_cpukinds_restrict(topology);
#ifndef HWLOC_DEBUG #ifndef HWLOC_DEBUG
if (getenv("HWLOC_DEBUG_CHECK")) if (getenv("HWLOC_DEBUG_CHECK"))
@ -4334,6 +4355,15 @@ hwloc_topology_allow(struct hwloc_topology *topology,
return -1; return -1;
} }
int
hwloc_topology_refresh(struct hwloc_topology *topology)
{
hwloc_internal_cpukinds_rank(topology);
hwloc_internal_distances_refresh(topology);
hwloc_internal_memattrs_refresh(topology);
return 0;
}
int int
hwloc_topology_is_thissystem(struct hwloc_topology *topology) hwloc_topology_is_thissystem(struct hwloc_topology *topology)
{ {

View file

@ -1,7 +1,7 @@
/* /*
* Copyright © 2009 CNRS * Copyright © 2009 CNRS
* Copyright © 2009-2019 Inria. All rights reserved. * Copyright © 2009-2020 Inria. All rights reserved.
* Copyright © 2009-2010 Université Bordeaux * Copyright © 2009-2010, 2020 Université Bordeaux
* Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved. * Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved.
* See COPYING in top-level directory. * See COPYING in top-level directory.
*/ */
@ -138,6 +138,37 @@ hwloc_obj_type_is_icache(hwloc_obj_type_t type)
return hwloc__obj_type_is_icache(type); return hwloc__obj_type_is_icache(type);
} }
static hwloc_obj_t hwloc_get_obj_by_depth_and_gp_index(hwloc_topology_t topology, unsigned depth, uint64_t gp_index)
{
hwloc_obj_t obj = hwloc_get_obj_by_depth(topology, depth, 0);
while (obj) {
if (obj->gp_index == gp_index)
return obj;
obj = obj->next_cousin;
}
return NULL;
}
hwloc_obj_t hwloc_get_obj_by_type_and_gp_index(hwloc_topology_t topology, hwloc_obj_type_t type, uint64_t gp_index)
{
int depth = hwloc_get_type_depth(topology, type);
if (depth == HWLOC_TYPE_DEPTH_UNKNOWN)
return NULL;
if (depth == HWLOC_TYPE_DEPTH_MULTIPLE) {
for(depth=1 /* no multiple machine levels */;
(unsigned) depth < topology->nb_levels-1 /* no multiple PU levels */;
depth++) {
if (hwloc_get_depth_type(topology, depth) == type) {
hwloc_obj_t obj = hwloc_get_obj_by_depth_and_gp_index(topology, depth, gp_index);
if (obj)
return obj;
}
}
return NULL;
}
return hwloc_get_obj_by_depth_and_gp_index(topology, depth, gp_index);
}
unsigned hwloc_get_closest_objs (struct hwloc_topology *topology, struct hwloc_obj *src, struct hwloc_obj **objs, unsigned max) unsigned hwloc_get_closest_objs (struct hwloc_topology *topology, struct hwloc_obj *src, struct hwloc_obj **objs, unsigned max)
{ {
struct hwloc_obj *parent, *nextparent, **src_objs; struct hwloc_obj *parent, *nextparent, **src_objs;
@ -654,7 +685,11 @@ hwloc_obj_attr_snprintf(char * __hwloc_restrict string, size_t size, hwloc_obj_t
unsigned i; unsigned i;
for(i=0; i<obj->infos_count; i++) { for(i=0; i<obj->infos_count; i++) {
struct hwloc_info_s *info = &obj->infos[i]; struct hwloc_info_s *info = &obj->infos[i];
const char *quote = strchr(info->value, ' ') ? "\"" : ""; const char *quote;
if (strchr(info->value, ' '))
quote = "\"";
else
quote = "";
res = hwloc_snprintf(tmp, tmplen, "%s%s=%s%s%s", res = hwloc_snprintf(tmp, tmplen, "%s%s=%s%s%s",
prefix, prefix,
info->name, info->name,
@ -673,3 +708,31 @@ hwloc_obj_attr_snprintf(char * __hwloc_restrict string, size_t size, hwloc_obj_t
return ret; return ret;
} }
int hwloc_bitmap_singlify_per_core(hwloc_topology_t topology, hwloc_bitmap_t cpuset, unsigned which)
{
hwloc_obj_t core = NULL;
while ((core = hwloc_get_next_obj_covering_cpuset_by_type(topology, cpuset, HWLOC_OBJ_CORE, core)) != NULL) {
/* this core has some PUs in the cpuset, find the index-th one */
unsigned i = 0;
int pu = -1;
do {
pu = hwloc_bitmap_next(core->cpuset, pu);
if (pu == -1) {
/* no which-th PU in cpuset and core, remove the entire core */
hwloc_bitmap_andnot(cpuset, cpuset, core->cpuset);
break;
}
if (hwloc_bitmap_isset(cpuset, pu)) {
if (i == which) {
/* remove the entire core except that exact pu */
hwloc_bitmap_andnot(cpuset, cpuset, core->cpuset);
hwloc_bitmap_set(cpuset, pu);
break;
}
i++;
}
} while (1);
}
return 0;
}