diff --git a/opal/mca/hwloc/hwloc1110/Makefile.am b/opal/mca/hwloc/hwloc1110/Makefile.am new file mode 100644 index 0000000000..4fb47162ac --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/Makefile.am @@ -0,0 +1,83 @@ +# +# Copyright (c) 2011-2014 Cisco Systems, Inc. All rights reserved. +# Copyright (c) 2014-2015 Intel, Inc. All right reserved. +# $COPYRIGHT$ +# +# Additional copyrights may follow +# +# $HEADER$ +# + +# Due to what might be a bug in Automake, we need to remove stamp-h? +# files manually. See +# http://debbugs.gnu.org/cgi/bugreport.cgi?bug=19418. +DISTCLEANFILES = \ + hwloc/include/hwloc/autogen/stamp-h? \ + hwloc/include/private/autogen/stamp-h? + +# Need to include these files so that these directories are carried in +# the tarball (in case someone invokes autogen.sh on a dist tarball). +EXTRA_DIST = \ + hwloc/doc/README.txt \ + hwloc/tests/README.txt \ + hwloc/utils/README.txt + +SUBDIRS = hwloc + +# Headers and sources +headers = hwloc1110.h +sources = hwloc1110_component.c + +# We only ever build this component statically +noinst_LTLIBRARIES = libmca_hwloc_hwloc1110.la +libmca_hwloc_hwloc1110_la_SOURCES = $(headers) $(sources) +nodist_libmca_hwloc_hwloc1110_la_SOURCES = $(nodist_headers) +libmca_hwloc_hwloc1110_la_LDFLAGS = -module -avoid-version $(opal_hwloc_hwloc1110_LDFLAGS) +libmca_hwloc_hwloc1110_la_LIBADD = $(opal_hwloc_hwloc1110_LIBS) +libmca_hwloc_hwloc1110_la_DEPENDENCIES = \ + $(HWLOC_top_builddir)/src/libhwloc_embedded.la + +# Since the rest of the code base includes the underlying hwloc.h, we +# also have to install the underlying header files when +# --with-devel-headers is specified. hwloc doesn't support this; the +# least gross way to make this happen is just to list all of hwloc's +# header files here. :-( +headers += \ + hwloc/include/hwloc.h \ + hwloc/include/hwloc/bitmap.h \ + hwloc/include/hwloc/cuda.h \ + hwloc/include/hwloc/cudart.h \ + hwloc/include/hwloc/deprecated.h \ + hwloc/include/hwloc/diff.h \ + hwloc/include/hwloc/gl.h \ + hwloc/include/hwloc/helper.h \ + hwloc/include/hwloc/inlines.h \ + hwloc/include/hwloc/intel-mic.h \ + hwloc/include/hwloc/myriexpress.h \ + hwloc/include/hwloc/nvml.h \ + hwloc/include/hwloc/opencl.h \ + hwloc/include/hwloc/openfabrics-verbs.h \ + hwloc/include/hwloc/plugins.h \ + hwloc/include/hwloc/rename.h \ + hwloc/include/private/private.h \ + hwloc/include/private/debug.h \ + hwloc/include/private/misc.h \ + hwloc/include/private/cpuid-x86.h +nodist_headers = hwloc/include/hwloc/autogen/config.h + +if HWLOC_HAVE_LINUX +headers += \ + hwloc/include/hwloc/linux.h \ + hwloc/include/hwloc/linux-libnuma.h +endif HWLOC_HAVE_LINUX + +if HWLOC_HAVE_SCHED_SETAFFINITY +headers += hwloc/include/hwloc/glibc-sched.h +endif HWLOC_HAVE_SCHED_SETAFFINITY + +# Conditionally install the header files +if WANT_INSTALL_HEADERS +opaldir = $(opalincludedir)/$(subdir) +nobase_opal_HEADERS = $(headers) +nobase_nodist_opal_HEADERS = $(nodist_headers) +endif diff --git a/opal/mca/hwloc/hwloc1110/README-ompi.txt b/opal/mca/hwloc/hwloc1110/README-ompi.txt new file mode 100644 index 0000000000..948285aaff --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/README-ompi.txt @@ -0,0 +1,35 @@ +Applied the following patches from the upstream hwloc 1.9 branch after +the v1.9.1 release: + +All relevant commits up to open-mpi/hwloc@4e23b12 (i.e., the HEAD as +of 27 March 2015). "Relevant" commits are defined as those that +included files that are embedded in the Open MPI tree (e.g., updates +to files in docs/, utils/, etc. aren't relevant because they are not +embedded in the Open MPI tree). To be specific, the following commits +have been cherry-picked over to Open MPI: + +* open-mpi/hwloc@7c03216 v1.9.1 released, doing 1.9.2rc1 now +* open-mpi/hwloc@b35ced8 misc.h: Fix hwloc_strncasecmp() build under strict flags on BSD +* open-mpi/hwloc@d8c3f3d misc.h: Fix hwloc_strncasecmp() with some icc +* open-mpi/hwloc@f705a23 Use gcc's __asm__ version of the asm extension, which can be used in all standards +* open-mpi/hwloc@307726a configure: fix the check for X11/Xutil.h +* open-mpi/hwloc@ec58c05 errors: improve the advice to send hwloc-gather-topology files in the OS error message +* open-mpi/hwloc@35c743d NEWS update +* open-mpi/hwloc@868170e API: clearly state that os_index isn't unique while logical_index is +* open-mpi/hwloc@851532d x86 and OSF: Don't forget to set NUMA node nodeset +* open-mpi/hwloc@790aa2e cpuid-x86: Fix duplicate asm labels in case of heavy inlining on x86-32 +* open-mpi/hwloc@dd09aa5 debug: fix an overzealous assertion about the parent cpuset vs its children +* open-mpi/hwloc@769b9b5 core: fix the merging of identical objects in presence of Misc objects +* open-mpi/hwloc@71da0f1 core: reorder children in merge_useless_child() as well +* open-mpi/hwloc@c9cef07 hpux: improve hwloc_hpux_find_ldom() looking for NUMA node +* open-mpi/hwloc@cdffea6 x86: use ulong for cache sizes, uint won't be enough in the near future +* open-mpi/hwloc@55b0676 x86: use Group instead of Misc for unknown x2apic levels +* open-mpi/hwloc@7764ce5 synthetic: Misc levels are not allowed in the synthetic description +* open-mpi/hwloc@5b2dce1 error: point to the FAQ when displaying the big OS error message +* open-mpi/hwloc@c7bd9e6 pci: fix SR-IOV VF vendor/device names +* open-mpi/hwloc@a0f72ef distances: when we fail to insert an intermediate group, don't try to group further above +* open-mpi/hwloc@e419811 AIX: Fix PU os_index +* open-mpi/hwloc@08ab793 groups: add complete sets when inserting distance/pci groups +* open-mpi/hwloc@c66e714 core: only update root->complete sets if insert succeeds +* open-mpi/hwloc@01da9b9 bitmap: fix a corner case in hwloc_bitmap_isincluded() with infinite sets +* open-mpi/hwloc@e7b192b pci: fix bridge depth diff --git a/opal/mca/hwloc/hwloc1110/configure.m4 b/opal/mca/hwloc/hwloc1110/configure.m4 new file mode 100644 index 0000000000..72a249f8f9 --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/configure.m4 @@ -0,0 +1,170 @@ +# -*- shell-script -*- +# +# Copyright (c) 2009-2014 Cisco Systems, Inc. All rights reserved. +# Copyright (c) 2014-2015 Intel, Inc. All rights reserved. +# +# $COPYRIGHT$ +# +# Additional copyrights may follow +# +# $HEADER$ +# + +# +# Priority +# +AC_DEFUN([MCA_opal_hwloc_hwloc1110_PRIORITY], [90]) + +# +# Force this component to compile in static-only mode +# +AC_DEFUN([MCA_opal_hwloc_hwloc1110_COMPILE_MODE], [ + AC_MSG_CHECKING([for MCA component $2:$3 compile mode]) + $4="static" + AC_MSG_RESULT([$$4]) +]) + +# Include hwloc m4 files +m4_include(opal/mca/hwloc/hwloc1110/hwloc/config/hwloc.m4) +m4_include(opal/mca/hwloc/hwloc1110/hwloc/config/hwloc_pkg.m4) +m4_include(opal/mca/hwloc/hwloc1110/hwloc/config/hwloc_check_attributes.m4) +m4_include(opal/mca/hwloc/hwloc1110/hwloc/config/hwloc_check_visibility.m4) +m4_include(opal/mca/hwloc/hwloc1110/hwloc/config/hwloc_check_vendor.m4) +m4_include(opal/mca/hwloc/hwloc1110/hwloc/config/hwloc_components.m4) + +# MCA_hwloc_hwloc1110_POST_CONFIG() +# --------------------------------- +AC_DEFUN([MCA_opal_hwloc_hwloc1110_POST_CONFIG],[ + OPAL_VAR_SCOPE_PUSH([opal_hwloc_hwloc1110_basedir]) + + # If we won, then do all the rest of the setup + AS_IF([test "$1" = "1" && test "$opal_hwloc_hwloc1110_support" = "yes"], + [ + # Set this variable so that the framework m4 knows what + # file to include in opal/mca/hwloc/hwloc.h + opal_hwloc_hwloc1110_basedir=opal/mca/hwloc/hwloc1110 + opal_hwloc_base_include="$opal_hwloc_hwloc1110_basedir/hwloc1110.h" + + # Add some stuff to CPPFLAGS so that the rest of the source + # tree can be built + file=$opal_hwloc_hwloc1110_basedir/hwloc + CPPFLAGS="$CPPFLAGS -I$OPAL_TOP_SRCDIR/$file/include" + AS_IF([test "$OPAL_TOP_BUILDDIR" != "$OPAL_TOP_SRCDIR"], + [CPPFLAGS="$CPPFLAGS -I$OPAL_TOP_BUILDDIR/$file/include"]) + unset file + ]) + OPAL_VAR_SCOPE_POP + + # This must be run unconditionally + HWLOC_DO_AM_CONDITIONALS +])dnl + + +# MCA_hwloc_hwloc1110_CONFIG([action-if-found], [action-if-not-found]) +# -------------------------------------------------------------------- +AC_DEFUN([MCA_opal_hwloc_hwloc1110_CONFIG],[ + # Hwloc needs to know if we have Verbs support + AC_REQUIRE([OPAL_CHECK_VERBS_DIR]) + + AC_CONFIG_FILES([opal/mca/hwloc/hwloc1110/Makefile]) + + OPAL_VAR_SCOPE_PUSH([HWLOC_VERSION opal_hwloc_hwloc1110_save_CPPFLAGS opal_hwloc_hwloc1110_save_LDFLAGS opal_hwloc_hwloc1110_save_LIBS opal_hwloc_hwloc1110_save_cairo opal_hwloc_hwloc1110_save_xml opal_hwloc_hwloc1110_basedir opal_hwloc_hwloc1110_file opal_hwloc_hwloc1110_save_cflags CPPFLAGS_save LIBS_save]) + + # default to this component not providing support + opal_hwloc_hwloc1110_basedir=opal/mca/hwloc/hwloc1110 + opal_hwloc_hwloc1110_support=no + + if test "$with_hwloc" = "internal" -o "$with_hwloc" = "" -o "$with_hwloc" = "yes"; then + opal_hwloc_hwloc1110_save_CPPFLAGS=$CPPFLAGS + opal_hwloc_hwloc1110_save_LDFLAGS=$LDFLAGS + opal_hwloc_hwloc1110_save_LIBS=$LIBS + + # Run the hwloc configuration - set the prefix to minimize + # the chance that someone will use the internal symbols + HWLOC_SET_SYMBOL_PREFIX([opal_hwloc1110_]) + + # save XML or graphical options + opal_hwloc_hwloc1110_save_cairo=$enable_cairo + opal_hwloc_hwloc1110_save_xml=$enable_xml + opal_hwloc_hwloc1110_save_static=$enable_static + opal_hwloc_hwloc1110_save_shared=$enable_shared + opal_hwloc_hwloc1110_save_plugins=$enable_plugins + + # never enable hwloc's graphical option + enable_cairo=no + + # never enable hwloc's plugin system + enable_plugins=no + enable_static=yes + enable_shared=no + + # Override -- disable hwloc's libxml2 support, but enable the + # native hwloc XML support + enable_libxml2=no + enable_xml=yes + + # hwloc checks for compiler visibility, and its needs to do + # this without "picky" flags. + opal_hwloc_hwloc1110_save_cflags=$CFLAGS + CFLAGS=$OPAL_CFLAGS_BEFORE_PICKY + HWLOC_SETUP_CORE([opal/mca/hwloc/hwloc1110/hwloc], + [AC_MSG_CHECKING([whether hwloc configure succeeded]) + AC_MSG_RESULT([yes]) + HWLOC_VERSION="internal v`$srcdir/$opal_hwloc_hwloc1110_basedir/hwloc/config/hwloc_get_version.sh $srcdir/$opal_hwloc_hwloc1110_basedir/hwloc/VERSION`" + + # Build flags for our Makefile.am + opal_hwloc_hwloc1110_LDFLAGS='$(HWLOC_EMBEDDED_LDFLAGS)' + opal_hwloc_hwloc1110_LIBS='$(OPAL_TOP_BUILDDIR)/'"$opal_hwloc_hwloc1110_basedir"'/hwloc/src/libhwloc_embedded.la $(HWLOC_EMBEDDED_LIBS)' + opal_hwloc_hwloc1110_support=yes + + AC_DEFINE_UNQUOTED([HWLOC_HWLOC1110_HWLOC_VERSION], + ["$HWLOC_VERSION"], + [Version of hwloc]) + + # Do we have verbs support? + CPPFLAGS_save=$CPPFLAGS + AS_IF([test "$opal_want_verbs" = "yes"], + [CPPFLAGS="-I$opal_verbs_dir/include $CPPFLAGS"]) + AC_CHECK_HEADERS([infiniband/verbs.h]) + CPPFLAGS=$CPPFLAGS_save + ], + [AC_MSG_CHECKING([whether hwloc configure succeeded]) + AC_MSG_RESULT([no]) + opal_hwloc_hwloc1110_support=no]) + CFLAGS=$opal_hwloc_hwloc1110_save_cflags + + # Restore some env variables, if necessary + AS_IF([test -n "$opal_hwloc_hwloc1110_save_cairo"], + [enable_cairo=$opal_hwloc_hwloc1110_save_cairo]) + AS_IF([test -n "$opal_hwloc_hwloc1110_save_xml"], + [enable_xml=$opal_hwloc_hwloc1110_save_xml]) + AS_IF([test -n "$opal_hwloc_hwloc1110_save_static"], + [enable_static=$opal_hwloc_hwloc1110_save_static]) + AS_IF([test -n "$opal_hwloc_hwloc1110_save_shared"], + [enable_shared=$opal_hwloc_hwloc1110_save_shared]) + AS_IF([test -n "$opal_hwloc_hwloc1110_save_plugins"], + [enable_plugins=$opal_hwloc_hwloc1110_save_shared]) + + CPPFLAGS=$opal_hwloc_hwloc1110_save_CPPFLAGS + LDFLAGS=$opal_hwloc_hwloc1110_save_LDFLAGS + LIBS=$opal_hwloc_hwloc1110_save_LIBS + + AC_SUBST([opal_hwloc_hwloc1110_CFLAGS]) + AC_SUBST([opal_hwloc_hwloc1110_CPPFLAGS]) + AC_SUBST([opal_hwloc_hwloc1110_LDFLAGS]) + AC_SUBST([opal_hwloc_hwloc1110_LIBS]) + + # Finally, add some flags to the wrapper compiler so that our + # headers can be found. + hwloc_hwloc1110_WRAPPER_EXTRA_LDFLAGS="$HWLOC_EMBEDDED_LDFLAGS" + hwloc_hwloc1110_WRAPPER_EXTRA_LIBS="$HWLOC_EMBEDDED_LIBS" + hwloc_hwloc1110_WRAPPER_EXTRA_CPPFLAGS='-I${includedir}/openmpi/'"$opal_hwloc_hwloc1110_basedir/hwloc/include" + fi + + # Done! + AS_IF([test "$opal_hwloc_hwloc1110_support" = "yes"], + [$1], + [$2]) + + OPAL_VAR_SCOPE_POP +])dnl diff --git a/opal/mca/hwloc/hwloc1110/hwloc/AUTHORS b/opal/mca/hwloc/hwloc1110/hwloc/AUTHORS new file mode 100644 index 0000000000..837b27f2ca --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/AUTHORS @@ -0,0 +1,8 @@ +Cédric Augonnet +Jérôme Clet-Ortega +Ludovic Courtès +Brice Goglin +Nathalie Furmento +Samuel Thibault +Jeff Squyres +Alexey Kardashevskiy diff --git a/opal/mca/hwloc/hwloc1110/hwloc/COPYING b/opal/mca/hwloc/hwloc1110/hwloc/COPYING new file mode 100644 index 0000000000..694a7bd774 --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/COPYING @@ -0,0 +1,28 @@ +Copyright © 2009 CNRS +Copyright © 2009 inria. All rights reserved. +Copyright © 2009 Université Bordeaux +Copyright © 2009 Cisco Systems, Inc. All rights reserved. +Copyright © 2012 Blue Brain Project, EPFL. All rights reserved. +See COPYING in top-level directory. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/opal/mca/hwloc/hwloc1110/hwloc/Makefile.am b/opal/mca/hwloc/hwloc1110/hwloc/Makefile.am new file mode 100644 index 0000000000..69ae667548 --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/Makefile.am @@ -0,0 +1,75 @@ +# Copyright © 2009-2015 Inria. All rights reserved. +# Copyright © 2009 Université Bordeaux +# Copyright © 2009-2014 Cisco Systems, Inc. All rights reserved. +# See COPYING in top-level directory. + +# Note that the -I directory must *exactly* match what was specified +# via AC_CONFIG_MACRO_DIR in configure.ac. +ACLOCAL_AMFLAGS = -I ./config + +SUBDIRS = src include +if HWLOC_BUILD_STANDALONE +SUBDIRS += tests utils +# We need doc/ if HWLOC_BUILD_DOXYGEN, or during make install if HWLOC_INSTALL_DOXYGEN. +# There's no INSTALL_SUBDIRS, so always enter doc/ and check HWLOC_BUILD/INSTALL_DOXYGEN there +SUBDIRS += doc +endif + +# Do not let automake automatically add the non-standalone dirs to the +# distribution tarball if we're building in embedded mode. +DIST_SUBDIRS = $(SUBDIRS) + +# Only install the pkg file if we're building in standalone mode (and not on Windows) +if HWLOC_BUILD_STANDALONE +if !HWLOC_HAVE_WINDOWS +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = hwloc.pc +endif +endif + +# Only install the valgrind suppressions file if we're building in standalone mode +if HWLOC_BUILD_STANDALONE +dist_pkgdata_DATA = contrib/hwloc-valgrind.supp +endif + +# +# "make distcheck" requires that tarballs are able to be able to "make +# dist", so we have to include config/distscript.sh. +# +EXTRA_DIST = \ + README VERSION COPYING AUTHORS \ + config/hwloc_get_version.sh \ + config/distscript.sh + +# Only install entire visual studio subdirectory if we're building in standalone mode +if HWLOC_BUILD_STANDALONE +EXTRA_DIST += contrib/windows +endif + +if HWLOC_BUILD_STANDALONE +dist-hook: + sh "$(top_srcdir)/config/distscript.sh" "$(top_srcdir)" "$(distdir)" "$(HWLOC_VERSION)" +endif HWLOC_BUILD_STANDALONE + +# +# Build the documenation and top-level README file +# +if HWLOC_BUILD_STANDALONE +.PHONY: doc readme +doc readme: + $(MAKE) -C doc +endif HWLOC_BUILD_STANDALONE + +if HWLOC_BUILD_STANDALONE +if HWLOC_HAVE_WINDOWS +# +# Winball specific rules +# +install-data-local: + sed -e 's/$$/'$$'\015'/ < $(srcdir)/README > $(DESTDIR)$(prefix)/README.txt + sed -e 's/$$/'$$'\015'/ < $(srcdir)/NEWS > $(DESTDIR)$(prefix)/NEWS.txt + sed -e 's/$$/'$$'\015'/ < $(srcdir)/COPYING > $(DESTDIR)$(prefix)/COPYING.txt +uninstall-local: + rm -f $(DESTDIR)$(prefix)/README.txt $(DESTDIR)$(prefix)/NEWS.txt $(DESTDIR)$(prefix)/COPYING.txt +endif HWLOC_HAVE_WINDOWS +endif HWLOC_BUILD_STANDALONE diff --git a/opal/mca/hwloc/hwloc1110/hwloc/NEWS b/opal/mca/hwloc/hwloc1110/hwloc/NEWS new file mode 100644 index 0000000000..01df3258ae --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/NEWS @@ -0,0 +1,1156 @@ +Copyright © 2009 CNRS +Copyright © 2009-2015 Inria. All rights reserved. +Copyright © 2009-2013 Université Bordeaux +Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved. + +$COPYRIGHT$ + +Additional copyrights may follow + +$HEADER$ + +=========================================================================== + +This file contains the main features as well as overviews of specific +bug fixes (and other actions) for each version of hwloc since version +0.9 (as initially released as "libtopology", then re-branded to "hwloc" +in v0.9.1). + + +Version 1.11.0 +-------------- +* API + + Socket objects are renamed into Package to align with the terminology + used by processor vendors. The old HWLOC_OBJ_SOCKET type and "Socket" + name are still supported for backward compatibility. + + HWLOC_OBJ_NODE is replaced with HWLOC_OBJ_NUMANODE for clarification. + HWLOC_OBJ_NODE is still supported for backward compatibility. + "Node" and "NUMANode" strings are supported as in earlier releases. +* Detection improvements + + Add support for Intel Knights Landing Xeon Phi. + Thanks to Grzegorz Andrejczuk and Lukasz Anaczkowski. + + Add Vendor, Model, Revision, SerialNumber, Type and LinuxDeviceID + info attributes to Block OS devices on Linux. Thanks to Vineet Pedaballe + for the help. + - Add --disable-libudev to avoid dependency on the libudev library. + + Add "MemoryDevice" Misc objects with information about DIMMs, on Linux + when privileged and when I/O is enabled. + Thanks to Vineet Pedaballe for the help. + + Add a PCISlot attribute to PCI devices on Linux when supported to + identify the physical PCI slot where the board is plugged. + + Add CPUStepping info attribute on x86 processors, + thanks to Thomas Röhl for the suggestion. + + Ignore the device-tree on non-Power architectures to avoid buggy + detection on ARM. Thanks to Orion Poplawski for reporting the issue. + + Work-around buggy Xeon E5v3 BIOS reporting invalid PCI-NUMA affinity + for the PCI links on the second processor. + + Add support for CUDA compute capability 5.x, thanks Benjamin Worpitz. + + Many fixes to the x86 backend + - Add L1i and fix L2/L3 type on old AMD processors without topoext support. + - Fix Intel CPU family and model numbers when basic family isn't 6 or 15. + - Fix package IDs on recent AMD processors. + - Fix misc issues due to incomplete APIC IDs on x2APIC processors. + - Avoid buggy discovery on old SGI Altix UVs with non-unique APIC IDs. + + Gather total machine memory on NetBSD. +* Tools + + lstopo + - Collapse identical PCI devices unless --no-collapse is given. + This avoids gigantic outputs when a PCI device contains dozens of + identical virtual functions. + - The ASCII art output is now called "ascii", for instance in + "lstopo -.ascii". + The former "txt" extension is retained for backward compatibility. + - Automatically scales graphical box width to the inner text in Cairo, + ASCII and Windows outputs. + - Add --rect to lstopo to force rectangular layout even for NUMA nodes. + - Objects may have a Type info attribute to specific a better type name + and display it in lstopo. + + hwloc-annotate + - May now operate on all types of objects, including I/O. + - May now insert Misc objects in the topology. + - Do not drop instruction caches and I/O devices from the output anymore. + + Fix lstopo path in hwloc-gather-topology after install. +* Misc + + Fix PCI Bridge-specific depth attribute. + + Fix hwloc_bitmap_intersect() for two infinite bitmaps. + + Improve the performance of object insertion by cpuset for large + topologies. + + Prefix verbose XML import errors with the source name. + + Improve pkg-config checks and error messages. + + Fix excluding after a component with an argument in the HWLOC_COMPONENTS + environment variable. + + Fix the recommended way in documentation and examples to allocate memory + on some node, it should use HWLOC_MEMBIND_BIND. + Thanks to Nicolas Bouzat for reporting the issue. + + Add a "Miscellaneous objects" section in the documentation. + + Add a FAQ entry "What happens to my topology if I disable symmetric + multithreading, hyper-threading, etc. ?" to the documentation. + + +Version 1.10.1 +-------------- +* Actually remove disallowed NUMA nodes from nodesets when the whole-system + flag isn't enabled. +* Fix the gathering of PCI domains. Thanks to James Custer for reporting + the issue and providing a patch. +* Fix the merging of identical parent and child in presence of Misc objects. + Thanks to Dave Love for reporting the issue. +* Fix some misordering of children when merging with ignore_keep_structure() + in partially allowed topologies. +* Fix an overzealous assertion in the debug code when running on a single-PU + host with I/O. Thanks to Thomas Van Doren for reporting the issue. +* Don't forget to setup NUMA node object nodesets in x86 backend (for BSDs) + and OSF/Tru64 backend. +* Fix cpuid-x86 build error with gcc -O3 on x86-32. Thanks to Thomas Van Doren + for reporting the issue. +* Fix support for future very large caches in the x86 backend. +* Fix vendor/device names for SR-IOV PCI devices on Linux. +* Fix an unlikely crash in case of buggy hierarchical distance matrix. +* Fix PU os_index on some AIX releases. Thanks to Hendryk Bockelmann and + Erik Schnetter for helping debugging. +* Fix hwloc_bitmap_isincluded() in case of infinite sets. +* Change hwloc-ls.desktop into a lstopo.desktop and only install it if + lstopo is built with Cairo/X11 support. It cannot work with a non-graphical + lstopo or hwloc-ls. +* Add support for the renaming of Socket into Package in future releases. +* Add support for the replacement of HWLOC_OBJ_NODE with HWLOC_OBJ_NUMANODE + in future releases. +* Clarify the documentation of distance matrices in hwloc.h and in the manpage + of the hwloc-distances. Thanks to Dave Love for the suggestion. +* Improve some error messages by displaying more information about the + hwloc library in use. +* Document how to deal with the ABI break when upgrading to the upcoming 2.0 + See "How do I handle ABI breaks and API upgrades ?" in the FAQ. + + +Version 1.10.0 +-------------- +* API + + Add hwloc_topology_export_synthetic() to export a topology to a + synthetic string without using lstopo. See the Synthetic topologies + section in the documentation. + + Add hwloc_topology_set/get_userdata() to let the application save + a private pointer in the topology whenever it needs a way to find + its own object corresponding to a topology. + + Add hwloc_get_numanode_obj_by_os_index() and document that this function + as well as hwloc_get_pu_obj_by_os_index() are good at converting + nodesets and cpusets into objects. + + hwloc_distrib() does not ignore any objects anymore when there are + too many of them. They get merged with others instead. + Thanks to Tim Creech for reporting the issue. +* Tools + + hwloc-bind --get now executes the command after displaying + the binding instead of ignoring the command entirely. + Thanks to John Donners for the suggestion. + + Clarify that memory sizes shown in lstopo are local by default + unless specified (total memory added in the root object). +* Synthetic topologies + + Synthetic topology descriptions may now specify attributes such as + memory sizes and OS indexes. See the Synthetic topologies section + in the documentation. + + lstopo now exports in this fully-detailed format by default. + The new option --export-synthetic-flags may be used to revert + back the old format. +* Documentation + + Add the doc/examples/ subdirectory with several real-life examples, + including the already existing hwloc-hello.C for basics. + Thanks to Rob Aulwes for the suggestion. + + Improve the documentation of CPU and memory binding in the API. + + Add a FAQ entry about operating system errors, especially on AMD + platforms with buggy cache information. + + Add a FAQ entry about loading many topologies in a single program. +* Misc + + Work around buggy Linux kernels reporting 2 sockets instead + 1 socket with 2 NUMA nodes for each Xeon E5 v3 (Haswell) processor. + + pciutils/libpci support is now removed since libpciaccess works + well and there's also a Linux-specific PCI backend. For the record, + pciutils was GPL and therefore disabled by default since v1.6.2. + + Add --disable-cpuid configure flag to work around buggy processor + simulators reporting invalid CPUID information. + Thanks for Andrew Friedley for reporting the issue. + + Fix a racy use of libltdl when manipulating multiple topologies in + different threads. + Thanks to Andra Hugo for reporting the issue and testing patches. + + Fix some build failures in private/misc.h. + Thanks to Pavan Balaji and Ralph Castain for the reports. + + Fix failures to detect X11/Xutil.h on some Solaris platforms. + Thanks to Siegmar Gross for reporting the failure. + + The plugin ABI has changed, this release will not load plugins + built against previous hwloc releases. + + +Version 1.9.1 +------------- +* Fix a crash when the PCI locality is invalid. Attach to the root object + instead. Thanks to Nicolas Denoyelle for reporting the issue. +* Fix -f in lstopo manpage. Thanks to Jirka Hladky for reporting the issue. +* Fix hwloc_obj_type_sscanf() and others when strncasecmp() is not properly + available. Thanks to Nick Papior Andersen for reporting the problem. +* Mark Linux file descriptors as close-on-exec to avoid leaks on exec. +* Fix some minor memory leaks. + + +Version 1.9.0 +------------- +* API + + Add hwloc_obj_type_sscanf() to extend hwloc_obj_type_of_string() with + type-specific attributes such as Cache/Group depth and Cache type. + hwloc_obj_type_of_string() is moved to hwloc/deprecated.h. + + Add hwloc_linux_get_tid_last_cpu_location() for retrieving the + last CPU where a Linux thread given by TID ran. + + Add hwloc_distrib() to extend the old hwloc_distribute[v]() functions. + hwloc_distribute[v]() is moved to hwloc/deprecated.h. + + Don't mix total and local memory when displaying verbose object attributes + with hwloc_obj_attr_snprintf() or in lstopo. +* Backends + + Add CPUVendor, CPUModelNumber and CPUFamilyNumber info attributes for + x86, ia64 and Xeon Phi sockets on Linux, to extend the x86-specific + support added in v1.8.1. Requested by Ralph Castain. + + Add many CPU- and Platform-related info attributes on ARM and POWER + platforms, in the Machine and Socket objects. + + Add CUDA info attributes describing the number of multiprocessors and + cores and the size of the global, shared and L2 cache memories in CUDA + OS devices. + + Add OpenCL info attributes describing the number of compute units and + the global memory size in OpenCL OS devices. + + The synthetic backend now accepts extended types such as L2Cache, L1i or + Group3. lstopo also exports synthetic strings using these extended types. +* Tools + + lstopo + - Do not overwrite output files by default anymore. + Pass -f or --force to enforce it. + - Display OpenCL, CUDA and Xeon Phi numbers of cores and memory sizes + in the graphical output. + - Fix export to stdout when specifying a Cairo-based output type + with --of. + + hwloc-ps + - Add -e or --get-last-cpu-location to report where processes/threads + run instead of where they are bound. + - Report locations as likely-more-useful objects such as Cores or Sockets + instead of Caches when possible. + + hwloc-bind + - Fix failure on Windows when not using --pid. + - Add -e as a synonym to --get-last-cpu-location. + + hwloc-distrib + - Add --reverse to distribute using last objects first and singlify + into last bits first. Thanks to Jirka Hladky for the suggestion. + + hwloc-info + - Report unified caches when looking for data or instruction cache + ancestor objects. +* Misc + + Add experimental Visual Studio support under contrib/windows. + Thanks to Eloi Gaudry for his help and for providing the first draft. + + Fix some overzealous assertions and warnings about the ordering of + objects on a level with respect to cpusets. The ordering is only + guaranteed for complete cpusets (based on the first bit in sets). + + Fix some memory leaks when importing xml diffs and when exporting a + "too complex" entry. + + +Version 1.8.1 +------------- +* Fix the cpuid code on Windows 64bits so that the x86 backend gets + enabled as expected and can populate CPU information. + Thanks to Robin Scher for reporting the problem. +* Add CPUVendor/CPUModelNumber/CPUFamilyNumber attributes when running + on x86 architecture. Thanks to Ralph Castain for the suggestion. +* Work around buggy BIOS reporting duplicate NUMA nodes on Linux. + Thanks to Jeff Becker for reporting the problem and testing the patch. +* Add a name to the lstopo graphical window. Thanks to Michael Prokop + for reporting the issue. + + +Version 1.8.0 +------------- +* New components + + Add the "linuxpci" component that always works on Linux even when + libpciaccess and libpci aren't available (and even with a modified + file-system root). By default the old "pci" component runs first + because "linuxpci" lacks device names (obj->name is always NULL). +* API + + Add the topology difference API in hwloc/diff.h for manipulating + many similar topologies. + + Add hwloc_topology_dup() for duplicating an entire topology. + + hwloc.h and hwloc/helper.h have been reorganized to clarify the + documentation sections. The actual inline code has moved out of hwloc.h + into the new hwloc/inlines.h. + + Deprecated functions are now in hwloc/deprecated.h, and not in the + official documentation anymore. +* Tools + + Add hwloc-diff and hwloc-patch tools together with the new diff API. + + Add hwloc-compress-dir to (de)compress an entire directory of XML files + using hwloc-diff and hwloc-patch. + + Object colors in the graphical output of lstopo may be changed by adding + a "lstopoStyle" info attribute. See CUSTOM COLORS in the lstopo(1) manpage + for details. Thanks to Jirka Hladky for discussing the idea. + + hwloc-gather-topology may now gather I/O-related files on Linux when + --io is given. Only the linuxpci component supports discovering I/O + objects from these extended tarballs. + + hwloc-annotate now supports --ri to remove/replace info attributes with + a given name. + + hwloc-info supports "root" and "all" special locations for dumping + information about the root object. + + lstopo now supports --append-legend to append custom lines of text + to the legend in the graphical output. Thanks to Jirka Hladky for + discussing the idea. + + hwloc-calc and friends have a more robust parsing of locations given + on the command-line and they report useful error messages about it. + + Add --whole-system to hwloc-bind, hwloc-calc, hwloc-distances and + hwloc-distrib, and add --restrict to hwloc-bind for uniformity among + tools. +* Misc + + Calling hwloc_topology_load() or hwloc_topology_set_*() on an already + loaded topology now returns an error (deprecated since release 1.6.1). + + Fix the initialisation of cpusets and nodesets in Group objects added + when inserting PCI hostbridges. + + Never merge Group objects that were added explicitly by the user with + hwloc_custom_insert_group_object_by_parent(). + + Add a sanity check during dynamic plugin loading to prevent some + crashes when hwloc is dynamically loaded by another plugin mechanisms. + + Add --with-hwloc-plugins-path to specify the install/load directories + of plugins. + + Add the MICSerialNumber info attribute to the root object when running + hwloc inside a Xeon Phi to match the same attribute in the MIC OS device + when running in the host. + + +Version 1.7.2 +------------- +* Do not create invalid block OS devices on very old Linux kernel such + as RHEL4 2.6.9. +* Fix PCI subvendor/device IDs. +* Fix the management of Misc objects inserted by parent. + Thanks to Jirka Hladky for reporting the problem. +* Add a PortState into attribute to OpenFabrics OS devices. +* Add a MICSerialNumber info attribute to Xeon PHI/MIC OS devices. +* Improve verbose error messages when failing to load from XML. + + +Version 1.7.1 +------------- +* Fix a failed assertion in the distance grouping code when loading a XML + file that already contains some groups. + Thanks to Laercio Lima Pilla for reporting the problem. +* Remove unexpected Group objects when loading XML topologies with I/O + objects and NUMA distances. + Thanks to Elena Elkina for reporting the problem and testing patches. +* Fix PCI link speed discovery when using libpciaccess. +* Fix invalid libpciaccess virtual function device/vendor IDs when using + SR-IOV PCI devices on Linux. +* Fix GL component build with old NVCtrl releases. + Thanks to Jirka Hladky for reporting the problem. +* Fix embedding breakage caused by libltdl. + Thanks to Pavan Balaji for reporting the problem. +* Always use the system-wide libltdl instead of shipping one inside hwloc. +* Document issues when enabling plugins while embedding hwloc in another + project, in the documentation section Embedding hwloc in Other Software. +* Add a FAQ entry "How to get useful topology information on NetBSD?" + in the documentation. +* Somes fixes in the renaming code for embedding. +* Miscellaneous minor build fixes. + + +Version 1.7.0 +------------- +* New operating system backends + + Add BlueGene/Q compute node kernel (CNK) support. See the FAQ in the + documentation for details. Thanks to Jeff Hammond, Christopher Samuel + and Erik Schnetter for their help. + + Add NetBSD support, thanks to Aleksej Saushev. +* New I/O device discovery + + Add co-processor OS devices such as "mic0" for Intel Xeon Phi (MIC) + on Linux. Thanks to Jerome Vienne for helping. + + Add co-processor OS devices such as "cuda0" for NVIDIA CUDA-capable GPUs. + + Add co-processor OS devices such as "opencl0d0" for OpenCL GPU devices + on the AMD OpenCL implementation. + + Add GPU OS devices such as ":0.0" for NVIDIA X11 displays. + + Add GPU OS devices such as "nvml0" for NVIDIA GPUs. + Thanks to Marwan Abdellah and Stefan Eilemann for helping. + These new OS devices have some string info attributes such as CoProcType, + GPUModel, etc. to better identify them. + See the I/O Devices and Attributes documentation sections for details. +* New components + + Add the "opencl", "cuda", "nvml" and "gl" components for I/O device + discovery. + + "nvml" also improves the discovery of NVIDIA GPU PCIe link speed. + All of these new components may be built as plugins. They may also be + disabled entirely by passing --disable-opencl/cuda/nvml/gl to configure. + See the I/O Devices, Components and Plugins, and FAQ documentation + sections for details. +* API + + Add hwloc_topology_get_flags(). + + Add hwloc/plugins.h for building external plugins. + See the Adding new discovery components and plugins section. +* Interoperability + + Add hwloc/opencl.h, hwloc/nvml.h, hwloc/gl.h and hwloc/intel-mic.h + to retrieve the locality of OS devices that correspond to AMD OpenCL + GPU devices or indexes, to NVML devices or indexes, to NVIDIA X11 + displays, or to Intel Xeon Phi (MIC) device indexes. + + Add new helpers in hwloc/cuda.h and hwloc/cudart.h to convert + between CUDA devices or indexes and hwloc OS devices. + + Add hwloc_ibv_get_device_osdev() and clarify the requirements + of the OpenFabrics Verbs helpers in hwloc/openfabrics-verbs.h. +* Tools + + hwloc-info is not only a synonym of lstopo -s anymore, it also + dumps information about objects given on the command-line. +* Documentation + + Add a section "Existing components and plugins". + + Add a list of common OS devices in section "Software devices". + + Add a new FAQ entry "Why is lstopo slow?" about lstopo slowness + issues because of GPUs. + + Clarify the documentation of inline helpers in hwloc/myriexpress.h + and hwloc/openfabrics-verbs.h. +* Misc + + Improve cache detection on AIX. + + The HWLOC_COMPONENTS variable now excludes the components whose + names are prefixed with '-'. + + lstopo --ignore PU now works when displaying the topology in + graphical and textual mode (not when exporting to XML). + + Make sure I/O options always appear in lstopo usage, not only when + using pciutils/libpci. + + Remove some unneeded Linux specific includes from some interoperability + headers. + + Fix some inconsistencies in hwloc-distrib and hwloc-assembler-remote + manpages. Thanks to Guy Streeter for the report. + + Fix a memory leak on AIX when getting memory binding. + + Fix many small memory leaks on Linux. + + The `libpci' component is now called `pci' but the old name is still + accepted in the HWLOC_COMPONENTS variable for backward compatibility. + + +Version 1.6.2 +------------- +* Use libpciaccess instead of pciutils/libpci by default for I/O discovery. + pciutils/libpci is only used if --enable-libpci is given to configure + because its GPL license may taint hwloc. See the Installation section + in the documentation for details. +* Fix get_cpubind on Solaris when bound to a single PU with + processor_bind(). Thanks to Eugene Loh for reporting the problem + and providing a patch. + + +Version 1.6.1 +------------- +* Fix some crash or buggy detection in the x86 backend when Linux + cgroups/cpusets restrict the available CPUs. +* Fix the pkg-config output with --libs --static. + Thanks to Erik Schnetter for reporting one of the problems. +* Fix the output of hwloc-calc -H --hierarchical when using logical + indexes in the output. +* Calling hwloc_topology_load() multiple times on the same topology + is officially deprecated. hwloc will warn in such cases. +* Add some documentation about existing plugins/components, package + dependencies, and I/O devices specification on the command-line. + + +Version 1.6.0 +------------- +* Major changes + + Reorganize the backend infrastructure to support dynamic selection + of components and dynamic loading of plugins. For details, see the + new documentation section Components and plugins. + - The HWLOC_COMPONENTS variable lets one replace the default discovery + components. + - Dynamic loading of plugins may be enabled with --enable-plugins + (except on AIX and Windows). It will build libxml2 and libpci + support as separated modules. This helps reducing the dependencies + of the core hwloc library when distributed as a binary package. +* Backends + + Add CPUModel detection on Darwin and x86/FreeBSD. + Thanks to Robin Scher for providing ways to implement this. + + The x86 backend now adds CPUModel info attributes to socket objects + created by other backends that do not natively support this attribute. + + Fix detection on FreeBSD in case of cpuset restriction. Thanks to + Sebastian Kuzminsky for reporting the problem. +* XML + + Add hwloc_topology_set_userdata_import/export_callback(), + hwloc_export_obj_userdata() and _userdata_base64() to let + applications specify how to save/restore the custom data they placed + in the userdata private pointer field of hwloc objects. +* Tools + + Add hwloc-annotate program to add string info attributes to XML + topologies. + + Add --pid-cmd to hwloc-ps to append the output of a command to each + PID line. May be used for showing Open MPI process ranks, see the + hwloc-ps(1) manpage for details. + + hwloc-bind now exits with an error if binding fails; the executable + is not launched unless binding suceeeded or --force was given. + + Add --quiet to hwloc-calc and hwloc-bind to hide non-fatal error + messages. + + Fix command-line pid support in windows tools. + + All programs accept --verbose as a synonym to -v. +* Misc + + Fix some DIR descriptor leaks on Linux. + + Fix I/O device lists when some were filtered out after a XML import. + + Fix the removal of I/O objects when importing a I/O-enabled XML topology + without any I/O topology flag. + + When merging objects with HWLOC_IGNORE_TYPE_KEEP_STRUCTURE or + lstopo --merge, compare object types before deciding which one of two + identical object to remove (e.g. keep sockets in favor of caches). + + Add some GUID- and LID-related info attributes to OpenFabrics + OS devices. + + Only add CPUType socket attributes on Solaris/Sparc. Other cases + don't report reliable information (Solaris/x86), and a replacement + is available as the Architecture string info in the Machine object. + + Add missing Backend string info on Solaris in most cases. + + Document object attributes and string infos in a new Attributes + section in the documentation. + + Add a section about Synthetic topologies in the documentation. + + +Version 1.5.2 (some of these changes are in v1.6.2 but not in v1.6) +------------- +* Use libpciaccess instead of pciutils/libpci by default for I/O discovery. + pciutils/libpci is only used if --enable-libpci is given to configure + because its GPL license may taint hwloc. See the Installation section + in the documentation for details. +* Fix get_cpubind on Solaris when bound to a single PU with + processor_bind(). Thanks to Eugene Loh for reporting the problem + and providing a patch. +* Fix some DIR descriptor leaks on Linux. +* Fix I/O device lists when some were filtered out after a XML import. +* Add missing Backend string info on Solaris in most cases. +* Fix the removal of I/O objects when importing a I/O-enabled XML topology + without any I/O topology flag. +* Fix the output of hwloc-calc -H --hierarchical when using logical + indexes in the output. +* Fix the pkg-config output with --libs --static. + Thanks to Erik Schnetter for reporting one of the problems. + + +Version 1.5.1 +------------- +* Fix block OS device detection on Linux kernel 3.3 and later. + Thanks to Guy Streeter for reporting the problem and testing the fix. +* Fix the cpuid code in the x86 backend (for FreeBSD). Thanks to + Sebastian Kuzminsky for reporting problems and testing patches. +* Fix 64bit detection on FreeBSD. +* Fix some corner cases in the management of the thissystem flag with + respect to topology flags and environment variables. +* Fix some corner cases in command-line parsing checks in hwloc-distrib + and hwloc-distances. +* Make sure we do not miss some block OS devices on old Linux kernels + when a single PCI device has multiple IDE hosts/devices behind it. +* Do not disable I/O devices or instruction caches in hwloc-assembler output. + + +Version 1.5.0 +------------- +* Backends + + Do not limit the number of processors to 1024 on Solaris anymore. + + Gather total machine memory on FreeBSD. Thanks to Cyril Roelandt. + + XML topology files do not depend on the locale anymore. Float numbers + such as NUMA distances or PCI link speeds now always use a dot as a + decimal separator. + + Add instruction caches detection on Linux, AIX, Windows and Darwin. + + Add get_last_cpu_location() support for the current thread on AIX. + + Support binding on AIX when threads or processes were bound with + bindprocessor(). Thanks to Hendryk Bockelmann for reporting the issue + and testing patches, and to Farid Parpia for explaining the binding + interfaces. + + Improve AMD topology detection in the x86 backend (for FreeBSD) using + the topoext feature. +* API + + Increase HWLOC_API_VERSION to 0x00010500 so that API changes may be + detected at build-time. + + Add a cache type attribute describind Data, Instruction and Unified + caches. Caches with different types but same depth (for instance L1d + and L1i) are placed on different levels. + + Add hwloc_get_cache_type_depth() to retrieve the hwloc level depth of + of the given cache depth and type, for instance L1i or L2. + It helps disambiguating the case where hwloc_get_type_depth() returns + HWLOC_TYPE_DEPTH_MULTIPLE. + + Instruction caches are ignored unless HWLOC_TOPOLOGY_FLAG_ICACHES is + passed to hwloc_topology_set_flags() before load. + + Add hwloc_ibv_get_device_osdev_by_name() OpenFabrics helper in + openfabrics-verbs.h to find the hwloc OS device object corresponding to + an OpenFabrics device. +* Tools + + Add lstopo-no-graphics, a lstopo built without graphical support to + avoid dependencies on external libraries such as Cairo and X11. When + supported, graphical outputs are only available in the original lstopo + program. + - Packagers splitting lstopo and lstopo-no-graphics into different + packages are advised to use the alternatives system so that lstopo + points to the best available binary. + + Instruction caches are enabled in lstopo by default. Use --no-icaches + to disable them. + + Add -t/--threads to show threads in hwloc-ps. +* Removal of obsolete components + + Remove the old cpuset interface (hwloc/cpuset.h) which is deprecated and + superseded by the bitmap API (hwloc/bitmap.h) since v1.1. + hwloc_cpuset and nodeset types are still defined, but all hwloc_cpuset_* + compatibility wrappers are now gone. + + Remove Linux libnuma conversion helpers for the deprecated and + broken nodemask_t interface. + + Remove support for "Proc" type name, it was superseded by "PU" in v1.0. + + Remove hwloc-mask symlinks, it was replaced by hwloc-calc in v1.0. +* Misc + + Fix PCIe 3.0 link speed computation. + + Non-printable characters are dropped from strings during XML export. + + Fix importing of escaped characters with the minimalistic XML backend. + + Assert hwloc_is_thissystem() in several I/O related helpers. + + Fix some memory leaks in the x86 backend for FreeBSD. + + Minor fixes to ease native builds on Windows. + + Limit the number of retries when operating on all threads within a + process on Linux if the list of threads is heavily getting modified. + + +Version 1.4.3 +------------- +* This release is only meant to fix the pciutils license issue when upgrading + to hwloc v1.5 or later is not possible. It contains several other minor + fixes but ignores many of them that are only in v1.5 or later. +* Use libpciaccess instead of pciutils/libpci by default for I/O discovery. + pciutils/libpci is only used if --enable-libpci is given to configure + because its GPL license may taint hwloc. See the Installation section + in the documentation for details. +* Fix PCIe 3.0 link speed computation. +* Fix importing of escaped characters with the minimalistic XML backend. +* Fix a memory leak in the x86 backend. + + +Version 1.4.2 +------------- +* Fix build on Solaris 9 and earlier when fabsf() is not a compiler + built-in. Thanks to Igor Galić for reporting the problem. +* Fix support for more than 32 processors on Windows. Thanks to Hartmut + Kaiser for reporting the problem. +* Fix process-wide binding and cpulocation routines on Linux when some + threads disappear in the meantime. Thanks to Vlad Roubtsov for reporting + the issue. +* Make installed scripts executable. Thanks to Jirka Hladky for reporting + the problem. +* Fix libtool revision management when building for Windows. This fix was + also released as hwloc v1.4.1.1 Windows builds. Thanks to Hartmut Kaiser + for reporting the problem. +* Fix the __hwloc_inline keyword in public headers when compiling with a + C++ compiler. +* Add Port info attribute to network OS devices inside OpenFabrics PCI + devices so as to identify which interface corresponds to which port. +* Document requirements for interoperability helpers: I/O devices discovery + is required for some of them; the topology must match the current host + for most of them. + + +Version 1.4.1 +------------- +* This release contains all changes from v1.3.2. +* Fix hwloc_alloc_membind, thanks Karl Napf for reporting the issue. +* Fix memory leaks in some get_membind() functions. +* Fix helpers converting from Linux libnuma to hwloc (hwloc/linux-libnuma.h) + in case of out-of-order NUMA node ids. +* Fix some overzealous assertions in the distance grouping code. +* Workaround BIOS reporting empty I/O locality in CUDA and OpenFabrics + helpers on Linux. Thanks to Albert Solernou for reporting the problem. +* Install a valgrind suppressions file hwloc-valgrind.supp (see the FAQ). +* Fix memory binding documentation. Thanks to Karl Napf for reporting the + issues. + + +Version 1.4.0 (does not contain all v1.3.2 changes) +------------- +* Major features + + Add "custom" interface and "assembler" tools to build multi-node + topology. See the Multi-node Topologies section in the documentation + for details. +* Interface improvements + + Add symmetric_subtree object attribute to ease assumptions when consulting + regular symmetric topologies. + + Add a CPUModel and CPUType info attribute to Socket objects on Linux + and Solaris. + + Add hwloc_get_obj_index_inside_cpuset() to retrieve the "logical" index + of an object within a subtree of the topology. + + Add more NVIDIA CUDA helpers in cuda.h and cudart.h to find hwloc objects + corresponding to CUDA devices. +* Discovery improvements + + Add a group object above partial distance matrices to make sure + the matrices are available in the final topology, except when this + new object would contradict the existing hierarchy. + + Grouping by distances now also works when loading from XML. + + Fix some corner cases in object insertion, for instance when dealing + with NUMA nodes without any CPU. +* Backends + + Implement hwloc_get_area_membind() on Linux. + + Honor I/O topology flags when importing from XML. + + Further improve XML-related error checking and reporting. + + Hide synthetic topology error messages unless HWLOC_SYNTHETIC_VERBOSE=1. +* Tools + + Add synthetic exporting of symmetric topologies to lstopo. + + lstopo --horiz and --vert can now be applied to some specific object types. + + lstopo -v -p now displays distance matrices with physical indexes. + + Add hwloc-distances utility to list distances. +* Documentation + + Fix and/or document the behavior of most inline functions in hwloc/helper.h + when the topology contains some I/O or Misc objects. + + Backend documentation enhancements. +* Bug fixes + + Fix missing last bit in hwloc_linux_get_thread_cpubind(). + Thanks to Carolina Gómez-Tostón Gutiérrez for reporting the issue. + + Fix FreeBSD build without cpuid support. + + Fix several Windows build issues. + + Fix inline keyword definition in public headers. + + Fix dependencies in the embedded library. + + Improve visibility support detection. Thanks to Dave Love for providing + the patch. + + Remove references to internal symbols in the tools. + + +Version 1.3.3 +------------- +* This release is only meant to fix the pciutils license issue when upgrading + to hwloc v1.4 or later is not possible. It contains several other minor + fixes but ignores many of them that are only in v1.4 or later. +* Use libpciaccess instead of pciutils/libpci by default for I/O discovery. + pciutils/libpci is only used if --enable-libpci is given to configure + because its GPL license may taint hwloc. See the Installation section + in the documentation for details. + + +Version 1.3.2 +------------- +* Fix missing last bit in hwloc_linux_get_thread_cpubind(). + Thanks to Carolina Gómez-Tostón Gutiérrez for reporting the issue. +* Fix build with -mcmodel=medium. Thanks to Devendar Bureddy for reporting + the issue. +* Fix build with Solaris Studio 12 compiler when XML is disabled. + Thanks to Paul H. Hargrove for reporting the problem. +* Fix installation with old GNU sed, for instance on Red Hat 8. + Thanks to Paul H. Hargrove for reporting the problem. +* Fix PCI locality when Linux cgroups restrict the available CPUs. +* Fix floating point issue when grouping by distance on mips64 architecture. + Thanks to Paul H. Hargrove for reporting the problem. +* Fix conversion from/to Linux libnuma when some NUMA nodes have no memory. +* Fix support for gccfss compilers with broken ffs() support. Thanks to + Paul H. Hargrove for reporting the problem and providing a patch. +* Fix FreeBSD build without cpuid support. +* Fix several Windows build issues. +* Fix inline keyword definition in public headers. +* Fix dependencies in the embedded library. +* Detect when a compiler such as xlc may not report compile errors + properly, causing some configure checks to be wrong. Thanks to + Paul H. Hargrove for reporting the problem and providing a patch. +* Improve visibility support detection. Thanks to Dave Love for providing + the patch. +* Remove references to internal symbols in the tools. +* Fix installation on systems with limited command-line size. + Thanks to Paul H. Hargrove for reporting the problem. +* Further improve XML-related error checking and reporting. + + +Version 1.3.1 +------------- +* Fix pciutils detection with pkg-config when not installed in standard + directories. +* Fix visibility options detection with the Solaris Studio compiler. + Thanks to Igor Galić and Terry Dontje for reporting the problems. +* Fix support for old Linux sched.h headers such as those found + on Red Hat 8. Thanks to Paul H. Hargrove for reporting the problems. +* Fix inline and attribute support for Solaris compilers. Thanks to + Dave Love for reporting the problems. +* Print a short summary at the end of the configure output. Thanks to + Stefan Eilemann for the suggestion. +* Add --disable-libnuma configure option to disable libnuma-based + memory binding support on Linux. Thanks to Rayson Ho for the + suggestion. +* Make hwloc's configure script properly obey $PKG_CONFIG. Thanks to + Nathan Phillip Brink for raising the issue. +* Silence some harmless pciutils warnings, thanks to Paul H. Hargrove + for reporting the problem. +* Fix the documentation with respect to hwloc_pid_t and hwloc_thread_t + being either pid_t and pthread_t on Unix, or HANDLE on Windows. + + +Version 1.3.0 +------------- +* Major features + + Add I/O devices and bridges to the topology using the pciutils + library. Only enabled after setting the relevant flag with + hwloc_topology_set_flags() before hwloc_topology_load(). See the + I/O Devices section in the documentation for details. +* Discovery improvements + + Add associativity to the cache attributes. + + Add support for s390/z11 "books" on Linux. + + Add the HWLOC_GROUPING_ACCURACY environment variable to relax + distance-based grouping constraints. See the Environment Variables + section in the documentation for details about grouping behavior + and configuration. + + Allow user-given distance matrices to remove or replace those + discovered by the OS backend. +* XML improvements + + XML is now always supported: a minimalistic custom import/export + code is used when libxml2 is not available. It is only guaranteed + to read XML files generated by hwloc. + + hwloc_topology_export_xml() and export_xmlbuffer() now return an + integer. + + Add hwloc_free_xmlbuffer() to free the buffer allocated by + hwloc_topology_export_xmlbuffer(). + + Hide XML topology error messages unless HWLOC_XML_VERBOSE=1. +* Minor API updates + + Add hwloc_obj_add_info to customize object info attributes. +* Tools + + lstopo now displays I/O devices by default. Several options are + added to configure the I/O discovery. + + hwloc-calc and hwloc-bind now accept I/O devices as input. + + Add --restrict option to hwloc-calc and hwloc-distribute. + + Add --sep option to change the output field separator in hwloc-calc. + + Add --whole-system option to hwloc-ps. + + +Version 1.2.2 +------------- +* Fix build on AIX 5.2, thanks Utpal Kumar Ray for the report. +* Fix XML import of very large page sizes or counts on 32bits platform, + thanks to Karsten Hopp for the RedHat ticket. +* Fix crash when administrator limitations such as Linux cgroup require + to restrict distance matrices. Thanks to Ake Sandgren for reporting the + problem. +* Fix the removal of objects such as AMD Magny-Cours dual-node sockets + in case of administrator restrictions. +* Improve error reporting and messages in case of wrong synthetic topology + description. +* Several other minor internal fixes and documentation improvements. + + +Version 1.2.1 +------------- +* Improve support of AMD Bulldozer "Compute-Unit" modules by detecting + logical processors with different core IDs on Linux. +* Fix hwloc-ps crash when listing processes from another Linux cpuset. + Thanks to Carl Smith for reporting the problem. +* Fix build on AIX and Solaris. Thanks to Carl Smith and Andreas Kupries + for reporting the problems. +* Fix cache size detection on Darwin. Thanks to Erkcan Özcan for reporting + the problem. +* Make configure fail if --enable-xml or --enable-cairo is given and + proper support cannot be found. Thanks to Andreas Kupries for reporting + the XML problem. +* Fix spurious L1 cache detection on AIX. Thanks to Hendryk Bockelmann + for reporting the problem. +* Fix hwloc_get_last_cpu_location(THREAD) on Linux. Thanks to Gabriele + Fatigati for reporting the problem. +* Fix object distance detection on Solaris. +* Add pthread_self weak symbol to ease static linking. +* Minor documentation fixes. + + +Version 1.2.0 +------------- +* Major features + + Expose latency matrices in the API as an array of distance structures + within objects. Add several helpers to find distances. + + Add hwloc_topology_set_distance_matrix() and environment variables + to provide a matrix of distances between a given set of objects. + + Add hwloc_get_last_cpu_location() and hwloc_get_proc_last_cpu_location() + to retrieve the processors where a process or thread recently ran. + - Add the corresponding --get-last-cpu-location option to hwloc-bind. + + Add hwloc_topology_restrict() to restrict an existing topology to a + given cpuset. + - Add the corresponding --restrict option to lstopo. +* Minor API updates + + Add hwloc_bitmap_list_sscanf/snprintf/asprintf to convert between bitmaps + and strings such as 4-5,7-9,12,15- + + hwloc_bitmap_set/clr_range() now support infinite ranges. + + Clarify the difference between inserting Misc objects by cpuset or by + parent. + + hwloc_insert_misc_object_by_cpuset() now returns NULL in case of error. +* Discovery improvements + + x86 backend (for freebsd): add x2APIC support + + Support standard device-tree phandle, to get better support on e.g. ARM + systems providing it. + + Detect cache size on AIX. Thanks Christopher and IBM. + + Improve grouping to support asymmetric topologies. +* Tools + + Command-line tools now support "all" and "root" special locations + consisting in the entire topology, as well as type names with depth + attributes such as L2 or Group4. + + hwloc-calc improvements: + - Add --number-of/-N option to report the number of objects of a given + type or depth. + - -I is now equivalent to --intersect for listing the indexes of + objects of a given type or depth that intersects the input. + - Add -H to report the output as a hierarchical combination of types + and depths. + + Add --thissystem to lstopo. + + Add lstopo-win, a console-less lstopo variant on Windows. +* Miscellaneous + + Remove C99 usage from code base. + + Rename hwloc-gather-topology.sh into hwloc-gather-topology + + Fix AMD cache discovery on freebsd when there is no L3 cache, thanks + Andriy Gapon for the fix. + + +Version 1.1.2 +------------- +* Fix a segfault in the distance-based grouping code when some objects + are not placed in any group. Thanks to Bernd Kallies for reporting + the problem and providing a patch. +* Fix the command-line parsing of hwloc-bind --mempolicy interleave. + Thanks to Guy Streeter for reporting the problem. +* Stop truncating the output in hwloc_obj_attr_snprintf() and in the + corresponding lstopo output. Thanks to Guy Streeter for reporting the + problem. +* Fix object levels ordering in synthetic topologies. +* Fix potential incoherency between device tree and kernel information, + when SMT is disabled on Power machines. +* Fix and document the behavior of hwloc_topology_set_synthetic() in case + of invalid argument. Thanks to Guy Streeter for reporting the problem. +* Add some verbose error message reporting when it looks like the OS + gives erroneous information. +* Do not include unistd.h and stdint.h in public headers on Windows. +* Move config.h files into their own subdirectories to avoid name + conflicts when AC_CONFIG_HEADERS adds -I's for them. +* Remove the use of declaring variables inside "for" loops. +* Some other minor fixes. +* Many minor documentation fixes. + + +Version 1.1.1 +------------- +* Add hwloc_get_api_version() which returns the version of hwloc used + at runtime. Thanks to Guy Streeter for the suggestion. +* Fix the number of hugepages reported for NUMA nodes on Linux. +* Fix hwloc_bitmap_to_ulong() right after allocating the bitmap. + Thanks to Bernd Kallies for reporting the problem. +* Fix hwloc_bitmap_from_ith_ulong() to properly zero the first ulong. + Thanks to Guy Streeter for reporting the problem. +* Fix hwloc_get_membind_nodeset() on Linux. + Thanks to Bernd Kallies for reporting the problem and providing a patch. +* Fix some file descriptor leaks in the Linux discovery. +* Fix the minimum width of NUMA nodes, caches and the legend in the graphical + lstopo output. Thanks to Jirka Hladky for reporting the problem. +* Various fixes to bitmap conversion from/to taskset-strings. +* Fix and document snprintf functions behavior when the buffer size is too + small or zero. Thanks to Guy Streeter for reporting the problem. +* Fix configure to avoid spurious enabling of the cpuid backend. + Thanks to Tim Anderson for reporting the problem. +* Cleanup error management in hwloc-gather-topology.sh. + Thanks to Jirka Hladky for reporting the problem and providing a patch. +* Add a manpage and usage for hwloc-gather-topology.sh on Linux. + Thanks to Jirka Hladky for providing a patch. +* Memory binding documentation enhancements. + + +Version 1.1.0 +------------- + +* API + + Increase HWLOC_API_VERSION to 0x00010100 so that API changes may be + detected at build-time. + + Add a memory binding interface. + + The cpuset API (hwloc/cpuset.h) is now deprecated. It is replaced by + the bitmap API (hwloc/bitmap.h) which offers the same features with more + generic names since it applies to CPU sets, node sets and more. + Backward compatibility with the cpuset API and ABI is still provided but + it will be removed in a future release. + Old types (hwloc_cpuset_t, ...) are still available as a way to clarify + what kind of hwloc_bitmap_t each API function manipulates. + Upgrading to the new API only requires to replace hwloc_cpuset_ function + calls with the corresponding hwloc_bitmap_ calls, with the following + renaming exceptions: + - hwloc_cpuset_cpu -> hwloc_bitmap_only + - hwloc_cpuset_all_but_cpu -> hwloc_bitmap_allbut + - hwloc_cpuset_from_string -> hwloc_bitmap_sscanf + + Add an `infos' array in each object to store couples of info names and + values. It enables generic storage of things like the old dmi board infos + that were previously stored in machine specific attributes. + + Add linesize cache attribute. +* Features + + Bitmaps (and thus CPU sets and node sets) are dynamically (re-)allocated, + the maximal number of CPUs (HWLOC_NBMAXCPUS) has been removed. + + Improve the distance-based grouping code to better support irregular + distance matrices. + + Add support for device-tree to get cache information (useful on Power + architectures). +* Helpers + + Add NVIDIA CUDA helpers in cuda.h and cudart.h to ease interoperability + with CUDA Runtime and Driver APIs. + + Add Myrinet Express helper in myriexpress.h to ease interoperability. +* Tools + + lstopo now displays physical/OS indexes by default in graphical mode + (use -l to switch back to logical indexes). The textual output still uses + logical by default (use -p to switch to physical indexes). + + lstopo prefixes logical indexes with `L#' and physical indexes with `P#'. + Physical indexes are also printed as `P#N' instead of `phys=N' within + object attributes (in parentheses). + + Add a legend at the bottom of the lstopo graphical output, use --no-legend + to remove it. + + Add hwloc-ps to list process' bindings. + + Add --membind and --mempolicy options to hwloc-bind. + + Improve tools command-line options by adding a generic --input option + (and more) which replaces the old --xml, --synthetic and --fsys-root. + + Cleanup lstopo output configuration by adding --output-format. + + Add --intersect in hwloc-calc, and replace --objects with --largest. + + Add the ability to work on standard input in hwloc-calc. + + Add --from, --to and --at in hwloc-distrib. + + Add taskset-specific functions and command-line tools options to + manipulate CPU set strings in the format of the taskset program. + + Install hwloc-gather-topology.sh on Linux. + + +Version 1.0.3 +------------- + +* Fix support for Linux cpuset when emulated by a cgroup mount point. +* Remove unneeded runtime dependency on libibverbs.so in the library and + all utils programs. +* Fix hwloc_cpuset_to_linux_libnuma_ulongs in case of non-linear OS-indexes + for NUMA nodes. +* lstopo now displays physical/OS indexes by default in graphical mode + (use -l to switch back to logical indexes). The textual output still uses + logical by default (use -p to switch to physical indexes). + + +Version 1.0.2 +------------- + +* Public headers can now be included directly from C++ programs. +* Solaris fix for non-contiguous cpu numbers. Thanks to Rolf vandeVaart for + reporting the issue. +* Darwin 10.4 fix. Thanks to Olivier Cessenat for reporting the issue. +* Revert 1.0.1 patch that ignored sockets with unknown ID values since it + only slightly helped POWER7 machines with old Linux kernels while it + prevents recent kernels from getting the complete POWER7 topology. +* Fix hwloc_get_common_ancestor_obj(). +* Remove arch-specific bits in public headers. +* Some fixes in the lstopo graphical output. +* Various man page clarifications and minor updates. + + +Version 1.0.1 +------------- + +* Various Solaris fixes. Thanks to Yannick Martin for reporting the issue. +* Fix "non-native" builds on x86 platforms (e.g., when building 32 + bit executables with compilers that natively build 64 bit). +* Ignore sockets with unknown ID values (which fixes issues on POWER7 + machines). Thanks to Greg Bauer for reporting the issue. +* Various man page clarifications and minor updates. +* Fixed memory leaks in hwloc_setup_group_from_min_distance_clique(). +* Fix cache type filtering on MS Windows 7. Thanks to Αλέξανδρος + Παπαδογιαννάκ for reporting the issue. +* Fixed warnings when compiling with -DNDEBUG. + + +Version 1.0.0 +------------- + +* The ABI of the library has changed. +* Backend updates + + Add FreeBSD support. + + Add x86 cpuid based backend. + + Add Linux cgroup support to the Linux cpuset code. + + Support binding of entire multithreaded process on Linux. + + Fix and enable Group support in Windows. + + Cleanup XML export/import. +* Objects + + HWLOC_OBJ_PROC is renamed into HWLOC_OBJ_PU for "Processing Unit", + its stringified type name is now "PU". + + Use new HWLOC_OBJ_GROUP objects instead of MISC when grouping + objects according to NUMA distances or arbitrary OS aggregation. + + Rework memory attributes. + + Add different cpusets in each object to specify processors that + are offline, unavailable, ... + + Cleanup the storage of object names and DMI infos. +* Features + + Add support for looking up specific PID topology information. + + Add hwloc_topology_export_xml() to export the topology in a XML file. + + Add hwloc_topology_get_support() to retrieve the supported features + for the current topology context. + + Support non-SYSTEM object as the root of the tree, use MACHINE in + most common cases. + + Add hwloc_get_*cpubind() routines to retrieve the current binding + of processes and threads. +* API + + Add HWLOC_API_VERSION to help detect the currently used API version. + + Add missing ending "e" to *compare* functions. + + Add several routines to emulate PLPA functions. + + Rename and rework the cpuset and/or/xor/not/clear operators to output + their result in a dedicated argument instead of modifying one input. + + Deprecate hwloc_obj_snprintf() in favor of hwloc_obj_type/attr_snprintf(). + + Clarify the use of parent and ancestor in the API, do not use father. + + Replace hwloc_get_system_obj() with hwloc_get_root_obj(). + + Return -1 instead of HWLOC_OBJ_TYPE_MAX in the API since the latter + isn't public. + + Relax constraints in hwloc_obj_type_of_string(). + + Improve displaying of memory sizes. + + Add 0x prefix to cpuset strings. +* Tools + + lstopo now displays logical indexes by default, use --physical to + revert back to OS/physical indexes. + + Add colors in the lstopo graphical outputs to distinguish between online, + offline, reserved, ... objects. + + Extend lstopo to show cpusets, filter objects by type, ... + + Renamed hwloc-mask into hwloc-calc which supports many new options. +* Documentation + + Add a hwloc(7) manpage containing general information. + + Add documentation about how to switch from PLPA to hwloc. + + Cleanup the distributed documentation files. +* Miscellaneous + + Many compilers warning fixes. + + Cleanup the ABI by using the visibility attribute. + + Add project embedding support. + + +Version 0.9.4 (unreleased) +-------------------------- + +* Fix reseting colors to normal in lstopo -.txt output. +* Fix Linux pthread_t binding error report. + + +Version 0.9.3 +------------- + +* Fix autogen.sh to work with Autoconf 2.63. +* Fix various crashes in particular conditions: + - xml files with root attributes + - offline CPUs + - partial sysfs support + - unparseable /proc/cpuinfo + - ignoring NUMA level while Misc level have been generated +* Tweak documentation a bit +* Do not require the pthread library for binding the current thread on Linux +* Do not erroneously consider the sched_setaffinity prototype is the old version + when there is actually none. +* Fix _syscall3 compilation on archs for which we do not have the + sched_setaffinity system call number. +* Fix AIX binding. +* Fix libraries dependencies: now only lstopo depends on libtermcap, fix + binutils-gold link +* Have make check always build and run hwloc-hello.c +* Do not limit size of a cpuset. + + +Version 0.9.2 +------------- + +* Trivial documentation changes. + + +Version 0.9.1 +------------- + +* Re-branded to "hwloc" and moved to the Open MPI project, relicensed under the + BSD license. +* The prefix of all functions and tools is now hwloc, and some public + functions were also renamed for real. +* Group NUMA nodes into Misc objects according to their physical distance + that may be reported by the OS/BIOS. + May be ignored by setting HWLOC_IGNORE_DISTANCES=1 in the environment. +* Ignore offline CPUs on Solaris. +* Improved binding support on AIX. +* Add HP-UX support. +* CPU sets are now allocated/freed dynamically. +* Add command line options to tune the lstopo graphical output, add + semi-graphical textual output +* Extend topobind to support multiple cpusets or objects on the command + line as topomask does. +* Add an Infiniband-specific helper hwloc/openfabrics-verbs.h to retrieve + the physical location of IB devices. + + +Version 0.9 (libtopology) +------------------------- + +* First release. diff --git a/opal/mca/hwloc/hwloc1110/hwloc/README b/opal/mca/hwloc/hwloc1110/hwloc/README new file mode 100644 index 0000000000..fed93191f9 --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/README @@ -0,0 +1,612 @@ +Introduction + +hwloc provides command line tools and a C API to obtain the hierarchical map of +key computing elements, such as: NUMA memory nodes, shared caches, processor +packages, processor cores, processing units (logical processors or "threads") +and even I/O devices. hwloc also gathers various attributes such as cache and +memory information, and is portable across a variety of different operating +systems and platforms. Additionally it may assemble the topologies of multiple +machines into a single one so as to let applications consult the topology of an +entire fabric or cluster at once. + +hwloc primarily aims at helping high-performance computing (HPC) applications, +but is also applicable to any project seeking to exploit code and/or data +locality on modern computing platforms. + +Note that the hwloc project represents the merger of the libtopology project +from inria and the Portable Linux Processor Affinity (PLPA) sub-project from +Open MPI. Both of these prior projects are now deprecated. The first hwloc +release was essentially a "re-branding" of the libtopology code base, but with +both a few genuinely new features and a few PLPA-like features added in. Prior +releases of hwloc included documentation about switching from PLPA to hwloc; +this documentation has been dropped on the assumption that everyone who was +using PLPA has already switched to hwloc. + +hwloc supports the following operating systems: + + * Linux (including old kernels not having sysfs topology information, with + knowledge of cpusets, offline CPUs, ScaleMP vSMP, NumaScale NumaConnect, + and Kerrighed support) on all supported hardware, including Intel Xeon Phi + (either standalone or as a coprocessor). + * Solaris + * AIX + * Darwin / OS X + * FreeBSD and its variants (such as kFreeBSD/GNU) + * NetBSD + * OSF/1 (a.k.a., Tru64) + * HP-UX + * Microsoft Windows + * IBM BlueGene/Q Compute Node Kernel (CNK) + +Since it uses standard Operating System information, hwloc's support is mostly +independant from the processor type (x86, powerpc, ...) and just relies on the +Operating System support. The only exception to this is kFreeBSD, which does +not support topology information, and hwloc thus uses an x86-only CPUID-based +backend (which can be used for other OSes too, see the Components and plugins +section). + +To check whether hwloc works on a particular machine, just try to build it and +run lstopo or lstopo-no-graphics. If some things do not look right (e.g. bogus +or missing cache information), see Questions and Bugs below. + +hwloc only reports the number of processors on unsupported operating systems; +no topology information is available. + +For development and debugging purposes, hwloc also offers the ability to work +on "fake" topologies: + + * Symmetrical tree of resources generated from a list of level arities + * Remote machine simulation through the gathering of Linux sysfs topology + files + +hwloc can display the topology in a human-readable format, either in graphical +mode (X11), or by exporting in one of several different formats, including: +plain text, PDF, PNG, and FIG (see CLI Examples below). Note that some of the +export formats require additional support libraries. + +hwloc offers a programming interface for manipulating topologies and objects. +It also brings a powerful CPU bitmap API that is used to describe topology +objects location on physical/logical processors. See the Programming Interface +below. It may also be used to binding applications onto certain cores or memory +nodes. Several utility programs are also provided to ease command-line +manipulation of topology objects, binding of processes, and so on. + +Perl bindings are available from Bernd Kallies on CPAN. + +Python bindings are available from Guy Streeter: + + * Fedora RPM and tarball. + * git tree (html). + +Installation + +hwloc (http://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:// +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. +It just happens to be hosted as part of the overall Open MPI project. + +Nightly development snapshots are available on the web site. Additionally, the +code can be directly cloned from Git: + +shell$ git clone https://github.com/open-mpi/hwloc.git +shell$ cd hwloc +shell$ ./autogen.sh + +Note that GNU Autoconf >=2.63, Automake >=1.10 and Libtool >=2.2.6 are required +when building from a Git clone. + +Installation by itself is the fairly common GNU-based process: + +shell$ ./configure --prefix=... +shell$ make +shell$ make install + +The hwloc command-line tool "lstopo" produces human-readable topology maps, as +mentioned above. It can also export maps to the "fig" file format. Support for +PDF, Postscript, and PNG exporting is provided if the "Cairo" development +package (usually cairo-devel or libcairo2-dev) can be found in "lstopo" when +hwloc is configured and build. + +The hwloc core may also benefit from the following development packages: + + * libnuma for memory binding and migration support on Linux (numactl-devel or + libnuma-dev package). + * libpciaccess for full I/O device discovery (libpciaccess-devel or + libpciaccess-dev package). On Linux, PCI discovery may still be performed + (without vendor/device names) even if libpciaccess cannot be used. + + * the AMD OpenCL implementation for OpenCL device discovery. + * the NVIDIA CUDA Toolkit for CUDA device discovery. + * the NVIDIA Tesla Development Kit for NVML device discovery. + * the NV-CONTROL X extension library (NVCtrl) for NVIDIA display discovery. + * libxml2 for full XML import/export support (otherwise, the internal + minimalistic parser will only be able to import XML files that were + exported by the same hwloc release). See Importing and exporting topologies + from/to XML files for details. The relevant development package is usually + libxml2-devel or libxml2-dev. + * libudev on Linux for easier discovery of OS device information (otherwise + hwloc will try to manually parse udev raw files). The relevant development + package is usually libudev-devel or libudev-dev. + * libtool's ltdl library for dynamic plugin loading. The relevant development + package is usually libtool-ltdl-devel or libltdl-dev. + +PCI and XML support may be statically built inside the main hwloc library, or +as separate dynamically-loaded plugins (see the Components and plugins +section). + +Note that because of the possibility of GPL taint, the pciutils library libpci +will not be used (remember that hwloc is BSD-licensed). + +Also note that if you install supplemental libraries in non-standard locations, +hwloc's configure script may not be able to find them without some help. You +may need to specify additional CPPFLAGS, LDFLAGS, or PKG_CONFIG_PATH values on +the configure command line. + +For example, if libpciaccess was installed into /opt/pciaccess, hwloc's +configure script may not find it be default. Try adding PKG_CONFIG_PATH to the +./configure command line, like this: + +./configure PKG_CONFIG_PATH=/opt/pciaccess/lib/pkgconfig ... + +CLI Examples + +On a 4-package 2-core machine with hyper-threading, the lstopo tool may show +the following graphical output: + +dudley.png + +Here's the equivalent output in textual form: + +Machine (16GB) + Package L#0 + L3 L#0 (4096KB) + L2 L#0 (1024KB) + L1 L#0 (16KB) + Core L#0 + PU L#0 (P#0) + PU L#1 (P#8) + L2 L#1 (1024KB) + L1 L#1 (16KB) + Core L#1 + PU L#2 (P#4) + PU L#3 (P#12) + Package L#1 + L3 L#1 (4096KB) + L2 L#2 (1024KB) + L1 L#2 (16KB) + Core L#2 + PU L#4 (P#1) + PU L#5 (P#9) + L2 L#3 (1024KB) + L1 L#3 (16KB) + Core L#3 + PU L#6 (P#5) + PU L#7 (P#13) + Package L#2 + L3 L#2 (4096KB) + L2 L#4 (1024KB) + L1 L#4 (16KB) + Core L#4 + PU L#8 (P#2) + PU L#9 (P#10) + L2 L#5 (1024KB) + L1 L#5 (16KB) + Core L#5 + PU L#10 (P#6) + PU L#11 (P#14) + Package L#3 + L3 L#3 (4096KB) + L2 L#6 (1024KB) + L1 L#6 (16KB) + Core L#6 + PU L#12 (P#3) + PU L#13 (P#11) + L2 L#7 (1024KB) + L1 L#7 (16KB) + Core L#7 + PU L#14 (P#7) + PU L#15 (P#15) + +Note that there is also an equivalent output in XML that is meant for exporting +/importing topologies but it is hardly readable to human-beings (see Importing +and exporting topologies from/to XML files for details). + +On a 4-package 2-core Opteron NUMA machine, the lstopo tool may show the +following graphical output: + +hagrid.png + +Here's the equivalent output in textual form: + +Machine (32GB) + NUMANode L#0 (P#0 8190MB) + Package L#0 + L2 L#0 (1024KB) + L1 L#0 (64KB) + Core L#0 + PU L#0 (P#0) + L2 L#1 (1024KB) + L1 L#1 (64KB) + Core L#1 + PU L#1 (P#1) + NUMANode L#1 (P#1 8192MB) + Package L#1 + L2 L#2 (1024KB) + L1 L#2 (64KB) + Core L#2 + PU L#2 (P#2) + L2 L#3 (1024KB) + L1 L#3 (64KB) + Core L#3 + PU L#3 (P#3) + NUMANode L#2 (P#2 8192MB) + Package L#2 + L2 L#4 (1024KB) + L1 L#4 (64KB) + Core L#4 + PU L#4 (P#4) + L2 L#5 (1024KB) + L1 L#5 (64KB) + Core L#5 + PU L#5 (P#5) + NUMANode L#3 (P#3 8192MB) + Package L#3 + L2 L#6 (1024KB) + L1 L#6 (64KB) + Core L#6 + PU L#6 (P#6) + L2 L#7 (1024KB) + L1 L#7 (64KB) + Core L#7 + PU L#7 (P#7) + +On a 2-package quad-core Xeon (pre-Nehalem, with 2 dual-core dies into each +package): + +emmett.png + +Here's the same output in textual form: + +Machine (16GB) + Package L#0 + L2 L#0 (4096KB) + L1 L#0 (32KB) + Core L#0 + PU L#0 (P#0) + L1 L#1 (32KB) + Core L#1 + PU L#1 (P#4) + L2 L#1 (4096KB) + L1 L#2 (32KB) + Core L#2 + PU L#2 (P#2) + L1 L#3 (32KB) + Core L#3 + PU L#3 (P#6) + Package L#1 + L2 L#2 (4096KB) + L1 L#4 (32KB) + Core L#4 + PU L#4 (P#1) + L1 L#5 (32KB) + Core L#5 + PU L#5 (P#5) + L2 L#3 (4096KB) + L1 L#6 (32KB) + Core L#6 + PU L#6 (P#3) + L1 L#7 (32KB) + Core L#7 + PU L#7 (P#7) + +Programming Interface + +The basic interface is available in hwloc.h. Some higher-level functions are +available in hwloc/helper.h to reduce the need to manually manipulate objects +and follow links between them. Documentation for all these is provided later in +this document. Developers may also want to look at hwloc/inlines.h which +contains the actual inline code of some hwloc.h routines, and at this document, +which provides good higher-level topology traversal examples. + +To precisely define the vocabulary used by hwloc, a Terms and Definitions +section is available and should probably be read first. + +Each hwloc object contains a cpuset describing the list of processing units +that it contains. These bitmaps may be used for CPU binding and Memory binding. +hwloc offers an extensive bitmap manipulation interface in hwloc/bitmap.h. + +Moreover, hwloc also comes with additional helpers for interoperability with +several commonly used environments. See the Interoperability With Other +Software section for details. + +The complete API documentation is available in a full set of HTML pages, man +pages, and self-contained PDF files (formatted for both both US letter and A4 +formats) in the source tarball in doc/doxygen-doc/. + +NOTE: If you are building the documentation from a Git clone, you will need to +have Doxygen and pdflatex installed -- the documentation will be built during +the normal "make" process. The documentation is installed during "make install" +to $prefix/share/doc/hwloc/ and your systems default man page tree (under +$prefix, of course). + +Portability + +As shown in CLI Examples, hwloc can obtain information on a wide variety of +hardware topologies. However, some platforms and/or operating system versions +will only report a subset of this information. For example, on an PPC64-based +system with 32 cores (each with 2 hardware threads) running a default +2.6.18-based kernel from RHEL 5.4, hwloc is only able to glean information +about NUMA nodes and processor units (PUs). No information about caches, +packages, or cores is available. + +Similarly, Operating System have varying support for CPU and memory binding, +e.g. while some Operating Systems provide interfaces for all kinds of CPU and +memory bindings, some others provide only interfaces for a limited number of +kinds of CPU and memory binding, and some do not provide any binding interface +at all. Hwloc's binding functions would then simply return the ENOSYS error +(Function not implemented), meaning that the underlying Operating System does +not provide any interface for them. CPU binding and Memory binding provide more +information on which hwloc binding functions should be preferred because +interfaces for them are usually available on the supported Operating Systems. + +Here's the graphical output from lstopo on this platform when Simultaneous +Multi-Threading (SMT) is enabled: + +ppc64-with-smt.png + +And here's the graphical output from lstopo on this platform when SMT is +disabled: + +ppc64-without-smt.png + +Notice that hwloc only sees half the PUs when SMT is disabled. PU #15, for +example, seems to change location from NUMA node #0 to #1. In reality, no PUs +"moved" -- they were simply re-numbered when hwloc only saw half as many. +Hence, PU #15 in the SMT-disabled picture probably corresponds to PU #30 in the +SMT-enabled picture. + +This same "PUs have disappeared" effect can be seen on other platforms -- even +platforms / OSs that provide much more information than the above PPC64 system. +This is an unfortunate side-effect of how operating systems report information +to hwloc. + +Note that upgrading the Linux kernel on the same PPC64 system mentioned above +to 2.6.34, hwloc is able to discover all the topology information. The +following picture shows the entire topology layout when SMT is enabled: + +ppc64-full-with-smt.png + +Developers using the hwloc API or XML output for portable applications should +therefore be extremely careful to not make any assumptions about the structure +of data that is returned. For example, per the above reported PPC topology, it +is not safe to assume that PUs will always be descendants of cores. + +Additionally, future hardware may insert new topology elements that are not +available in this version of hwloc. Long-lived applications that are meant to +span multiple different hardware platforms should also be careful about making +structure assumptions. For example, there may someday be an element "lower" +than a PU, or perhaps a new element may exist between a core and a PU. + +API Example + +The following small C example (named ``hwloc-hello.c'') prints the topology of +the machine and bring the process to the first logical processor of the second +core of the machine. More examples are available in the doc/examples/ directory +of the source tree. + +/* Example hwloc API program. + * + * See other examples under doc/examples/ in the source tree + * for more details. + * + * Copyright (c) 2009-2015 Inria. All rights reserved. + * Copyright (c) 2009-2011 Universit?eacute; Bordeaux + * Copyright (c) 2009-2010 Cisco Systems, Inc. All rights reserved. + * See COPYING in top-level directory. + * + * hwloc-hello.c + */ + +#include +#include +#include +#include + +static void print_children(hwloc_topology_t topology, hwloc_obj_t obj, + int depth) +{ + char type[32], attr[1024]; + unsigned i; + + hwloc_obj_type_snprintf(type, sizeof(type), obj, 0); + printf("%*s%s", 2*depth, "", type); + if (obj->os_index != (unsigned) -1) + printf("#%u", obj->os_index); + hwloc_obj_attr_snprintf(attr, sizeof(attr), obj, " ", 0); + if (*attr) + printf("(%s)", attr); + printf("\n"); + for (i = 0; i < obj->arity; i++) { + print_children(topology, obj->children[i], depth + 1); + } +} + +int main(void) +{ + int depth; + unsigned i, n; + unsigned long size; + int levels; + char string[128]; + int topodepth; + hwloc_topology_t topology; + hwloc_cpuset_t cpuset; + hwloc_obj_t obj; + + /* Allocate and initialize topology object. */ + hwloc_topology_init(&topology); + + /* ... Optionally, put detection configuration here to ignore + some objects types, define a synthetic topology, etc.... + + The default is to detect all the objects of the machine that + the caller is allowed to access. See Configure Topology + Detection. */ + + /* Perform the topology detection. */ + hwloc_topology_load(topology); + + /* Optionally, get some additional topology information + in case we need the topology depth later. */ + topodepth = hwloc_topology_get_depth(topology); + + /***************************************************************** + * First example: + * Walk the topology with an array style, from level 0 (always + * the system level) to the lowest level (always the proc level). + *****************************************************************/ + for (depth = 0; depth < topodepth; depth++) { + printf("*** Objects at level %d\n", depth); + for (i = 0; i < hwloc_get_nbobjs_by_depth(topology, depth); + i++) { + hwloc_obj_type_snprintf(string, sizeof(string), + hwloc_get_obj_by_depth +(topology, depth, i), 0); + printf("Index %u: %s\n", i, string); + } + } + + /***************************************************************** + * Second example: + * Walk the topology with a tree style. + *****************************************************************/ + printf("*** Printing overall tree\n"); + print_children(topology, hwloc_get_root_obj(topology), 0); + + /***************************************************************** + * Third example: + * Print the number of packages. + *****************************************************************/ + depth = hwloc_get_type_depth(topology, HWLOC_OBJ_PACKAGE); + if (depth == HWLOC_TYPE_DEPTH_UNKNOWN) { + printf("*** The number of packages is unknown\n"); + } else { + printf("*** %u package(s)\n", + hwloc_get_nbobjs_by_depth(topology, depth)); + } + + /***************************************************************** + * Fourth example: + * Compute the amount of cache that the first logical processor + * has above it. + *****************************************************************/ + levels = 0; + size = 0; + for (obj = hwloc_get_obj_by_type(topology, HWLOC_OBJ_PU, 0); + obj; + obj = obj->parent) + if (obj->type == HWLOC_OBJ_CACHE) { + levels++; + size += obj->attr->cache.size; + } + printf("*** Logical processor 0 has %d caches totaling %luKB\n", + levels, size / 1024); + + /***************************************************************** + * Fifth example: + * Bind to only one thread of the last core of the machine. + * + * First find out where cores are, or else smaller sets of CPUs if + * the OS doesn't have the notion of a "core". + *****************************************************************/ + depth = hwloc_get_type_or_below_depth(topology, HWLOC_OBJ_CORE); + + /* Get last core. */ + obj = hwloc_get_obj_by_depth(topology, depth, + hwloc_get_nbobjs_by_depth(topology, depth) - 1); + if (obj) { + /* Get a copy of its cpuset that we may modify. */ + cpuset = hwloc_bitmap_dup(obj->cpuset); + + /* Get only one logical processor (in case the core is + SMT/hyper-threaded). */ + hwloc_bitmap_singlify(cpuset); + + /* And try to bind ourself there. */ + if (hwloc_set_cpubind(topology, cpuset, 0)) { + char *str; + int error = errno; + hwloc_bitmap_asprintf(&str, obj->cpuset); + printf("Couldn't bind to cpuset %s: %s\n", str, strerror(error)); + free(str); + } + + /* Free our cpuset copy */ + hwloc_bitmap_free(cpuset); + } + + /***************************************************************** + * Sixth example: + * Allocate some memory on the last NUMA node, bind some existing + * memory to the last NUMA node. + *****************************************************************/ + /* Get last node. */ + n = hwloc_get_nbobjs_by_type(topology, HWLOC_OBJ_NUMANODE); + if (n) { + void *m; + size = 1024*1024; + + obj = hwloc_get_obj_by_type(topology, HWLOC_OBJ_NUMANODE, n - 1); + m = hwloc_alloc_membind_nodeset(topology, size, obj->nodeset, + HWLOC_MEMBIND_BIND, 0); + hwloc_free(topology, m, size); + + m = malloc(size); + hwloc_set_area_membind_nodeset(topology, m, size, obj->nodeset, + HWLOC_MEMBIND_BIND, 0); + free(m); + } + + /* Destroy topology object. */ + hwloc_topology_destroy(topology); + + return 0; +} + +hwloc provides a pkg-config executable to obtain relevant compiler and linker +flags. For example, it can be used thusly to compile applications that utilize +the hwloc library (assuming GNU Make): + +CFLAGS += $(pkg-config --cflags hwloc) +LDLIBS += $(pkg-config --libs hwloc) +cc hwloc-hello.c $(CFLAGS) -o hwloc-hello $(LDLIBS) + +On a machine with 4GB of RAM and 2 processor packages -- each package of which +has two processing cores -- the output from running hwloc-hello could be +something like the following: + +shell$ ./hwloc-hello +*** Objects at level 0 +Index 0: Machine(3938MB) +*** Objects at level 1 +Index 0: Package#0 +Index 1: Package#1 +*** Objects at level 2 +Index 0: Core#0 +Index 1: Core#1 +Index 2: Core#3 +Index 3: Core#2 +*** Objects at level 3 +Index 0: PU#0 +Index 1: PU#1 +Index 2: PU#2 +Index 3: PU#3 +*** Printing overall tree +Machine(3938MB) + Package#0 + Core#0 + PU#0 + Core#1 + PU#1 + Package#1 + Core#3 + PU#2 + Core#2 + PU#3 +*** 2 package(s) +shell$ + +Questions and Bugs + +Questions should be sent to the devel mailing list (http://www.open-mpi.org/ +community/lists/hwloc.php). Bug reports should be reported in the tracker ( +https://git.open-mpi.org/trac/hwloc/). + +If hwloc discovers an incorrect topology for your machine, the very first thing +you should check is to ensure that you have the most recent updates installed +for your operating system. Indeed, most of hwloc topology discovery relies on +hardware information retrieved through the operation system (e.g., via the /sys +virtual filesystem of the Linux kernel). If upgrading your OS or Linux kernel +does not solve your problem, you may also want to ensure that you are running +the most recent version of the BIOS for your machine. + +If those things fail, contact us on the mailing list for additional help. +Please attach the output of lstopo after having given the --enable-debug option +to ./configure and rebuilt completely, to get debugging output. Also attach the +/proc + /sys tarball generated by the installed script hwloc-gather-topology +when submitting problems about Linux, or send the output of kstat cpu_info in +the Solaris case, or the output of sysctl hw in the Darwin or BSD cases. + +History / Credits + +hwloc is the evolution and merger of the libtopology (http:// +runtime.bordeaux.inria.fr/libtopology/) project and the Portable Linux +Processor Affinity (PLPA) (http://www.open-mpi.org/projects/plpa/) project. +Because of functional and ideological overlap, these two code bases and ideas +were merged and released under the name "hwloc" as an Open MPI sub-project. + +libtopology was initially developed by the inria Runtime Team-Project (http:// +runtime.bordeaux.inria.fr/) (headed by Raymond Namyst (http:// +dept-info.labri.fr/~namyst/). PLPA was initially developed by the Open MPI +development team as a sub-project. Both are now deprecated in favor of hwloc, +which is distributed as an Open MPI sub-project. + +Further Reading + +The documentation chapters include + + * Terms and Definitions + * Command-Line Tools + * Environment Variables + * CPU and Memory Binding Overview + * I/O Devices + * Miscellaneous objects + * Multi-node Topologies + * Object attributes + * Importing and exporting topologies from/to XML files + * Synthetic topologies + * Interoperability With Other Software + * Thread Safety + * Components and plugins + * Embedding hwloc in Other Software + * Frequently Asked Questions + +Make sure to have had a look at those too! + diff --git a/opal/mca/hwloc/hwloc1110/hwloc/VERSION b/opal/mca/hwloc/hwloc1110/hwloc/VERSION new file mode 100644 index 0000000000..5ccd593891 --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/VERSION @@ -0,0 +1,42 @@ +# This is the VERSION file for hwloc, describing the precise version +# of hwloc in this distribution. The various components of the version +# number below are combined to form a single version number string. + +# major, minor, and release are generally combined in the form +# ... If release is zero, then it is omitted. + +major=1 +minor=11 +release=0 + +# greek is used for alpha or beta release tags. If it is non-empty, +# it will be appended to the version number. It does not have to be +# numeric. Common examples include a1 (alpha release 1), b1 (beta +# release 1), sc2005 (Super Computing 2005 release). The only +# requirement is that it must be entirely printable ASCII characters +# and have no white space. + +greek=rc1 + +# The date when this release was created + +date="Jun 02, 2015" + +# If snapshot=1, then use the value from snapshot_version as the +# entire hwloc version (i.e., ignore major, minor, release, and +# greek). This is only set to 1 when making snapshot tarballs. +snapshot=0 +snapshot_version=${major}.${minor}.${release}${greek}-git + +# The shared library version of hwloc's public library. This version +# is maintained in accordance with the "Library Interface Versions" +# chapter from the GNU Libtool documentation. Notes: + +# 1. Since version numbers are associated with *releases*, the version +# number maintained on the hwloc git master (and developer branches) +# is always 0:0:0. + +# 2. Version numbers are described in the Libtool current:revision:age +# format. + +libhwloc_so_version=11:6:6 diff --git a/opal/mca/hwloc/hwloc1110/hwloc/config/distscript.sh b/opal/mca/hwloc/hwloc1110/hwloc/config/distscript.sh new file mode 100755 index 0000000000..d72a3fd305 --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/config/distscript.sh @@ -0,0 +1,130 @@ +#!/bin/sh -f +# +# Copyright © 2004-2005 The Trustees of Indiana University and Indiana +# University Research and Technology +# Corporation. All rights reserved. +# Copyright © 2004-2005 The University of Tennessee and The University +# of Tennessee Research Foundation. All rights +# reserved. +# Copyright © 2004-2005 High Performance Computing Center Stuttgart, +# University of Stuttgart. All rights reserved. +# Copyright © 2004-2005 The Regents of the University of California. +# All rights reserved. +# Copyright © 2010-2014 Inria. All rights reserved. +# Copyright © 2009-2014 Cisco Systems, Inc. All rights reserved. +# $COPYRIGHT$ +# +# Additional copyrights may follow +# +# $HEADER$ +# + +builddir="`pwd`" + +srcdir=$1 +cd "$srcdir" +srcdir=`pwd` +cd "$builddir" + +distdir="$builddir/$2" +HWLOC_VERSION=$3 + +if test "$distdir" = ""; then + echo "Must supply relative distdir as argv[2] -- aborting" + exit 1 +elif test "$HWLOC_VERSION" = ""; then + echo "Must supply version as argv[1] -- aborting" + exit 1 +fi + +#======================================================================== + +start=`date` +cat < header file.]) + ]) + AC_CHECK_HEADERS([sys/mman.h]) + + old_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS -D_WIN32_WINNT=0x0601" + AC_CHECK_TYPES([KAFFINITY, + PROCESSOR_CACHE_TYPE, + CACHE_DESCRIPTOR, + LOGICAL_PROCESSOR_RELATIONSHIP, + RelationProcessorPackage, + SYSTEM_LOGICAL_PROCESSOR_INFORMATION, + GROUP_AFFINITY, + PROCESSOR_RELATIONSHIP, + NUMA_NODE_RELATIONSHIP, + CACHE_RELATIONSHIP, + PROCESSOR_GROUP_INFO, + GROUP_RELATIONSHIP, + SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, + PSAPI_WORKING_SET_EX_BLOCK, + PSAPI_WORKING_SET_EX_INFORMATION], + [],[],[[#include ]]) + CPPFLAGS="$old_CPPFLAGS" + AC_CHECK_LIB([gdi32], [main], + [HWLOC_LIBS="-lgdi32 $HWLOC_LIBS" + AC_DEFINE([HAVE_LIBGDI32], 1, [Define to 1 if we have -lgdi32])]) + + AC_CHECK_HEADER([windows.h], [ + AC_DEFINE([HWLOC_HAVE_WINDOWS_H], [1], [Define to 1 if you have the `windows.h' header.]) + ]) + + AC_CHECK_HEADERS([sys/lgrp_user.h], [ + AC_CHECK_LIB([lgrp], [lgrp_latency_cookie], + [HWLOC_LIBS="-llgrp $HWLOC_LIBS" + AC_DEFINE([HAVE_LIBLGRP], 1, [Define to 1 if we have -llgrp])]) + ]) + AC_CHECK_HEADERS([kstat.h], [ + AC_CHECK_LIB([kstat], [main], + [HWLOC_LIBS="-lkstat $HWLOC_LIBS" + AC_DEFINE([HAVE_LIBKSTAT], 1, [Define to 1 if we have -lkstat])]) + ]) + + AC_CHECK_DECLS([fabsf], [ + AC_CHECK_LIB([m], [fabsf], + [HWLOC_LIBS="-lm $HWLOC_LIBS"]) + ], [], [[#include ]]) + + AC_CHECK_HEADERS([picl.h], [ + AC_CHECK_LIB([picl], [picl_initialize], + [HWLOC_LIBS="-lpicl $HWLOC_LIBS"])]) + + AC_CHECK_DECLS([_SC_NPROCESSORS_ONLN, + _SC_NPROCESSORS_CONF, + _SC_NPROC_ONLN, + _SC_NPROC_CONF, + _SC_PAGESIZE, + _SC_PAGE_SIZE, + _SC_LARGE_PAGESIZE],,[:],[[#include ]]) + + AC_HAVE_HEADERS([mach/mach_host.h]) + AC_HAVE_HEADERS([mach/mach_init.h], [ + AC_CHECK_FUNCS([host_info]) + ]) + + AC_CHECK_HEADERS([sys/param.h]) + AC_CHECK_HEADERS([sys/sysctl.h], [ + AC_CHECK_DECLS([CTL_HW, HW_NCPU],,,[[ + #if HAVE_SYS_PARAM_H + #include + #endif + #include + ]]) + ],,[ + AC_INCLUDES_DEFAULT + #if HAVE_SYS_PARAM_H + #include + #endif + ]) + + AC_CHECK_DECLS([strtoull], [], [], [AC_INCLUDES_DEFAULT]) + + # Do a full link test instead of just using AC_CHECK_FUNCS, which + # just checks to see if the symbol exists or not. For example, + # the prototype of sysctl uses u_int, which on some platforms + # (such as FreeBSD) is only defined under __BSD_VISIBLE, __USE_BSD + # or other similar definitions. So while the symbols "sysctl" and + # "sysctlbyname" might still be available in libc (which autoconf + # checks for), they might not be actually usable. + AC_TRY_LINK([ + #include + #include + #include + ], + [return sysctl(NULL,0,NULL,NULL,NULL,0);], + AC_DEFINE([HAVE_SYSCTL],[1],[Define to '1' if sysctl is present and usable])) + AC_TRY_LINK([ + #include + #include + #include + ], + [return sysctlbyname(NULL,NULL,NULL,NULL,0);], + AC_DEFINE([HAVE_SYSCTLBYNAME],[1],[Define to '1' if sysctlbyname is present and usable])) + + AC_CHECK_DECLS([getprogname], [], [], [AC_INCLUDES_DEFAULT]) + AC_CHECK_DECLS([getexecname], [], [], [AC_INCLUDES_DEFAULT]) + AC_CHECK_DECLS([GetModuleFileName], [], [], [#include ]) + # program_invocation_name and __progname may be available but not exported in headers + AC_MSG_CHECKING([for program_invocation_name]) + AC_TRY_LINK([ + #define _GNU_SOURCE + #include + #include + extern char *program_invocation_name; + ],[ + return printf("%s\n", program_invocation_name); + ], + [AC_DEFINE([HAVE_PROGRAM_INVOCATION_NAME], [1], [Define to '1' if program_invocation_name is present and usable]) + AC_MSG_RESULT([yes]) + ],[AC_MSG_RESULT([no])]) + AC_MSG_CHECKING([for __progname]) + AC_TRY_LINK([ + #include + extern char *__progname; + ],[ + return printf("%s\n", __progname); + ], + [AC_DEFINE([HAVE___PROGNAME], [1], [Define to '1' if __progname is present and usable]) + AC_MSG_RESULT([yes]) + ],[AC_MSG_RESULT([no])]) + + case ${target} in + *-*-mingw*|*-*-cygwin*) + hwloc_pid_t=HANDLE + hwloc_thread_t=HANDLE + ;; + *) + hwloc_pid_t=pid_t + AC_CHECK_TYPES([pthread_t], [hwloc_thread_t=pthread_t], [:], [[#include ]]) + ;; + esac + AC_DEFINE_UNQUOTED(hwloc_pid_t, $hwloc_pid_t, [Define this to the process ID type]) + if test "x$hwloc_thread_t" != "x" ; then + AC_DEFINE_UNQUOTED(hwloc_thread_t, $hwloc_thread_t, [Define this to the thread ID type]) + fi + + _HWLOC_CHECK_DECL([sched_setaffinity], [ + AC_DEFINE([HWLOC_HAVE_SCHED_SETAFFINITY], [1], [Define to 1 if glibc provides a prototype of sched_setaffinity()]) + AS_IF([test "$HWLOC_STRICT_ARGS_CFLAGS" = "FAIL"],[ + AC_MSG_WARN([Support for sched_setaffinity() requires a C compiler which]) + AC_MSG_WARN([considers incorrect argument counts to be a fatal error.]) + AC_MSG_ERROR([Cannot continue.]) + ]) + AC_MSG_CHECKING([for old prototype of sched_setaffinity]) + hwloc_save_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS $HWLOC_STRICT_ARGS_CFLAGS" + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + #define _GNU_SOURCE + #include + static unsigned long mask; + ]], [[ sched_setaffinity(0, (void*) &mask); ]])], + [AC_DEFINE([HWLOC_HAVE_OLD_SCHED_SETAFFINITY], [1], [Define to 1 if glibc provides the old prototype (without length) of sched_setaffinity()]) + AC_MSG_RESULT([yes])], + [AC_MSG_RESULT([no])]) + CFLAGS=$hwloc_save_CFLAGS + ], , [[ +#define _GNU_SOURCE +#include +]]) + + AC_MSG_CHECKING([for working CPU_SET]) + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[ + #include + cpu_set_t set; + ]], [[ CPU_ZERO(&set); CPU_SET(0, &set);]])], + [AC_DEFINE([HWLOC_HAVE_CPU_SET], [1], [Define to 1 if the CPU_SET macro works]) + AC_MSG_RESULT([yes])], + [AC_MSG_RESULT([no])]) + + AC_MSG_CHECKING([for working CPU_SET_S]) + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[ + #include + cpu_set_t *set; + ]], [[ + set = CPU_ALLOC(1024); + CPU_ZERO_S(CPU_ALLOC_SIZE(1024), set); + CPU_SET_S(CPU_ALLOC_SIZE(1024), 0, set); + CPU_FREE(set); + ]])], + [AC_DEFINE([HWLOC_HAVE_CPU_SET_S], [1], [Define to 1 if the CPU_SET_S macro works]) + AC_MSG_RESULT([yes])], + [AC_MSG_RESULT([no])]) + + AC_MSG_CHECKING([for working _syscall3]) + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[ + #include + #include + #define __NR_hwloc_test 123 + _syscall3(int, hwloc_test, int, param1, int, param2, int, param3); + ]], [[ hwloc_test(1, 2, 3); ]])], + [AC_DEFINE([HWLOC_HAVE__SYSCALL3], [1], [Define to 1 if the _syscall3 macro works]) + AC_MSG_RESULT([yes])], + [AC_MSG_RESULT([no])]) + + # Check for kerrighed, but don't abort if not found. It's illegal + # to pass in an empty 3rd argument, but we trust the output of + # pkg-config, so just give it a value that will always work: + # printf. + HWLOC_PKG_CHECK_MODULES([KERRIGHED], [kerrighed >= 2.0], [printf], [stdio.h], [], [:]) + + AC_PATH_PROGS([HWLOC_MS_LIB], [lib]) + AC_ARG_VAR([HWLOC_MS_LIB], [Path to Microsoft's Visual Studio `lib' tool]) + + AC_PATH_PROG([BASH], [bash]) + + AC_CHECK_FUNCS([ffs], [ + _HWLOC_CHECK_DECL([ffs],[ + AC_DEFINE([HWLOC_HAVE_DECL_FFS], [1], [Define to 1 if function `ffs' is declared by system headers]) + ]) + AC_DEFINE([HWLOC_HAVE_FFS], [1], [Define to 1 if you have the `ffs' function.]) + if ( $CC --version | grep gccfss ) >/dev/null 2>&1 ; then + dnl May be broken due to + dnl https://forums.oracle.com/forums/thread.jspa?threadID=1997328 + dnl TODO: a more selective test, since bug may be version dependent. + dnl We can't use AC_TRY_LINK because the failure does not appear until + dnl run/load time and there is currently no precedent for AC_TRY_RUN + dnl use in hwloc. --PHH + dnl For now, we're going with "all gccfss compilers are broken". + dnl Better to be safe and correct; it's not like this is + dnl performance-critical code, after all. + AC_DEFINE([HWLOC_HAVE_BROKEN_FFS], [1], + [Define to 1 if your `ffs' function is known to be broken.]) + fi + ]) + AC_CHECK_FUNCS([ffsl], [ + _HWLOC_CHECK_DECL([ffsl],[ + AC_DEFINE([HWLOC_HAVE_DECL_FFSL], [1], [Define to 1 if function `ffsl' is declared by system headers]) + ]) + AC_DEFINE([HWLOC_HAVE_FFSL], [1], [Define to 1 if you have the `ffsl' function.]) + ]) + + AC_CHECK_FUNCS([fls], [ + _HWLOC_CHECK_DECL([fls],[ + AC_DEFINE([HWLOC_HAVE_DECL_FLS], [1], [Define to 1 if function `fls' is declared by system headers]) + ]) + AC_DEFINE([HWLOC_HAVE_FLS], [1], [Define to 1 if you have the `fls' function.]) + ]) + AC_CHECK_FUNCS([flsl], [ + _HWLOC_CHECK_DECL([flsl],[ + AC_DEFINE([HWLOC_HAVE_DECL_FLSL], [1], [Define to 1 if function `flsl' is declared by system headers]) + ]) + AC_DEFINE([HWLOC_HAVE_FLSL], [1], [Define to 1 if you have the `flsl' function.]) + ]) + + AC_CHECK_FUNCS([clz], [ + _HWLOC_CHECK_DECL([clz],[ + AC_DEFINE([HWLOC_HAVE_DECL_CLZ], [1], [Define to 1 if function `clz' is declared by system headers]) + ]) + AC_DEFINE([HWLOC_HAVE_CLZ], [1], [Define to 1 if you have the `clz' function.]) + ]) + AC_CHECK_FUNCS([clzl], [ + _HWLOC_CHECK_DECL([clzl],[ + AC_DEFINE([HWLOC_HAVE_DECL_CLZL], [1], [Define to 1 if function `clzl' is declared by system headers]) + ]) + AC_DEFINE([HWLOC_HAVE_CLZL], [1], [Define to 1 if you have the `clzl' function.]) + ]) + + AC_CHECK_FUNCS([openat], [hwloc_have_openat=yes]) + + AC_CHECK_HEADERS([malloc.h]) + AC_CHECK_FUNCS([getpagesize memalign posix_memalign]) + + AC_CHECK_HEADERS([sys/utsname.h]) + AC_CHECK_FUNCS([uname]) + + AC_CHECK_HEADERS([pthread_np.h]) + AC_CHECK_DECLS([pthread_setaffinity_np],,[:],[[ + #include + #ifdef HAVE_PTHREAD_NP_H + # include + #endif + ]]) + AC_CHECK_DECLS([pthread_getaffinity_np],,[:],[[ + #include + #ifdef HAVE_PTHREAD_NP_H + # include + #endif + ]]) + AC_CHECK_FUNC([sched_setaffinity], [hwloc_have_sched_setaffinity=yes]) + AC_CHECK_HEADERS([sys/cpuset.h],,,[[#include ]]) + AC_CHECK_FUNCS([cpuset_setaffinity]) + AC_SEARCH_LIBS([pthread_getthrds_np], [pthread], + AC_DEFINE([HWLOC_HAVE_PTHREAD_GETTHRDS_NP], 1, `Define to 1 if you have pthread_getthrds_np') + ) + AC_CHECK_FUNCS([cpuset_setid]) + + # Linux libnuma support + hwloc_linux_libnuma_happy=no + if test "x$enable_libnuma" != "xno"; then + hwloc_linux_libnuma_happy=yes + AC_CHECK_HEADERS([numaif.h], [ + AC_CHECK_LIB([numa], [numa_available], [HWLOC_LINUX_LIBNUMA_LIBS="-lnuma"], [hwloc_linux_libnuma_happy=no]) + ], [hwloc_linux_libnuma_happy=no]) + fi + AC_SUBST(HWLOC_LINUX_LIBNUMA_LIBS) + # If we asked for Linux libnuma support but couldn't deliver, fail + HWLOC_LIBS="$HWLOC_LIBS $HWLOC_LINUX_LIBNUMA_LIBS" + AS_IF([test "$enable_libnuma" = "yes" -a "$hwloc_linux_libnuma_happy" = "no"], + [AC_MSG_WARN([Specified --enable-libnuma switch, but could not]) + AC_MSG_WARN([find appropriate support]) + AC_MSG_ERROR([Cannot continue])]) + if test "x$hwloc_linux_libnuma_happy" = "xyes"; then + tmp_save_LIBS="$LIBS" + LIBS="$LIBS $HWLOC_LINUX_LIBNUMA_LIBS" + + AC_CHECK_LIB([numa], [set_mempolicy], [ + enable_set_mempolicy=yes + AC_DEFINE([HWLOC_HAVE_SET_MEMPOLICY], [1], [Define to 1 if set_mempolicy is available.]) + ]) + AC_CHECK_LIB([numa], [mbind], [ + enable_mbind=yes + AC_DEFINE([HWLOC_HAVE_MBIND], [1], [Define to 1 if mbind is available.]) + ]) + AC_CHECK_LIB([numa], [migrate_pages], [ + enable_migrate_pages=yes + AC_DEFINE([HWLOC_HAVE_MIGRATE_PAGES], [1], [Define to 1 if migrate_pages is available.]) + ]) + + LIBS="$tmp_save_LIBS" + fi + + # Linux libudev support + if test "x$enable_libudev" != xno; then + AC_CHECK_HEADERS([libudev.h], [ + AC_CHECK_LIB([udev], [udev_device_new_from_subsystem_sysname], [HWLOC_LIBS="$HWLOC_LIBS -ludev"]) + ]) + fi + + # PCI support via libpciaccess. NOTE: we do not support + # libpci/pciutils because that library is GPL and is incompatible + # with our BSD license. + hwloc_pci_happy=no + if test "x$enable_pci" != xno; then + hwloc_pci_happy=yes + HWLOC_PKG_CHECK_MODULES([PCIACCESS], [pciaccess], [pci_slot_match_iterator_create], [pciaccess.h], [:], [hwloc_pci_happy=no]) + + # Just for giggles, if we didn't find a pciaccess pkg-config, + # just try looking for its header file and library. + AS_IF([test "$hwloc_pci_happy" != "yes"], + [AC_CHECK_HEADER([pciaccess.h], + [AC_CHECK_LIB([pciaccess], [pci_slot_match_iterator_create], + [hwloc_pci_happy=yes + HWLOC_PCIACCESS_LIBS="-lpciaccess"]) + ]) + ]) + + AS_IF([test "$hwloc_pci_happy" = "yes"], + [HWLOC_PCIACCESS_REQUIRES=pciaccess + hwloc_pci_lib=pciaccess + hwloc_components="$hwloc_components pci" + hwloc_pci_component_maybeplugin=1]) + fi + # If we asked for pci support but couldn't deliver, fail + AS_IF([test "$enable_pci" = "yes" -a "$hwloc_pci_happy" = "no"], + [AC_MSG_WARN([Specified --enable-pci switch, but could not]) + AC_MSG_WARN([find appropriate support]) + AC_MSG_ERROR([Cannot continue])]) + # don't add LIBS/CFLAGS/REQUIRES yet, depends on plugins + + # OpenCL support + hwloc_opencl_happy=no + if test "x$enable_opencl" != "xno"; then + hwloc_opencl_happy=yes + AC_CHECK_HEADERS([CL/cl_ext.h], [ + AC_CHECK_LIB([OpenCL], [clGetDeviceIDs], [HWLOC_OPENCL_LIBS="-lOpenCL"], [hwloc_opencl_happy=no]) + ], [hwloc_opencl_happy=no]) + fi + AC_SUBST(HWLOC_OPENCL_LIBS) + # Check if required extensions are available + if test "x$hwloc_opencl_happy" = "xyes"; then + tmp_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $HWLOC_OPENCL_CFLAGS" + tmp_save_LIBS="$LIBS" + LIBS="$LIBS $HWLOC_OPENCL_LIBS" + AC_CHECK_DECLS([CL_DEVICE_TOPOLOGY_AMD],[hwloc_opencl_amd_happy=yes],[:],[[#include ]]) + CFLAGS="$tmp_save_CFLAGS" + LIBS="$tmp_save_LIBS" + # We can't do anything without CL_DEVICE_TOPOLOGY_AMD so far, so disable OpenCL entirely if not found + test "x$hwloc_opencl_amd_happy" != "xyes" && hwloc_opencl_happy=no + fi + # If we asked for opencl support but couldn't deliver, fail + AS_IF([test "$enable_opencl" = "yes" -a "$hwloc_opencl_happy" = "no"], + [AC_MSG_WARN([Specified --enable-opencl switch, but could not]) + AC_MSG_WARN([find appropriate support]) + AC_MSG_ERROR([Cannot continue])]) + if test "x$hwloc_opencl_happy" = "xyes"; then + AC_DEFINE([HWLOC_HAVE_OPENCL], [1], [Define to 1 if you have the `OpenCL' library.]) + AC_SUBST([HWLOC_HAVE_OPENCL], [1]) + hwloc_components="$hwloc_components opencl" + hwloc_opencl_component_maybeplugin=1 + else + AC_SUBST([HWLOC_HAVE_OPENCL], [0]) + fi + # don't add LIBS/CFLAGS/REQUIRES yet, depends on plugins + + # CUDA support + hwloc_have_cuda=no + hwloc_have_cudart=no + if test "x$enable_cuda" != "xno"; then + AC_CHECK_HEADERS([cuda.h], [ + AC_MSG_CHECKING(if CUDA_VERSION >= 3020) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#include +#ifndef CUDA_VERSION +#error CUDA_VERSION undefined +#elif CUDA_VERSION < 3020 +#error CUDA_VERSION too old +#endif]], [[int i = 3;]])], + [AC_MSG_RESULT(yes) + AC_CHECK_LIB([cuda], [cuInit], + [AC_DEFINE([HAVE_CUDA], 1, [Define to 1 if we have -lcuda]) + hwloc_have_cuda=yes])], + [AC_MSG_RESULT(no)])]) + + AC_CHECK_HEADERS([cuda_runtime_api.h], [ + AC_MSG_CHECKING(if CUDART_VERSION >= 3020) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#include +#ifndef CUDART_VERSION +#error CUDART_VERSION undefined +#elif CUDART_VERSION < 3020 +#error CUDART_VERSION too old +#endif]], [[int i = 3;]])], + [AC_MSG_RESULT(yes) + AC_CHECK_LIB([cudart], [cudaGetDeviceProperties], [ + HWLOC_CUDA_LIBS="-lcudart" + AC_SUBST(HWLOC_CUDA_LIBS) + hwloc_have_cudart=yes + AC_DEFINE([HWLOC_HAVE_CUDART], [1], [Define to 1 if you have the `cudart' SDK.]) + ]) + ]) + ]) + + AS_IF([test "$enable_cuda" = "yes" -a "$hwloc_have_cudart" = "no"], + [AC_MSG_WARN([Specified --enable-cuda switch, but could not]) + AC_MSG_WARN([find appropriate support]) + AC_MSG_ERROR([Cannot continue])]) + + if test "x$hwloc_have_cudart" = "xyes"; then + hwloc_components="$hwloc_components cuda" + hwloc_cuda_component_maybeplugin=1 + fi + fi + # don't add LIBS/CFLAGS yet, depends on plugins + + # NVML support + hwloc_nvml_happy=no + if test "x$enable_nvml" != "xno"; then + hwloc_nvml_happy=yes + AC_CHECK_HEADERS([nvml.h], [ + AC_CHECK_LIB([nvidia-ml], [nvmlInit], [HWLOC_NVML_LIBS="-lnvidia-ml"], [hwloc_nvml_happy=no]) + ], [hwloc_nvml_happy=no]) + fi + if test "x$hwloc_nvml_happy" = "xyes"; then + tmp_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $HWLOC_NVML_CFLAGS" + tmp_save_LIBS="$LIBS" + LIBS="$LIBS $HWLOC_NVML_LIBS" + AC_CHECK_DECLS([nvmlDeviceGetMaxPcieLinkGeneration],,[:],[[#include ]]) + CFLAGS="$tmp_save_CFLAGS" + LIBS="$tmp_save_LIBS" + fi + AC_SUBST(HWLOC_NVML_LIBS) + # If we asked for nvml support but couldn't deliver, fail + AS_IF([test "$enable_nvml" = "yes" -a "$hwloc_nvml_happy" = "no"], + [AC_MSG_WARN([Specified --enable-nvml switch, but could not]) + AC_MSG_WARN([find appropriate support]) + AC_MSG_ERROR([Cannot continue])]) + if test "x$hwloc_nvml_happy" = "xyes"; then + AC_DEFINE([HWLOC_HAVE_NVML], [1], [Define to 1 if you have the `NVML' library.]) + AC_SUBST([HWLOC_HAVE_NVML], [1]) + hwloc_components="$hwloc_components nvml" + hwloc_nvml_component_maybeplugin=1 + else + AC_SUBST([HWLOC_HAVE_NVML], [0]) + fi + # don't add LIBS/CFLAGS/REQUIRES yet, depends on plugins + + # X11 support + AC_PATH_XTRA + + CPPFLAGS_save=$CPPFLAGS + LIBS_save=$LIBS + + CPPFLAGS="$CPPFLAGS $X_CFLAGS" + LIBS="$LIBS $X_PRE_LIBS $X_LIBS $X_EXTRA_LIBS" + AC_CHECK_HEADERS([X11/Xlib.h], + [AC_CHECK_LIB([X11], [XOpenDisplay], + [ + # the GL backend just needs XOpenDisplay + hwloc_enable_X11=yes + # lstopo needs more + AC_CHECK_HEADERS([X11/Xutil.h], + [AC_CHECK_HEADERS([X11/keysym.h], + [AC_DEFINE([HWLOC_HAVE_X11_KEYSYM], [1], [Define to 1 if X11 headers including Xutil.h and keysym.h are available.])]) + AC_SUBST([HWLOC_X11_LIBS], ["-lX11"]) + ], [], [#include ]) + ]) + ]) + CPPFLAGS=$CPPFLAGS_save + LIBS=$LIBS_save + + # GL Support + hwloc_gl_happy=no + if test "x$enable_gl" != "xno"; then + hwloc_gl_happy=yes + + AS_IF([test "$hwloc_enable_X11" != "yes"], + [AC_MSG_WARN([X11 not found; GL disabled]) + hwloc_gl_happy=no]) + + AC_CHECK_HEADERS([NVCtrl/NVCtrl.h], [ + AC_CHECK_LIB([XNVCtrl], [XNVCTRLQueryTargetAttribute], [:], [hwloc_gl_happy=no], [-lXext]) + ], [hwloc_gl_happy=no]) + + if test "x$hwloc_gl_happy" = "xyes"; then + AC_DEFINE([HWLOC_HAVE_GL], [1], [Define to 1 if you have the GL module components.]) + HWLOC_GL_LIBS="-lXNVCtrl -lXext -lX11" + AC_SUBST(HWLOC_GL_LIBS) + HWLOC_GL_REQUIRES="xext x11" + hwloc_have_gl=yes + hwloc_components="$hwloc_components gl" + hwloc_gl_component_maybeplugin=1 + else + AS_IF([test "$enable_gl" = "yes"], [ + AC_MSG_WARN([Specified --enable-gl switch, but could not]) + AC_MSG_WARN([find appropriate support]) + AC_MSG_ERROR([Cannot continue]) + ]) + fi + fi + # don't add LIBS/CFLAGS yet, depends on plugins + + # libxml2 support + hwloc_libxml2_happy= + if test "x$enable_libxml2" != "xno"; then + HWLOC_PKG_CHECK_MODULES([LIBXML2], [libxml-2.0], [xmlNewDoc], [libxml/parser.h], + [hwloc_libxml2_happy=yes], + [hwloc_libxml2_happy=no]) + fi + if test "x$hwloc_libxml2_happy" = "xyes"; then + HWLOC_LIBXML2_REQUIRES="libxml-2.0" + AC_DEFINE([HWLOC_HAVE_LIBXML2], [1], [Define to 1 if you have the `libxml2' library.]) + AC_SUBST([HWLOC_HAVE_LIBXML2], [1]) + + hwloc_components="$hwloc_components xml_libxml" + hwloc_xml_libxml_component_maybeplugin=1 + else + AC_SUBST([HWLOC_HAVE_LIBXML2], [0]) + AS_IF([test "$enable_libxml2" = "yes"], + [AC_MSG_WARN([--enable-libxml2 requested, but libxml2 was not found]) + AC_MSG_ERROR([Cannot continue])]) + fi + # don't add LIBS/CFLAGS/REQUIRES yet, depends on plugins + + # Try to compile the x86 cpuid inlines + if test "x$enable_cpuid" != "xno"; then + AC_MSG_CHECKING([for x86 cpuid]) + old_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS -I$HWLOC_top_srcdir/include" + # We need hwloc_uint64_t but we can't use hwloc/autogen/config.h before configure ends. + # So pass #include/#define manually here for now. + CPUID_CHECK_HEADERS= + CPUID_CHECK_DEFINE= + if test "x$hwloc_windows" = xyes; then + X86_CPUID_CHECK_HEADERS="#include " + X86_CPUID_CHECK_DEFINE="#define hwloc_uint64_t DWORDLONG" + else + X86_CPUID_CHECK_DEFINE="#define hwloc_uint64_t uint64_t" + if test "x$ac_cv_header_stdint_h" = xyes; then + X86_CPUID_CHECK_HEADERS="#include " + fi + fi + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ + #include + $X86_CPUID_CHECK_HEADERS + $X86_CPUID_CHECK_DEFINE + #define __hwloc_inline + #include + ]], [[ + if (hwloc_have_x86_cpuid()) { + unsigned eax = 0, ebx, ecx = 0, edx; + hwloc_x86_cpuid(&eax, &ebx, &ecx, &edx); + printf("highest x86 cpuid %x\n", eax); + return 0; + } + ]])], + [AC_MSG_RESULT([yes]) + AC_DEFINE(HWLOC_HAVE_X86_CPUID, 1, [Define to 1 if you have x86 cpuid]) + hwloc_have_x86_cpuid=yes], + [AC_MSG_RESULT([no])]) + if test "x$hwloc_have_x86_cpuid" = xyes; then + hwloc_components="$hwloc_components x86" + fi + CPPFLAGS="$old_CPPFLAGS" + fi + + # Components require pthread_mutex, see if it needs -lpthread + hwloc_pthread_mutex_happy=no + # Try without explicit -lpthread first + AC_CHECK_FUNC([pthread_mutex_lock], + [hwloc_pthread_mutex_happy=yes + HWLOC_LIBS_PRIVATE="$HWLOC_LIBS_PRIVATE -lpthread" + ], + [AC_MSG_CHECKING([for pthread_mutex_lock with -lpthread]) + # Try again with explicit -lpthread, but don't use AC_CHECK_FUNC to avoid the cache + tmp_save_LIBS=$LIBS + LIBS="$LIBS -lpthread" + AC_LINK_IFELSE([AC_LANG_CALL([], [pthread_mutex_lock])], + [hwloc_pthread_mutex_happy=yes + HWLOC_LIBS="$HWLOC_LIBS -lpthread" + ]) + AC_MSG_RESULT([$hwloc_pthread_mutex_happy]) + LIBS="$tmp_save_LIBS" + ]) + AS_IF([test "x$hwloc_pthread_mutex_happy" = "xyes"], + [AC_DEFINE([HWLOC_HAVE_PTHREAD_MUTEX], 1, [Define to 1 if pthread mutexes are available])]) + + AS_IF([test "x$hwloc_pthread_mutex_happy" != xyes -a "x$hwloc_windows" != xyes], + [AC_MSG_WARN([pthread_mutex_lock not available, required for thread-safe initialization on non-Windows platforms.]) + AC_MSG_WARN([Please report this to the hwloc-devel mailing list.]) + AC_MSG_ERROR([Cannot continue])]) + + # + # Now enable registration of listed components + # + + # Plugin support + AC_MSG_CHECKING([if plugin support is enabled]) + # Plugins (even core support) are totally disabled by default + AS_IF([test "x$enable_plugins" = "x"], [enable_plugins=no]) + AS_IF([test "x$enable_plugins" != "xno"], [hwloc_have_plugins=yes], [hwloc_have_plugins=no]) + AC_MSG_RESULT([$hwloc_have_plugins]) + AS_IF([test "x$hwloc_have_plugins" = "xyes"], + [AC_DEFINE([HWLOC_HAVE_PLUGINS], 1, [Define to 1 if the hwloc library should support dynamically-loaded plugins])]) + + # Some sanity checks about plugins + # libltdl doesn't work on AIX as of 2.4.2 + AS_IF([test "x$enable_plugins" = "xyes" -a "x$hwloc_aix" = "xyes"], + [AC_MSG_WARN([libltdl does not work on AIX, plugins support cannot be enabled.]) + AC_MSG_ERROR([Cannot continue])]) + # posix linkers don't work well with plugins and windows dll constraints + AS_IF([test "x$enable_plugins" = "xyes" -a "x$hwloc_windows" = "xyes"], + [AC_MSG_WARN([Plugins not supported on non-native Windows build, plugins support cannot be enabled.]) + AC_MSG_ERROR([Cannot continue])]) + + # If we want plugins, look for ltdl.h and libltdl + if test "x$hwloc_have_plugins" = xyes; then + AC_CHECK_HEADER([ltdl.h], [], + [AC_MSG_WARN([Plugin support requested, but could not find ltdl.h]) + AC_MSG_ERROR([Cannot continue])]) + AC_CHECK_LIB([ltdl], [lt_dlopenext], + [HWLOC_LIBS="$HWLOC_LIBS -lltdl"], + [AC_MSG_WARN([Plugin support requested, but could not find libltdl]) + AC_MSG_ERROR([Cannot continue])]) + # Add libltdl static-build dependencies to hwloc.pc + HWLOC_CHECK_LTDL_DEPS + fi + + AC_ARG_WITH([hwloc-plugins-path], + AC_HELP_STRING([--with-hwloc-plugins-path=dir:...], + [Colon-separated list of plugin directories. Default: "$prefix/lib/hwloc". Plugins will be installed in the first directory. They will be loaded from all of them, in order.]), + [HWLOC_PLUGINS_PATH="$with_hwloc_plugins_path"], + [HWLOC_PLUGINS_PATH="\$(libdir)/hwloc"]) + AC_SUBST(HWLOC_PLUGINS_PATH) + HWLOC_PLUGINS_DIR=`echo "$HWLOC_PLUGINS_PATH" | cut -d: -f1` + AC_SUBST(HWLOC_PLUGINS_DIR) + + # Static components output file + hwloc_static_components_dir=${HWLOC_top_builddir}/src + mkdir -p ${hwloc_static_components_dir} + hwloc_static_components_file=${hwloc_static_components_dir}/static-components.h + rm -f ${hwloc_static_components_file} + + # Make $enable_plugins easier to use (it contains either "yes" (all) or a list of ) + HWLOC_PREPARE_FILTER_COMPONENTS([$enable_plugins]) + # Now we have some hwloc__component_wantplugin=1 + + # See which core components want plugin and support it + HWLOC_FILTER_COMPONENTS + # Now we have some hwloc__component=plugin/static + # and hwloc_static/plugin_components + AC_MSG_CHECKING([components to build statically]) + AC_MSG_RESULT($hwloc_static_components) + HWLOC_LIST_STATIC_COMPONENTS([$hwloc_static_components_file], [$hwloc_static_components]) + AC_MSG_CHECKING([components to build as plugins]) + AC_MSG_RESULT([$hwloc_plugin_components]) + + AS_IF([test "$hwloc_pci_component" = "static"], + [HWLOC_LIBS="$HWLOC_LIBS $HWLOC_PCIACCESS_LIBS" + HWLOC_CFLAGS="$HWLOC_CFLAGS $HWLOC_PCIACCESS_CFLAGS" + HWLOC_REQUIRES="$HWLOC_PCIACCESS_REQUIRES $HWLOC_REQUIRES"]) + AS_IF([test "$hwloc_opencl_component" = "static"], + [HWLOC_LIBS="$HWLOC_LIBS $HWLOC_OPENCL_LIBS" + HWLOC_CFLAGS="$HWLOC_CFLAGS $HWLOC_OPENCL_CFLAGS" + HWLOC_REQUIRES="$HWLOC_OPENCL_REQUIRES $HWLOC_REQUIRES"]) + AS_IF([test "$hwloc_cuda_component" = "static"], + [HWLOC_LIBS="$HWLOC_LIBS $HWLOC_CUDA_LIBS" + HWLOC_CFLAGS="$HWLOC_CFLAGS $HWLOC_CUDA_CFLAGS" + HWLOC_REQUIRES="$HWLOC_CUDA_REQUIRES $HWLOC_REQUIRES"]) + AS_IF([test "$hwloc_nvml_component" = "static"], + [HWLOC_LIBS="$HWLOC_LIBS $HWLOC_NVML_LIBS" + HWLOC_CFLAGS="$HWLOC_CFLAGS $HWLOC_NVML_CFLAGS" + HWLOC_REQUIRES="$HWLOC_NVML_REQUIRES $HWLOC_REQUIRES"]) + AS_IF([test "$hwloc_gl_component" = "static"], + [HWLOC_LIBS="$HWLOC_LIBS $HWLOC_GL_LIBS" + HWLOC_CFLAGS="$HWLOC_CFLAGS $HWLOC_GL_CFLAGS" + HWLOC_REQUIRES="$HWLOC_GL_REQUIRES $HWLOC_REQUIRES"]) + AS_IF([test "$hwloc_xml_libxml_component" = "static"], + [HWLOC_LIBS="$HWLOC_LIBS $HWLOC_LIBXML2_LIBS" + HWLOC_CFLAGS="$HWLOC_CFLAGS $HWLOC_LIBXML2_CFLAGS" + HWLOC_REQUIRES="$HWLOC_LIBXML2_REQUIRES $HWLOC_REQUIRES"]) + + # + # Setup HWLOC's C, CPP, and LD flags, and LIBS + # + AC_SUBST(HWLOC_REQUIRES) + AC_SUBST(HWLOC_CFLAGS) + HWLOC_CPPFLAGS='-I$(HWLOC_top_builddir)/include -I$(HWLOC_top_srcdir)/include' + AC_SUBST(HWLOC_CPPFLAGS) + AC_SUBST(HWLOC_LDFLAGS) + AC_SUBST(HWLOC_LIBS) + AC_SUBST(HWLOC_LIBS_PRIVATE) + + # Set these values explicitly for embedded builds. Exporting + # these values through *_EMBEDDED_* values gives us the freedom to + # do something different someday if we ever need to. There's no + # need to fill these values in unless we're in embedded mode. + # Indeed, if we're building in embedded mode, we want HWLOC_LIBS + # to be empty so that nothing is linked into libhwloc_embedded.la + # itself -- only the upper-layer will link in anything required. + + AS_IF([test "$hwloc_mode" = "embedded"], + [HWLOC_EMBEDDED_CFLAGS=$HWLOC_CFLAGS + HWLOC_EMBEDDED_CPPFLAGS=$HWLOC_CPPFLAGS + HWLOC_EMBEDDED_LDADD='$(HWLOC_top_builddir)/src/libhwloc_embedded.la' + HWLOC_EMBEDDED_LIBS=$HWLOC_LIBS + HWLOC_LIBS=]) + AC_SUBST(HWLOC_EMBEDDED_CFLAGS) + AC_SUBST(HWLOC_EMBEDDED_CPPFLAGS) + AC_SUBST(HWLOC_EMBEDDED_LDADD) + AC_SUBST(HWLOC_EMBEDDED_LIBS) + + # Always generate these files + AC_CONFIG_FILES( + hwloc_config_prefix[Makefile] + hwloc_config_prefix[include/Makefile] + hwloc_config_prefix[src/Makefile ] + ) + + # Cleanup + AC_LANG_POP + + # Success + $2 +])dnl + +#----------------------------------------------------------------------- + +# Specify the symbol prefix +AC_DEFUN([HWLOC_SET_SYMBOL_PREFIX],[ + hwloc_symbol_prefix_value=$1 +])dnl + +#----------------------------------------------------------------------- + +# This must be a standalone routine so that it can be called both by +# HWLOC_INIT and an external caller (if HWLOC_INIT is not invoked). +AC_DEFUN([HWLOC_DO_AM_CONDITIONALS],[ + AS_IF([test "$hwloc_did_am_conditionals" != "yes"],[ + AM_CONDITIONAL([HWLOC_BUILD_STANDALONE], [test "$hwloc_mode" = "standalone"]) + + AM_CONDITIONAL([HWLOC_HAVE_GCC], [test "x$GCC" = "xyes"]) + AM_CONDITIONAL([HWLOC_HAVE_MS_LIB], [test "x$HWLOC_MS_LIB" != "x"]) + AM_CONDITIONAL([HWLOC_HAVE_OPENAT], [test "x$hwloc_have_openat" = "xyes"]) + AM_CONDITIONAL([HWLOC_HAVE_LINUX_LIBNUMA], + [test "x$hwloc_have_linux_libnuma" = "xyes"]) + AM_CONDITIONAL([HWLOC_HAVE_SCHED_SETAFFINITY], + [test "x$hwloc_have_sched_setaffinity" = "xyes"]) + AM_CONDITIONAL([HWLOC_HAVE_PTHREAD], + [test "x$hwloc_have_pthread" = "xyes"]) + AM_CONDITIONAL([HWLOC_HAVE_LIBIBVERBS], + [test "x$hwloc_have_libibverbs" = "xyes"]) + AM_CONDITIONAL([HWLOC_HAVE_CUDA], + [test "x$hwloc_have_cuda" = "xyes"]) + AM_CONDITIONAL([HWLOC_HAVE_GL], + [test "x$hwloc_have_gl" = "xyes"]) + AM_CONDITIONAL([HWLOC_HAVE_MYRIEXPRESS], + [test "x$hwloc_have_myriexpress" = "xyes"]) + AM_CONDITIONAL([HWLOC_HAVE_CUDART], + [test "x$hwloc_have_cudart" = "xyes"]) + AM_CONDITIONAL([HWLOC_HAVE_LIBXML2], [test "$hwloc_libxml2_happy" = "yes"]) + AM_CONDITIONAL([HWLOC_HAVE_CAIRO], [test "$hwloc_cairo_happy" = "yes"]) + AM_CONDITIONAL([HWLOC_HAVE_PCI], [test "$hwloc_pci_happy" = "yes"]) + AM_CONDITIONAL([HWLOC_HAVE_OPENCL], [test "$hwloc_opencl_happy" = "yes"]) + AM_CONDITIONAL([HWLOC_HAVE_NVML], [test "$hwloc_nvml_happy" = "yes"]) + AM_CONDITIONAL([HWLOC_HAVE_SET_MEMPOLICY], [test "x$enable_set_mempolicy" != "xno"]) + AM_CONDITIONAL([HWLOC_HAVE_MBIND], [test "x$enable_mbind" != "xno"]) + AM_CONDITIONAL([HWLOC_HAVE_BUNZIPP], [test "x$BUNZIPP" != "xfalse"]) + + AM_CONDITIONAL([HWLOC_BUILD_DOXYGEN], + [test "x$hwloc_generate_doxs" = "xyes"]) + AM_CONDITIONAL([HWLOC_BUILD_README], + [test "x$hwloc_generate_readme" = "xyes" -a \( "x$hwloc_install_doxs" = "xyes" -o "x$hwloc_generate_doxs" = "xyes" \) ]) + AM_CONDITIONAL([HWLOC_INSTALL_DOXYGEN], + [test "x$hwloc_install_doxs" = "xyes"]) + + AM_CONDITIONAL([HWLOC_HAVE_LINUX], [test "x$hwloc_linux" = "xyes"]) + AM_CONDITIONAL([HWLOC_HAVE_BGQ], [test "x$hwloc_bgq" = "xyes"]) + AM_CONDITIONAL([HWLOC_HAVE_IRIX], [test "x$hwloc_irix" = "xyes"]) + AM_CONDITIONAL([HWLOC_HAVE_DARWIN], [test "x$hwloc_darwin" = "xyes"]) + AM_CONDITIONAL([HWLOC_HAVE_FREEBSD], [test "x$hwloc_freebsd" = "xyes"]) + AM_CONDITIONAL([HWLOC_HAVE_NETBSD], [test "x$hwloc_netbsd" = "xyes"]) + AM_CONDITIONAL([HWLOC_HAVE_SOLARIS], [test "x$hwloc_solaris" = "xyes"]) + AM_CONDITIONAL([HWLOC_HAVE_AIX], [test "x$hwloc_aix" = "xyes"]) + AM_CONDITIONAL([HWLOC_HAVE_OSF], [test "x$hwloc_osf" = "xyes"]) + AM_CONDITIONAL([HWLOC_HAVE_HPUX], [test "x$hwloc_hpux" = "xyes"]) + AM_CONDITIONAL([HWLOC_HAVE_WINDOWS], [test "x$hwloc_windows" = "xyes"]) + AM_CONDITIONAL([HWLOC_HAVE_MINGW32], [test "x$target_os" = "xmingw32"]) + + AM_CONDITIONAL([HWLOC_HAVE_X86_32], [test "x$hwloc_x86_32" = "xyes"]) + AM_CONDITIONAL([HWLOC_HAVE_X86_64], [test "x$hwloc_x86_64" = "xyes"]) + AM_CONDITIONAL([HWLOC_HAVE_X86_CPUID], [test "x$hwloc_have_x86_cpuid" = "xyes"]) + + AM_CONDITIONAL([HWLOC_HAVE_PLUGINS], [test "x$hwloc_have_plugins" = "xyes"]) + AM_CONDITIONAL([HWLOC_PCI_BUILD_STATIC], [test "x$hwloc_pci_component" = "xstatic"]) + AM_CONDITIONAL([HWLOC_OPENCL_BUILD_STATIC], [test "x$hwloc_opencl_component" = "xstatic"]) + AM_CONDITIONAL([HWLOC_CUDA_BUILD_STATIC], [test "x$hwloc_cuda_component" = "xstatic"]) + AM_CONDITIONAL([HWLOC_NVML_BUILD_STATIC], [test "x$hwloc_nvml_component" = "xstatic"]) + AM_CONDITIONAL([HWLOC_GL_BUILD_STATIC], [test "x$hwloc_gl_component" = "xstatic"]) + AM_CONDITIONAL([HWLOC_XML_LIBXML_BUILD_STATIC], [test "x$hwloc_xml_libxml_component" = "xstatic"]) + + AM_CONDITIONAL([HWLOC_HAVE_CXX], [test "x$hwloc_have_cxx" = "xyes"]) + ]) + hwloc_did_am_conditionals=yes +])dnl + +#----------------------------------------------------------------------- + +AC_DEFUN([_HWLOC_CHECK_DIFF_U], [ + AC_MSG_CHECKING([whether diff accepts -u]) + if diff -u /dev/null /dev/null 2> /dev/null + then + HWLOC_DIFF_U="-u" + else + HWLOC_DIFF_U="" + fi + AC_SUBST([HWLOC_DIFF_U]) + AC_MSG_RESULT([$HWLOC_DIFF_U]) +]) + +AC_DEFUN([_HWLOC_CHECK_DIFF_W], [ + AC_MSG_CHECKING([whether diff accepts -w]) + if diff -w /dev/null /dev/null 2> /dev/null + then + HWLOC_DIFF_W="-w" + else + HWLOC_DIFF_W="" + fi + AC_SUBST([HWLOC_DIFF_W]) + AC_MSG_RESULT([$HWLOC_DIFF_W]) +]) + +#----------------------------------------------------------------------- + +dnl HWLOC_CHECK_DECL +dnl +dnl Check declaration of given function by trying to call it with an insane +dnl number of arguments (10). Success means the compiler couldn't really check. +AC_DEFUN([_HWLOC_CHECK_DECL], [ + AC_MSG_CHECKING([whether function $1 is declared]) + AC_REQUIRE([AC_PROG_CC]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM( + [AC_INCLUDES_DEFAULT([$4]) + void * $1;], + )], + [AC_MSG_RESULT([no]) + $3], + [AC_MSG_RESULT([yes]) + $2] + ) +]) + +#----------------------------------------------------------------------- + +dnl HWLOC_CHECK_DECLS +dnl +dnl Same as HWLOCK_CHECK_DECL, but defines HAVE_DECL_foo to 1 or 0 depending on +dnl the result. +AC_DEFUN([_HWLOC_CHECK_DECLS], [ + HWLOC_CHECK_DECL([$1], [ac_have_decl=1], [ac_have_decl=0], [$4]) + AC_DEFINE_UNQUOTED(AS_TR_CPP([HAVE_DECL_$1]), [$ac_have_decl], + [Define to 1 if you have the declaration of `$1', and to 0 if you don't]) +]) + +#----------------------------------------------------------------------- + +dnl HWLOC_CHECK_LTDL_DEPS +dnl +dnl Add ltdl dependencies to HWLOC_LIBS_PRIVATE +AC_DEFUN([HWLOC_CHECK_LTDL_DEPS], [ + # save variables that we'll modify below + save_lt_cv_dlopen="$lt_cv_dlopen" + save_lt_cv_dlopen_libs="$lt_cv_dlopen_libs" + save_lt_cv_dlopen_self="$lt_cv_dlopen_self" + ########################################################### + # code stolen from LT_SYS_DLOPEN_SELF in libtool.m4 + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32* | cegcc*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ]) + ;; + + *) + AC_CHECK_FUNC([shl_load], + [lt_cv_dlopen="shl_load"], + [AC_CHECK_LIB([dld], [shl_load], + [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"], + [AC_CHECK_FUNC([dlopen], + [lt_cv_dlopen="dlopen"], + [AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], + [AC_CHECK_LIB([svld], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], + [AC_CHECK_LIB([dld], [dld_link], + [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"]) + ]) + ]) + ]) + ]) + ]) + ;; + esac + # end of code stolen from LT_SYS_DLOPEN_SELF in libtool.m4 + ########################################################### + + HWLOC_LIBS_PRIVATE="$HWLOC_LIBS_PRIVATE $lt_cv_dlopen_libs" + + # restore modified variable in case the actual libtool code uses them + lt_cv_dlopen="$save_lt_cv_dlopen" + lt_cv_dlopen_libs="$save_lt_cv_dlopen_libs" + lt_cv_dlopen_self="$save_lt_cv_dlopen_self" +]) diff --git a/opal/mca/hwloc/hwloc1110/hwloc/config/hwloc_check_attributes.m4 b/opal/mca/hwloc/hwloc1110/hwloc/config/hwloc_check_attributes.m4 new file mode 100644 index 0000000000..765407168b --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/config/hwloc_check_attributes.m4 @@ -0,0 +1,533 @@ +# This macro set originally copied from Open MPI: +# Copyright © 2004-2007 The Trustees of Indiana University and Indiana +# University Research and Technology +# Corporation. All rights reserved. +# Copyright © 2004-2005 The University of Tennessee and The University +# of Tennessee Research Foundation. All rights +# reserved. +# Copyright © 2004-2007 High Performance Computing Center Stuttgart, +# University of Stuttgart. All rights reserved. +# Copyright © 2004-2005 The Regents of the University of California. +# All rights reserved. +# and renamed for hwloc: +# Copyright © 2009 Inria. All rights reserved. +# Copyright © 2009 Université Bordeaux +# Copyright © 2010 Cisco Systems, Inc. All rights reserved. +# See COPYING in top-level directory. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer listed +# in this license in the documentation and/or other materials +# provided with the distribution. +# +# - Neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# The copyright holders provide no reassurances that the source code +# provided does not infringe any patent, copyright, or any other +# intellectual property rights of third parties. The copyright holders +# disclaim any liability to any recipient for claims brought against +# recipient by any third party for infringement of that parties +# intellectual property rights. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +# +# Search the generated warnings for +# keywords regarding skipping or ignoring certain attributes +# Intel: ignore +# Sun C++: skip +# +AC_DEFUN([_HWLOC_ATTRIBUTE_FAIL_SEARCH],[ + # Be safe for systems that have ancient Autoconf's (e.g., RHEL5) + m4_ifdef([AC_PROG_GREP], + [AC_REQUIRE([AC_PROG_GREP])], + [GREP=grep]) + + if test -s conftest.err ; then + for i in ignore skip ; do + $GREP -iq $i conftest.err + if test "$?" = "0" ; then + hwloc_cv___attribute__[$1]=0 + break; + fi + done + fi +]) + +# +# HWLOC: Remove C++ compiler check. It can result in a circular +# dependency in embedded situations. +# +# Check for one specific attribute by compiling with C +# and possibly using a cross-check. +# +# If the cross-check is defined, a static function "usage" should be +# defined, which is to be called from main (to circumvent warnings +# regarding unused function in main file) +# static int usage (int * argument); +# +# The last argument is for specific CFLAGS, that need to be set +# for the compiler to generate a warning on the cross-check. +# This may need adaption for future compilers / CFLAG-settings. +# +AC_DEFUN([_HWLOC_CHECK_SPECIFIC_ATTRIBUTE], [ + AC_MSG_CHECKING([for __attribute__([$1])]) + AC_CACHE_VAL(hwloc_cv___attribute__[$1], [ + # + # Try to compile using the C compiler + # + AC_TRY_COMPILE([$2],[], + [ + # + # In case we did succeed: Fine, but was this due to the + # attribute being ignored/skipped? Grep for IgNoRe/skip in conftest.err + # and if found, reset the hwloc_cv__attribute__var=0 + # + hwloc_cv___attribute__[$1]=1 + _HWLOC_ATTRIBUTE_FAIL_SEARCH([$1]) + ], + [hwloc_cv___attribute__[$1]=0]) + + # + # If the attribute is supported by both compilers, + # try to recompile a *cross-check*, IFF defined. + # + if test '(' "$hwloc_cv___attribute__[$1]" = "1" -a "[$3]" != "" ')' ; then + ac_c_werror_flag_safe=$ac_c_werror_flag + ac_c_werror_flag="yes" + CFLAGS_safe=$CFLAGS + CFLAGS="$CFLAGS [$4]" + + AC_TRY_COMPILE([$3], + [ + int i=4711; + i=usage(&i); + ], + [hwloc_cv___attribute__[$1]=0], + [ + # + # In case we did NOT succeed: Fine, but was this due to the + # attribute being ignored? Grep for IgNoRe in conftest.err + # and if found, reset the hwloc_cv__attribute__var=0 + # + hwloc_cv___attribute__[$1]=1 + _HWLOC_ATTRIBUTE_FAIL_SEARCH([$1]) + ]) + + ac_c_werror_flag=$ac_c_werror_flag_safe + CFLAGS=$CFLAGS_safe + fi + ]) + + if test "$hwloc_cv___attribute__[$1]" = "1" ; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi +]) + + +# +# Test the availability of __attribute__ and with the help +# of _HWLOC_CHECK_SPECIFIC_ATTRIBUTE for the support of +# particular attributes. Compilers, that do not support an +# attribute most often fail with a warning (when the warning +# level is set). +# The compilers output is parsed in _HWLOC_ATTRIBUTE_FAIL_SEARCH +# +# To add a new attributes __NAME__ add the +# hwloc_cv___attribute__NAME +# add a new check with _HWLOC_CHECK_SPECIFIC_ATTRIBUTE (possibly with a cross-check) +# _HWLOC_CHECK_SPECIFIC_ATTRIBUTE([name], [int foo (int arg) __attribute__ ((__name__));], [], []) +# and define the corresponding +# AC_DEFINE_UNQUOTED(_HWLOC_HAVE_ATTRIBUTE_NAME, [$hwloc_cv___attribute__NAME], +# [Whether your compiler has __attribute__ NAME or not]) +# and decide on a correct macro (in opal/include/opal_config_bottom.h): +# # define __opal_attribute_NAME(x) __attribute__(__NAME__) +# +# Please use the "__"-notation of the attribute in order not to +# clash with predefined names or macros (e.g. const, which some compilers +# do not like..) +# + + +AC_DEFUN([_HWLOC_CHECK_ATTRIBUTES], [ + AC_MSG_CHECKING(for __attribute__) + + AC_CACHE_VAL(hwloc_cv___attribute__, [ + AC_TRY_COMPILE( + [#include + /* Check for the longest available __attribute__ (since gcc-2.3) */ + struct foo { + char a; + int x[2] __attribute__ ((__packed__)); + }; + ], + [], + [hwloc_cv___attribute__=1], + [hwloc_cv___attribute__=0], + ) + + if test "$hwloc_cv___attribute__" = "1" ; then + AC_TRY_COMPILE( + [#include + /* Check for the longest available __attribute__ (since gcc-2.3) */ + struct foo { + char a; + int x[2] __attribute__ ((__packed__)); + }; + ], + [], + [hwloc_cv___attribute__=1], + [hwloc_cv___attribute__=0], + ) + fi + ]) + AC_DEFINE_UNQUOTED(HWLOC_HAVE_ATTRIBUTE, [$hwloc_cv___attribute__], + [Whether your compiler has __attribute__ or not]) + +# +# Now that we know the compiler support __attribute__ let's check which kind of +# attributed are supported. +# + if test "$hwloc_cv___attribute__" = "0" ; then + AC_MSG_RESULT([no]) + hwloc_cv___attribute__aligned=0 + hwloc_cv___attribute__always_inline=0 + hwloc_cv___attribute__cold=0 + hwloc_cv___attribute__const=0 + hwloc_cv___attribute__deprecated=0 + hwloc_cv___attribute__format=0 + hwloc_cv___attribute__hot=0 + hwloc_cv___attribute__malloc=0 + hwloc_cv___attribute__may_alias=0 + hwloc_cv___attribute__no_instrument_function=0 + hwloc_cv___attribute__nonnull=0 + hwloc_cv___attribute__noreturn=0 + hwloc_cv___attribute__packed=0 + hwloc_cv___attribute__pure=0 + hwloc_cv___attribute__sentinel=0 + hwloc_cv___attribute__unused=0 + hwloc_cv___attribute__warn_unused_result=0 + hwloc_cv___attribute__weak_alias=0 + else + AC_MSG_RESULT([yes]) + + _HWLOC_CHECK_SPECIFIC_ATTRIBUTE([aligned], + [struct foo { char text[4]; } __attribute__ ((__aligned__(8)));], + [], + []) + + # + # Ignored by PGI-6.2.5; -- recognized by output-parser + # + _HWLOC_CHECK_SPECIFIC_ATTRIBUTE([always_inline], + [int foo (int arg) __attribute__ ((__always_inline__));], + [], + []) + + _HWLOC_CHECK_SPECIFIC_ATTRIBUTE([cold], + [ + int foo(int arg1, int arg2) __attribute__ ((__cold__)); + int foo(int arg1, int arg2) { return arg1 * arg2 + arg1; } + ], + [], + []) + + _HWLOC_CHECK_SPECIFIC_ATTRIBUTE([const], + [ + int foo(int arg1, int arg2) __attribute__ ((__const__)); + int foo(int arg1, int arg2) { return arg1 * arg2 + arg1; } + ], + [], + []) + + + _HWLOC_CHECK_SPECIFIC_ATTRIBUTE([deprecated], + [ + int foo(int arg1, int arg2) __attribute__ ((__deprecated__)); + int foo(int arg1, int arg2) { return arg1 * arg2 + arg1; } + ], + [], + []) + + + HWLOC_ATTRIBUTE_CFLAGS= + case "$hwloc_c_vendor" in + gnu) + HWLOC_ATTRIBUTE_CFLAGS="-Wall" + ;; + intel) + # we want specifically the warning on format string conversion + HWLOC_ATTRIBUTE_CFLAGS="-we181" + ;; + esac + _HWLOC_CHECK_SPECIFIC_ATTRIBUTE([format], + [ + int this_printf (void *my_object, const char *my_format, ...) __attribute__ ((__format__ (__printf__, 2, 3))); + ], + [ + static int usage (int * argument); + extern int this_printf (int arg1, const char *my_format, ...) __attribute__ ((__format__ (__printf__, 2, 3))); + + static int usage (int * argument) { + return this_printf (*argument, "%d", argument); /* This should produce a format warning */ + } + /* The autoconf-generated main-function is int main(), which produces a warning by itself */ + int main(void); + ], + [$HWLOC_ATTRIBUTE_CFLAGS]) + + _HWLOC_CHECK_SPECIFIC_ATTRIBUTE([hot], + [ + int foo(int arg1, int arg2) __attribute__ ((__hot__)); + int foo(int arg1, int arg2) { return arg1 * arg2 + arg1; } + ], + [], + []) + + _HWLOC_CHECK_SPECIFIC_ATTRIBUTE([malloc], + [ +#ifdef HAVE_STDLIB_H +# include +#endif + int * foo(int arg1) __attribute__ ((__malloc__)); + int * foo(int arg1) { return (int*) malloc(arg1); } + ], + [], + []) + + + # + # Attribute may_alias: No suitable cross-check available, that works for non-supporting compilers + # Ignored by intel-9.1.045 -- turn off with -wd1292 + # Ignored by PGI-6.2.5; ignore not detected due to missing cross-check + # + _HWLOC_CHECK_SPECIFIC_ATTRIBUTE([may_alias], + [int * p_value __attribute__ ((__may_alias__));], + [], + []) + + + _HWLOC_CHECK_SPECIFIC_ATTRIBUTE([no_instrument_function], + [int * foo(int arg1) __attribute__ ((__no_instrument_function__));], + [], + []) + + + # + # Attribute nonnull: + # Ignored by intel-compiler 9.1.045 -- recognized by cross-check + # Ignored by PGI-6.2.5 (pgCC) -- recognized by cross-check + # + HWLOC_ATTRIBUTE_CFLAGS= + case "$hwloc_c_vendor" in + gnu) + HWLOC_ATTRIBUTE_CFLAGS="-Wall" + ;; + intel) + # we do not want to get ignored attributes warnings, but rather real warnings + HWLOC_ATTRIBUTE_CFLAGS="-wd1292" + ;; + esac + _HWLOC_CHECK_SPECIFIC_ATTRIBUTE([nonnull], + [ + int square(int *arg) __attribute__ ((__nonnull__)); + int square(int *arg) { return *arg; } + ], + [ + static int usage(int * argument); + int square(int * argument) __attribute__ ((__nonnull__)); + int square(int * argument) { return (*argument) * (*argument); } + + static int usage(int * argument) { + return square( ((void*)0) ); /* This should produce an argument must be nonnull warning */ + } + /* The autoconf-generated main-function is int main(), which produces a warning by itself */ + int main(void); + ], + [$HWLOC_ATTRIBUTE_CFLAGS]) + + + _HWLOC_CHECK_SPECIFIC_ATTRIBUTE([noreturn], + [ +#ifdef HAVE_UNISTD_H +# include +#endif +#ifdef HAVE_STDLIB_H +# include +#endif + void fatal(int arg1) __attribute__ ((__noreturn__)); + void fatal(int arg1) { exit(arg1); } + ], + [], + []) + + _HWLOC_CHECK_SPECIFIC_ATTRIBUTE([packed], + [ + struct foo { + char a; + int x[2] __attribute__ ((__packed__)); + }; + ], + [], + []) + + _HWLOC_CHECK_SPECIFIC_ATTRIBUTE([pure], + [ + int square(int arg) __attribute__ ((__pure__)); + int square(int arg) { return arg * arg; } + ], + [], + []) + + # + # Attribute sentinel: + # Ignored by the intel-9.1.045 -- recognized by cross-check + # intel-10.0beta works fine + # Ignored by PGI-6.2.5 (pgCC) -- recognized by output-parser and cross-check + # Ignored by pathcc-2.2.1 -- recognized by cross-check (through grep ignore) + # + HWLOC_ATTRIBUTE_CFLAGS= + case "$hwloc_c_vendor" in + gnu) + HWLOC_ATTRIBUTE_CFLAGS="-Wall" + ;; + intel) + # we do not want to get ignored attributes warnings + HWLOC_ATTRIBUTE_CFLAGS="-wd1292" + ;; + esac + _HWLOC_CHECK_SPECIFIC_ATTRIBUTE([sentinel], + [ + int my_execlp(const char * file, const char *arg, ...) __attribute__ ((__sentinel__)); + ], + [ + static int usage(int * argument); + int my_execlp(const char * file, const char *arg, ...) __attribute__ ((__sentinel__)); + + static int usage(int * argument) { + void * last_arg_should_be_null = argument; + return my_execlp ("lala", "/home/there", last_arg_should_be_null); /* This should produce a warning */ + } + /* The autoconf-generated main-function is int main(), which produces a warning by itself */ + int main(void); + ], + [$HWLOC_ATTRIBUTE_CFLAGS]) + + _HWLOC_CHECK_SPECIFIC_ATTRIBUTE([unused], + [ + int square(int arg1 __attribute__ ((__unused__)), int arg2); + int square(int arg1, int arg2) { return arg2; } + ], + [], + []) + + + # + # Attribute warn_unused_result: + # Ignored by the intel-compiler 9.1.045 -- recognized by cross-check + # Ignored by pathcc-2.2.1 -- recognized by cross-check (through grep ignore) + # + HWLOC_ATTRIBUTE_CFLAGS= + case "$hwloc_c_vendor" in + gnu) + HWLOC_ATTRIBUTE_CFLAGS="-Wall" + ;; + intel) + # we do not want to get ignored attributes warnings + HWLOC_ATTRIBUTE_CFLAGS="-wd1292" + ;; + esac + _HWLOC_CHECK_SPECIFIC_ATTRIBUTE([warn_unused_result], + [ + int foo(int arg) __attribute__ ((__warn_unused_result__)); + int foo(int arg) { return arg + 3; } + ], + [ + static int usage(int * argument); + int foo(int arg) __attribute__ ((__warn_unused_result__)); + + int foo(int arg) { return arg + 3; } + static int usage(int * argument) { + foo (*argument); /* Should produce an unused result warning */ + return 0; + } + + /* The autoconf-generated main-function is int main(), which produces a warning by itself */ + int main(void); + ], + [$HWLOC_ATTRIBUTE_CFLAGS]) + + + _HWLOC_CHECK_SPECIFIC_ATTRIBUTE([weak_alias], + [ + int foo(int arg); + int foo(int arg) { return arg + 3; } + int foo2(int arg) __attribute__ ((__weak__, __alias__("foo"))); + ], + [], + []) + + fi + + # Now that all the values are set, define them + + AC_DEFINE_UNQUOTED(HWLOC_HAVE_ATTRIBUTE_ALIGNED, [$hwloc_cv___attribute__aligned], + [Whether your compiler has __attribute__ aligned or not]) + AC_DEFINE_UNQUOTED(HWLOC_HAVE_ATTRIBUTE_ALWAYS_INLINE, [$hwloc_cv___attribute__always_inline], + [Whether your compiler has __attribute__ always_inline or not]) + AC_DEFINE_UNQUOTED(HWLOC_HAVE_ATTRIBUTE_COLD, [$hwloc_cv___attribute__cold], + [Whether your compiler has __attribute__ cold or not]) + AC_DEFINE_UNQUOTED(HWLOC_HAVE_ATTRIBUTE_CONST, [$hwloc_cv___attribute__const], + [Whether your compiler has __attribute__ const or not]) + AC_DEFINE_UNQUOTED(HWLOC_HAVE_ATTRIBUTE_DEPRECATED, [$hwloc_cv___attribute__deprecated], + [Whether your compiler has __attribute__ deprecated or not]) + AC_DEFINE_UNQUOTED(HWLOC_HAVE_ATTRIBUTE_FORMAT, [$hwloc_cv___attribute__format], + [Whether your compiler has __attribute__ format or not]) + AC_DEFINE_UNQUOTED(HWLOC_HAVE_ATTRIBUTE_HOT, [$hwloc_cv___attribute__hot], + [Whether your compiler has __attribute__ hot or not]) + AC_DEFINE_UNQUOTED(HWLOC_HAVE_ATTRIBUTE_MALLOC, [$hwloc_cv___attribute__malloc], + [Whether your compiler has __attribute__ malloc or not]) + AC_DEFINE_UNQUOTED(HWLOC_HAVE_ATTRIBUTE_MAY_ALIAS, [$hwloc_cv___attribute__may_alias], + [Whether your compiler has __attribute__ may_alias or not]) + AC_DEFINE_UNQUOTED(HWLOC_HAVE_ATTRIBUTE_NO_INSTRUMENT_FUNCTION, [$hwloc_cv___attribute__no_instrument_function], + [Whether your compiler has __attribute__ no_instrument_function or not]) + AC_DEFINE_UNQUOTED(HWLOC_HAVE_ATTRIBUTE_NONNULL, [$hwloc_cv___attribute__nonnull], + [Whether your compiler has __attribute__ nonnull or not]) + AC_DEFINE_UNQUOTED(HWLOC_HAVE_ATTRIBUTE_NORETURN, [$hwloc_cv___attribute__noreturn], + [Whether your compiler has __attribute__ noreturn or not]) + AC_DEFINE_UNQUOTED(HWLOC_HAVE_ATTRIBUTE_PACKED, [$hwloc_cv___attribute__packed], + [Whether your compiler has __attribute__ packed or not]) + AC_DEFINE_UNQUOTED(HWLOC_HAVE_ATTRIBUTE_PURE, [$hwloc_cv___attribute__pure], + [Whether your compiler has __attribute__ pure or not]) + AC_DEFINE_UNQUOTED(HWLOC_HAVE_ATTRIBUTE_SENTINEL, [$hwloc_cv___attribute__sentinel], + [Whether your compiler has __attribute__ sentinel or not]) + AC_DEFINE_UNQUOTED(HWLOC_HAVE_ATTRIBUTE_UNUSED, [$hwloc_cv___attribute__unused], + [Whether your compiler has __attribute__ unused or not]) + AC_DEFINE_UNQUOTED(HWLOC_HAVE_ATTRIBUTE_WARN_UNUSED_RESULT, [$hwloc_cv___attribute__warn_unused_result], + [Whether your compiler has __attribute__ warn unused result or not]) + AC_DEFINE_UNQUOTED(HWLOC_HAVE_ATTRIBUTE_WEAK_ALIAS, [$hwloc_cv___attribute__weak_alias], + [Whether your compiler has __attribute__ weak alias or not]) +]) + diff --git a/opal/mca/hwloc/hwloc1110/hwloc/config/hwloc_check_vendor.m4 b/opal/mca/hwloc/hwloc1110/hwloc/config/hwloc_check_vendor.m4 new file mode 100644 index 0000000000..0963bc1749 --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/config/hwloc_check_vendor.m4 @@ -0,0 +1,239 @@ +dnl -*- shell-script -*- +dnl +dnl Copyright © 2004-2005 The Trustees of Indiana University and Indiana +dnl University Research and Technology +dnl Corporation. All rights reserved. +dnl Copyright © 2004-2005 The University of Tennessee and The University +dnl of Tennessee Research Foundation. All rights +dnl reserved. +dnl Copyright © 2004-2005 High Performance Computing Center Stuttgart, +dnl University of Stuttgart. All rights reserved. +dnl Copyright © 2004-2005 The Regents of the University of California. +dnl All rights reserved. +dnl Copyright © 2011 Cisco Systems, Inc. All rights reserved. +dnl $COPYRIGHT$ +dnl +dnl Additional copyrights may follow +dnl +dnl $HEADER$ +dnl + +dnl ------------------------------------------------------------------ +dnl This m4 file originally copied from Open MPI +dnl config/ompi_check_vendor.m4. +dnl ------------------------------------------------------------------ + + +# HWLOC_C_COMPILER_VENDOR(VENDOR_VARIABLE) +# --------------------------------------- +# Set shell variable VENDOR_VARIABLE to the name of the compiler +# vendor for the current C compiler. +# +# See comment for _HWLOC_CHECK_COMPILER_VENDOR for a complete +# list of currently detected compilers. +AC_DEFUN([_HWLOC_C_COMPILER_VENDOR], [ + AC_REQUIRE([AC_PROG_CC]) + + AC_CACHE_CHECK([for the C compiler vendor], + [hwloc_cv_c_compiler_vendor], + [AC_LANG_PUSH(C) + _HWLOC_CHECK_COMPILER_VENDOR([hwloc_cv_c_compiler_vendor]) + AC_LANG_POP(C)]) + + $1="$hwloc_cv_c_compiler_vendor" +]) + + +# workaround to avoid syntax error with Autoconf < 2.68: +m4_ifndef([AC_LANG_DEFINES_PROVIDED], + [m4_define([AC_LANG_DEFINES_PROVIDED])]) + +# HWLOC_IFDEF_IFELSE(symbol, [action-if-defined], +# [action-if-not-defined]) +# ---------------------------------------------- +# Run compiler to determine if preprocessor symbol "symbol" is +# defined by the compiler. +AC_DEFUN([HWLOC_IFDEF_IFELSE], [ + AC_COMPILE_IFELSE([AC_LANG_DEFINES_PROVIDED +#ifndef $1 +#error "symbol $1 not defined" +choke me +#endif], [$2], [$3])]) + + +# HWLOC_IF_IFELSE(symbol, [action-if-defined], +# [action-if-not-defined]) +# ---------------------------------------------- +# Run compiler to determine if preprocessor symbol "symbol" is +# defined by the compiler. +AC_DEFUN([HWLOC_IF_IFELSE], [ + AC_COMPILE_IFELSE([AC_LANG_DEFINES_PROVIDED +#if !( $1 ) +#error "condition $1 not met" +choke me +#endif], [$2], [$3])]) + + +# _HWLOC_CHECK_COMPILER_VENDOR(VENDOR_VARIABLE) +# -------------------------------------------- +# Set shell variable VENDOR_VARIABLE to the name of the compiler +# vendor for the compiler for the current language. Language must be +# one of C, OBJC, or C++. +# +# thanks to http://predef.sourceforge.net/precomp.html for the list +# of defines to check. +AC_DEFUN([_HWLOC_CHECK_COMPILER_VENDOR], [ + hwloc_check_compiler_vendor_result="unknown" + + # GNU is probably the most common, so check that one as soon as + # possible. Intel pretends to be GNU, so need to check Intel + # before checking for GNU. + + # Intel + AS_IF([test "$hwloc_check_compiler_vendor_result" = "unknown"], + [HWLOC_IF_IFELSE([defined(__INTEL_COMPILER) || defined(__ICC)], + [hwloc_check_compiler_vendor_result="intel"])]) + + # GNU + AS_IF([test "$hwloc_check_compiler_vendor_result" = "unknown"], + [HWLOC_IFDEF_IFELSE([__GNUC__], + [hwloc_check_compiler_vendor_result="gnu"])]) + + # Borland Turbo C + AS_IF([test "$hwloc_check_compiler_vendor_result" = "unknown"], + [HWLOC_IFDEF_IFELSE([__TURBOC__], + [hwloc_check_compiler_vendor_result="borland"])]) + + # Borland C++ + AS_IF([test "$hwloc_check_compiler_vendor_result" = "unknown"], + [HWLOC_IFDEF_IFELSE([__BORLANDC__], + [hwloc_check_compiler_vendor_result="borland"])]) + + # Comeau C++ + AS_IF([test "$hwloc_check_compiler_vendor_result" = "unknown"], + [HWLOC_IFDEF_IFELSE([__COMO__], + [hwloc_check_compiler_vendor_result="comeau"])]) + + # Compaq C/C++ + AS_IF([test "$hwloc_check_compiler_vendor_result" = "unknown"], + [HWLOC_IF_IFELSE([defined(__DECC) || defined(VAXC) || defined(__VAXC)], + [hwloc_check_compiler_vendor_result="compaq"], + [HWLOC_IF_IFELSE([defined(__osf__) && defined(__LANGUAGE_C__)], + [hwloc_check_compiler_vendor_result="compaq"], + [HWLOC_IFDEF_IFELSE([__DECCXX], + [hwloc_check_compiler_vendor_result="compaq"])])])]) + + # Cray C/C++ + AS_IF([test "$hwloc_check_compiler_vendor_result" = "unknown"], + [HWLOC_IFDEF_IFELSE([_CRAYC], + [hwloc_check_compiler_vendor_result="cray"])]) + + # Diab C/C++ + AS_IF([test "$hwloc_check_compiler_vendor_result" = "unknown"], + [HWLOC_IFDEF_IFELSE([__DCC__], + [hwloc_check_compiler_vendor_result="diab"])]) + + # Digital Mars + AS_IF([test "$hwloc_check_compiler_vendor_result" = "unknown"], + [HWLOC_IF_IFELSE([defined(__DMC__) || defined(__SC__) || defined(__ZTC__)], + [hwloc_check_compiler_vendor_result="digital mars"])]) + + # HP ANSI C / aC++ + AS_IF([test "$hwloc_check_compiler_vendor_result" = "unknown"], + [HWLOC_IF_IFELSE([defined(__HP_cc) || defined(__HP_aCC)], + [hwloc_check_compiler_vendor_result="hp"])]) + + # IBM XL C/C++ + AS_IF([test "$hwloc_check_compiler_vendor_result" = "unknown"], + [HWLOC_IF_IFELSE([defined(__xlC__) || defined(__IBMC__) || defined(__IBMCPP__)], + [hwloc_check_compiler_vendor_result="ibm"], + [HWLOC_IF_IFELSE([defined(_AIX) && !defined(__GNUC__)], + [hwloc_check_compiler_vendor_result="ibm"])])]) + + # KAI C++ (rest in peace) + AS_IF([test "$hwloc_check_compiler_vendor_result" = "unknown"], + [HWLOC_IFDEF_IFELSE([__KCC], + [hwloc_check_compiler_vendor_result="kai"])]) + + # LCC + AS_IF([test "$hwloc_check_compiler_vendor_result" = "unknown"], + [HWLOC_IFDEF_IFELSE([__LCC__], + [hwloc_check_compiler_vendor_result="lcc"])]) + + # MetaWare High C/C++ + AS_IF([test "$hwloc_check_compiler_vendor_result" = "unknown"], + [HWLOC_IFDEF_IFELSE([__HIGHC__], + [hwloc_check_compiler_vendor_result="metaware high"])]) + + # Metrowerks Codewarrior + AS_IF([test "$hwloc_check_compiler_vendor_result" = "unknown"], + [HWLOC_IFDEF_IFELSE([__MWERKS__], + [hwloc_check_compiler_vendor_result="metrowerks"])]) + + # MIPSpro (SGI) + AS_IF([test "$hwloc_check_compiler_vendor_result" = "unknown"], + [HWLOC_IF_IFELSE([defined(sgi) || defined(__sgi)], + [hwloc_check_compiler_vendor_result="sgi"])]) + + # MPW C++ + AS_IF([test "$hwloc_check_compiler_vendor_result" = "unknown"], + [HWLOC_IF_IFELSE([defined(__MRC__) || defined(MPW_C) || defined(MPW_CPLUS)], + [hwloc_check_compiler_vendor_result="mpw"])]) + + # Microsoft + AS_IF([test "$hwloc_check_compiler_vendor_result" = "unknown"], + [# Always use C compiler when checking for Microsoft, as + # Visual C++ doesn't recognize .cc as a C++ file. + AC_LANG_PUSH(C) + HWLOC_IF_IFELSE([defined(_MSC_VER) || defined(__MSC_VER)], + [hwloc_check_compiler_vendor_result="microsoft"]) + AC_LANG_POP(C)]) + + # Norcroft C + AS_IF([test "$hwloc_check_compiler_vendor_result" = "unknown"], + [HWLOC_IFDEF_IFELSE([__CC_NORCROFT], + [hwloc_check_compiler_vendor_result="norcroft"])]) + + # Pelles C + AS_IF([test "$hwloc_check_compiler_vendor_result" = "unknown"], + [HWLOC_IFDEF_IFELSE([__POCC__], + [hwloc_check_compiler_vendor_result="pelles"])]) + + # Portland Group + AS_IF([test "$hwloc_check_compiler_vendor_result" = "unknown"], + [HWLOC_IFDEF_IFELSE([__PGI], + [hwloc_check_compiler_vendor_result="portland group"])]) + + # SAS/C + AS_IF([test "$hwloc_check_compiler_vendor_result" = "unknown"], + [HWLOC_IF_IFELSE([defined(SASC) || defined(__SASC) || defined(__SASC__)], + [hwloc_check_compiler_vendor_result="sas"])]) + + # Sun Workshop C/C++ + AS_IF([test "$hwloc_check_compiler_vendor_result" = "unknown"], + [HWLOC_IF_IFELSE([defined(__SUNPRO_C) || defined(__SUNPRO_CC)], + [hwloc_check_compiler_vendor_result="sun"])]) + + # TenDRA C/C++ + AS_IF([test "$hwloc_check_compiler_vendor_result" = "unknown"], + [HWLOC_IFDEF_IFELSE([__TenDRA__], + [hwloc_check_compiler_vendor_result="tendra"])]) + + # Tiny C + AS_IF([test "$hwloc_check_compiler_vendor_result" = "unknown"], + [HWLOC_IFDEF_IFELSE([__TINYC__], + [hwloc_check_compiler_vendor_result="tiny"])]) + + # USL C + AS_IF([test "$hwloc_check_compiler_vendor_result" = "unknown"], + [HWLOC_IFDEF_IFELSE([__USLC__], + [hwloc_check_compiler_vendor_result="usl"])]) + + # Watcom C++ + AS_IF([test "$hwloc_check_compiler_vendor_result" = "unknown"], + [HWLOC_IFDEF_IFELSE([__WATCOMC__], + [hwloc_check_compiler_vendor_result="watcom"])]) + + $1="$hwloc_check_compiler_vendor_result" + unset hwloc_check_compiler_vendor_result +]) diff --git a/opal/mca/hwloc/hwloc1110/hwloc/config/hwloc_check_visibility.m4 b/opal/mca/hwloc/hwloc1110/hwloc/config/hwloc_check_visibility.m4 new file mode 100644 index 0000000000..885fe3d8df --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/config/hwloc_check_visibility.m4 @@ -0,0 +1,131 @@ +# This macro set originally copied from Open MPI: +# Copyright © 2004-2005 The Trustees of Indiana University and Indiana +# University Research and Technology +# Corporation. All rights reserved. +# Copyright © 2004-2005 The University of Tennessee and The University +# of Tennessee Research Foundation. All rights +# reserved. +# Copyright © 2004-2007 High Performance Computing Center Stuttgart, +# University of Stuttgart. All rights reserved. +# Copyright © 2004-2005 The Regents of the University of California. +# All rights reserved. +# Copyright © 2006-2007 Cisco Systems, Inc. All rights reserved. +# and renamed/modified for hwloc: +# Copyright © 2009 Inria. All rights reserved. +# Copyright © 2009-2010 Université Bordeaux +# Copyright © 2010-2012 Cisco Systems, Inc. All rights reserved. +# See COPYING in top-level directory. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer listed +# in this license in the documentation and/or other materials +# provided with the distribution. +# +# - Neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# The copyright holders provide no reassurances that the source code +# provided does not infringe any patent, copyright, or any other +# intellectual property rights of third parties. The copyright holders +# disclaim any liability to any recipient for claims brought against +# recipient by any third party for infringement of that parties +# intellectual property rights. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +# _HWLOC_CHECK_VISIBILITY +# -------------------------------------------------------- +AC_DEFUN([_HWLOC_CHECK_VISIBILITY],[ + # Be safe for systems that have ancient Autoconf's (e.g., RHEL5) + m4_ifdef([AC_PROG_GREP], + [AC_REQUIRE([AC_PROG_GREP])], + [GREP=grep]) + + # Check if the compiler has support for visibility, like some + # versions of gcc, icc, Sun Studio cc. + AC_ARG_ENABLE(visibility, + AC_HELP_STRING([--enable-visibility], + [enable visibility feature of certain compilers/linkers (default: enabled on platforms that support it)])) + + case ${target} in + *-*-aix*|*-*-mingw*|*-*-cygwin*|*-*-hpux*) + enable_visibility=no + ;; + esac + + hwloc_visibility_define=0 + hwloc_msg="whether to enable symbol visibility" + if test "$enable_visibility" = "no"; then + AC_MSG_CHECKING([$hwloc_msg]) + AC_MSG_RESULT([no (disabled)]) + else + CFLAGS_orig=$CFLAGS + + hwloc_add= + case "$hwloc_c_vendor" in + sun) + # Check using Sun Studio -xldscope=hidden flag + hwloc_add=-xldscope=hidden + CFLAGS="$CFLAGS_orig $hwloc_add -errwarn=%all" + ;; + + *) + # Check using -fvisibility=hidden + hwloc_add=-fvisibility=hidden + CFLAGS="$CFLAGS_orig $hwloc_add -Werror" + ;; + esac + + AC_MSG_CHECKING([if $CC supports $hwloc_add]) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ + #include + __attribute__((visibility("default"))) int foo; + ]],[[fprintf(stderr, "Hello, world\n");]])], + [AS_IF([test -s conftest.err], + [$GREP -iq visibility conftest.err + # If we find "visibility" in the stderr, then + # assume it doesn't work + AS_IF([test "$?" = "0"], [hwloc_add=])]) + ], [hwloc_add=]) + AS_IF([test "$hwloc_add" = ""], + [AC_MSG_RESULT([no])], + [AC_MSG_RESULT([yes])]) + + CFLAGS=$CFLAGS_orig + HWLOC_VISIBILITY_CFLAGS=$hwloc_add + + if test "$hwloc_add" != "" ; then + hwloc_visibility_define=1 + AC_MSG_CHECKING([$hwloc_msg]) + AC_MSG_RESULT([yes (via $hwloc_add)]) + elif test "$enable_visibility" = "yes"; then + AC_MSG_ERROR([Symbol visibility support requested but compiler does not seem to support it. Aborting]) + else + AC_MSG_CHECKING([$hwloc_msg]) + AC_MSG_RESULT([no (unsupported)]) + fi + unset hwloc_add + fi + + AC_DEFINE_UNQUOTED([HWLOC_C_HAVE_VISIBILITY], [$hwloc_visibility_define], + [Whether C compiler supports symbol visibility or not]) +]) diff --git a/opal/mca/hwloc/hwloc1110/hwloc/config/hwloc_components.m4 b/opal/mca/hwloc/hwloc1110/hwloc/config/hwloc_components.m4 new file mode 100644 index 0000000000..7d5c1fa194 --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/config/hwloc_components.m4 @@ -0,0 +1,66 @@ +# Copyright © 2012 Inria. All rights reserved. +# See COPYING in top-level directory. + + +# HWLOC_PREPARE_FILTER_COMPONENTS +# +# Given a comma-separated list of names, define hwloc__component_maybeplugin=1. +# +# $1 = command-line given list of components to build as plugins +# +AC_DEFUN([HWLOC_PREPARE_FILTER_COMPONENTS], [ + for name in `echo [$1] | sed -e 's/,/ /g'` ; do + str="hwloc_${name}_component_wantplugin=1" + eval $str + done +]) + + +# HWLOC_FILTER_COMPONENTS +# +# For each component in hwloc_components, +# check if hwloc__component_wantplugin=1 or enable_plugin=yes, +# and check if hwloc__component_maybeplugin=1. +# Add to hwloc_[static|plugin]_components accordingly. +# And set hwloc__component=[static|plugin] accordingly. +# +AC_DEFUN([HWLOC_FILTER_COMPONENTS], [ +for name in $hwloc_components ; do + str="maybeplugin=\$hwloc_${name}_component_maybeplugin" + eval $str + str="wantplugin=\$hwloc_${name}_component_wantplugin" + eval $str + if test x$hwloc_have_plugins = xyes && test x$maybeplugin = x1 && test x$wantplugin = x1 -o x$enable_plugins = xyes; then + hwloc_plugin_components="$hwloc_plugin_components $name" + str="hwloc_${name}_component=plugin" + else + hwloc_static_components="$hwloc_static_components $name" + str="hwloc_${name}_component=static" + fi + eval $str +done +]) + + +# HWLOC_LIST_STATIC_COMPONENTS +# +# Append to file $1 an array of components by listing component names in $2. +# +# $1 = filename +# $2 = list of component names +# +AC_DEFUN([HWLOC_LIST_STATIC_COMPONENTS], [ +for comp in [$2]; do + echo "HWLOC_DECLSPEC extern const struct hwloc_component hwloc_${comp}_component;" >>[$1] +done +cat <>[$1] +static const struct hwloc_component * hwloc_static_components[[]] = { +EOF +for comp in [$2]; do + echo " &hwloc_${comp}_component," >>[$1] +done +cat <>[$1] + NULL +}; +EOF +]) diff --git a/opal/mca/hwloc/hwloc1110/hwloc/config/hwloc_get_version.sh b/opal/mca/hwloc/hwloc1110/hwloc/config/hwloc_get_version.sh new file mode 100755 index 0000000000..74bca537ce --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/config/hwloc_get_version.sh @@ -0,0 +1,98 @@ +#!/bin/sh +# +# Copyright © 2004-2006 The Trustees of Indiana University and Indiana +# University Research and Technology +# Corporation. All rights reserved. +# Copyright © 2004-2005 The University of Tennessee and The University +# of Tennessee Research Foundation. All rights +# reserved. +# Copyright © 2004-2005 High Performance Computing Center Stuttgart, +# University of Stuttgart. All rights reserved. +# Copyright © 2004-2005 The Regents of the University of California. +# All rights reserved. +# Copyright © 2008-2014 Cisco Systems, Inc. All rights reserved. +# Copyright © 2014 Inria. All rights reserved. +# $COPYRIGHT$ +# +# Additional copyrights may follow +# +# $HEADER$ +# + +srcfile="$1" +option="$2" + +if test -z "$srcfile"; then + option="--help" +else + : ${srcdir=.} + + if test -f "$srcfile"; then + ompi_vers=`sed -n " + t clear + : clear + s/^major/HWLOC_MAJOR_VERSION/ + s/^minor/HWLOC_MINOR_VERSION/ + s/^release/HWLOC_RELEASE_VERSION/ + s/^greek/HWLOC_GREEK_VERSION/ + s/\\\${major}/\\\${HWLOC_MAJOR_VERSION}/ + s/\\\${minor}/\\\${HWLOC_MINOR_VERSION}/ + s/\\\${release}/\\\${HWLOC_RELEASE_VERSION}/ + s/\\\${greek}/\\\${HWLOC_GREEK_VERSION}/ + s/^date/HWLOC_RELEASE_DATE/ + s/^snapshot_version/HWLOC_SNAPSHOT_VERSION/ + s/^snapshot/HWLOC_SNAPSHOT/ + t print + b + : print + p" < "$srcfile"` + eval "$ompi_vers" + + HWLOC_VERSION="$HWLOC_MAJOR_VERSION.$HWLOC_MINOR_VERSION.$HWLOC_RELEASE_VERSION${HWLOC_GREEK_VERSION}" + + # If HWLOC_SNAPSHOT=1, then use HWLOC_SNAPSHOT_VERSION + if test "$HWLOC_SNAPSHOT" = "1"; then + # First, verify that HWLOC_SNAPSHOT_VERSION isn't empty. + if test -z "$HWLOC_SNAPSHOT_VERSION"; then + echo "*** ERROR: $1 contains snapshot=1, but an empty value for snapshot_version" 1>&2 + exit 1 + fi + HWLOC_VERSION=$HWLOC_SNAPSHOT_VERSION + fi + fi + + if test "$option" = ""; then + option="--version" + fi +fi + +case "$option" in + --version) + echo $HWLOC_VERSION + ;; + --release-date) + echo $HWLOC_RELEASE_DATE + ;; + --snapshot) + echo $HWLOC_SNAPSHOT + ;; + -h|--help) + cat < */ + 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); + void (*close_content)(struct hwloc__xml_import_state_s * state); + char * msgprefix; + void *data; /* libxml2 doc, or nolibxml buffer */ + struct hwloc_xml_imported_distances_s { + hwloc_obj_t root; + struct hwloc_distances_s distances; + struct hwloc_xml_imported_distances_s *prev, *next; + } *first_distances, *last_distances; +}; + +/************** + * XML export * + **************/ + +typedef struct hwloc__xml_export_state_s { + struct hwloc__xml_export_state_s *parent; + + void (*new_child)(struct hwloc__xml_export_state_s *parentstate, struct hwloc__xml_export_state_s *state, const char *name); + void (*new_prop)(struct hwloc__xml_export_state_s *state, const char *name, const char *value); + void (*add_content)(struct hwloc__xml_export_state_s *state, const char *buffer, size_t length); + void (*end_object)(struct hwloc__xml_export_state_s *state, const char *name); + + /* opaque data used to store backend-specific data. + * statically allocated to allow stack-allocation by the common code without knowing actual backend needs. + */ + char data[40]; +} * hwloc__xml_export_state_t; + +HWLOC_DECLSPEC void hwloc__xml_export_object (hwloc__xml_export_state_t state, struct hwloc_topology *topology, struct hwloc_obj *obj); + +HWLOC_DECLSPEC void hwloc__xml_export_diff(hwloc__xml_export_state_t parentstate, hwloc_topology_diff_t diff); + +/****************** + * XML components * + ******************/ + +struct hwloc_xml_callbacks { + int (*backend_init)(struct hwloc_xml_backend_data_s *bdata, const char *xmlpath, const char *xmlbuffer, int xmlbuflen); + int (*export_file)(struct hwloc_topology *topology, const char *filename); + int (*export_buffer)(struct hwloc_topology *topology, char **xmlbuffer, int *buflen); + void (*free_buffer)(void *xmlbuffer); + int (*import_diff)(struct hwloc__xml_import_state_s *state, const char *xmlpath, const char *xmlbuffer, int xmlbuflen, hwloc_topology_diff_t *diff, char **refnamep); + int (*export_diff_file)(union hwloc_topology_diff_u *diff, const char *refname, const char *filename); + int (*export_diff_buffer)(union hwloc_topology_diff_u *diff, const char *refname, char **xmlbuffer, int *buflen); +}; + +struct hwloc_xml_component { + struct hwloc_xml_callbacks *nolibxml_callbacks; + struct hwloc_xml_callbacks *libxml_callbacks; +}; + +HWLOC_DECLSPEC void hwloc_xml_callbacks_register(struct hwloc_xml_component *component); +HWLOC_DECLSPEC void hwloc_xml_callbacks_reset(void); + +#endif /* PRIVATE_XML_H */ diff --git a/opal/mca/hwloc/hwloc1110/hwloc/src/Makefile.am b/opal/mca/hwloc/hwloc1110/hwloc/src/Makefile.am new file mode 100644 index 0000000000..41aa35c14e --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/src/Makefile.am @@ -0,0 +1,235 @@ +# Copyright © 2009-2014 Inria. All rights reserved. +# Copyright © 2009-2012 Université Bordeaux +# Copyright © 2009-2014 Cisco Systems, Inc. All rights reserved. +# Copyright © 2011-2012 Oracle and/or its affiliates. All rights reserved. +# See COPYING in top-level directory. + +AM_CFLAGS = $(HWLOC_CFLAGS) +AM_CPPFLAGS = $(HWLOC_CPPFLAGS) -DHWLOC_INSIDE_LIBHWLOC +AM_LDFLAGS = $(HWLOC_LDFLAGS) + +EXTRA_DIST = dolib.c + +# If we're in standalone mode, build the installable library. +# Otherwise, build the embedded library. + +if HWLOC_BUILD_STANDALONE +lib_LTLIBRARIES = libhwloc.la +else +noinst_LTLIBRARIES = libhwloc_embedded.la +endif + +pluginsdir = @HWLOC_PLUGINS_DIR@ +plugins_LTLIBRARIES = +plugins_ldflags = -module -avoid-version -lltdl +AM_CPPFLAGS += -DHWLOC_PLUGINS_PATH=\"$(HWLOC_PLUGINS_PATH)\" + +# Sources and ldflags + +sources = \ + topology.c \ + traversal.c \ + distances.c \ + components.c \ + bind.c \ + bitmap.c \ + pci-common.c \ + diff.c \ + misc.c \ + base64.c \ + topology-noos.c \ + topology-synthetic.c \ + topology-custom.c \ + topology-xml.c \ + topology-xml-nolibxml.c +ldflags = + +# Conditionally add to the sources and ldflags + +if HWLOC_HAVE_LIBXML2 +if HWLOC_XML_LIBXML_BUILD_STATIC +sources += topology-xml-libxml.c +else +plugins_LTLIBRARIES += hwloc_xml_libxml.la +hwloc_xml_libxml_la_SOURCES = topology-xml-libxml.c +hwloc_xml_libxml_la_CFLAGS = $(AM_CFLAGS) $(HWLOC_LIBXML2_CFLAGS) -DHWLOC_INSIDE_PLUGIN +hwloc_xml_libxml_la_LDFLAGS = $(plugins_ldflags) $(HWLOC_LIBXML2_LIBS) +endif +endif HWLOC_HAVE_LIBXML2 + +if HWLOC_HAVE_PCI +if HWLOC_PCI_BUILD_STATIC +sources += topology-pci.c +else +plugins_LTLIBRARIES += hwloc_pci.la +hwloc_pci_la_SOURCES = topology-pci.c +hwloc_pci_la_CFLAGS = $(AM_CFLAGS) $(HWLOC_PCIACCESS_CFLAGS) -DHWLOC_INSIDE_PLUGIN +hwloc_pci_la_LDFLAGS = $(plugins_ldflags) $(HWLOC_PCIACCESS_LIBS) +endif +endif HWLOC_HAVE_PCI + +if HWLOC_HAVE_OPENCL +if HWLOC_OPENCL_BUILD_STATIC +sources += topology-opencl.c +else +plugins_LTLIBRARIES += hwloc_opencl.la +hwloc_opencl_la_SOURCES = topology-opencl.c +hwloc_opencl_la_CFLAGS = $(AM_CFLAGS) $(HWLOC_OPENCL_CFLAGS) -DHWLOC_INSIDE_PLUGIN +hwloc_opencl_la_LDFLAGS = $(plugins_ldflags) $(HWLOC_OPENCL_LIBS) +endif +endif HWLOC_HAVE_OPENCL + +if HWLOC_HAVE_CUDART +if HWLOC_CUDA_BUILD_STATIC +sources += topology-cuda.c +else +plugins_LTLIBRARIES += hwloc_cuda.la +hwloc_cuda_la_SOURCES = topology-cuda.c +hwloc_cuda_la_CFLAGS = $(AM_CFLAGS) $(HWLOC_CUDA_CFLAGS) -DHWLOC_INSIDE_PLUGIN +hwloc_cuda_la_LDFLAGS = $(plugins_ldflags) $(HWLOC_CUDA_LIBS) +endif +endif HWLOC_HAVE_CUDART + +if HWLOC_HAVE_NVML +if HWLOC_NVML_BUILD_STATIC +sources += topology-nvml.c +else +plugins_LTLIBRARIES += hwloc_nvml.la +hwloc_nvml_la_SOURCES = topology-nvml.c +hwloc_nvml_la_CFLAGS = $(AM_CFLAGS) $(HWLOC_NVML_CFLAGS) -DHWLOC_INSIDE_PLUGIN +hwloc_nvml_la_LDFLAGS = $(plugins_ldflags) $(HWLOC_NVML_LIBS) +endif +endif HWLOC_HAVE_NVML + +if HWLOC_HAVE_GL +if HWLOC_GL_BUILD_STATIC +sources += topology-gl.c +else +plugins_LTLIBRARIES += hwloc_gl.la +hwloc_gl_la_SOURCES = topology-gl.c +hwloc_gl_la_CFLAGS = $(AM_CFLAGS) $(HWLOC_GL_CFLAGS) -DHWLOC_INSIDE_PLUGIN +hwloc_gl_la_LDFLAGS = $(plugins_ldflags) $(HWLOC_GL_LIBS) +endif +endif HWLOC_HAVE_GL + +if HWLOC_HAVE_SOLARIS +sources += topology-solaris.c +sources += topology-solaris-chiptype.c +endif HWLOC_HAVE_SOLARIS + +if HWLOC_HAVE_LINUX +sources += topology-linux.c +endif HWLOC_HAVE_LINUX + +if HWLOC_HAVE_BGQ +sources += topology-bgq.c +endif HWLOC_HAVE_BGQ + +if HWLOC_HAVE_AIX +sources += topology-aix.c +ldflags += -lpthread +endif HWLOC_HAVE_AIX + +if HWLOC_HAVE_OSF +sources += topology-osf.c +ldflags += -lnuma -lpthread +endif HWLOC_HAVE_OSF + +if HWLOC_HAVE_HPUX +sources += topology-hpux.c +ldflags += -lpthread +endif HWLOC_HAVE_HPUX + +if HWLOC_HAVE_WINDOWS +sources += topology-windows.c +endif HWLOC_HAVE_WINDOWS + +if HWLOC_HAVE_DARWIN +sources += topology-darwin.c +endif HWLOC_HAVE_DARWIN + +if HWLOC_HAVE_FREEBSD +sources += topology-freebsd.c +endif HWLOC_HAVE_FREEBSD + +if HWLOC_HAVE_NETBSD +sources += topology-netbsd.c +ldflags += -lpthread +endif HWLOC_HAVE_NETBSD + +if HWLOC_HAVE_X86_CPUID +sources += topology-x86.c +endif HWLOC_HAVE_X86_CPUID + +if HWLOC_HAVE_GCC +ldflags += -no-undefined +endif HWLOC_HAVE_GCC + + +if HWLOC_HAVE_WINDOWS +# Windows specific rules + +LC_MESSAGES=C +export LC_MESSAGES +ldflags += -Xlinker --output-def -Xlinker .libs/libhwloc.def + +if HWLOC_HAVE_MS_LIB +dolib$(EXEEXT): dolib.c + $(CC_FOR_BUILD) $< -o $@ +.libs/libhwloc.lib: libhwloc.la dolib$(EXEEXT) + [ ! -r .libs/libhwloc.def ] || ./dolib$(EXEEXT) "$(HWLOC_MS_LIB)" $(HWLOC_MS_LIB_ARCH) .libs/libhwloc.def $(libhwloc_so_version) .libs/libhwloc.lib +all-local: .libs/libhwloc.lib +clean-local: + $(RM) dolib$(EXEEXT) +endif HWLOC_HAVE_MS_LIB + +install-exec-hook: + [ ! -r .libs/libhwloc.def ] || $(INSTALL) .libs/libhwloc.def $(DESTDIR)$(libdir) +if HWLOC_HAVE_MS_LIB + [ ! -r .libs/libhwloc.def ] || $(INSTALL) .libs/libhwloc.lib $(DESTDIR)$(libdir) + [ ! -r .libs/libhwloc.def ] || $(INSTALL) .libs/libhwloc.exp $(DESTDIR)$(libdir) +endif HWLOC_HAVE_MS_LIB + +uninstall-local: + rm -f $(DESTDIR)$(libdir)/libhwloc.def +if HWLOC_HAVE_MS_LIB + rm -f $(DESTDIR)$(libdir)/libhwloc.lib $(DESTDIR)$(libdir)/libhwloc.exp +endif HWLOC_HAVE_MS_LIB + +# End of Windows specific rules +endif HWLOC_HAVE_WINDOWS + + +# Installable library + +libhwloc_la_SOURCES = $(sources) +libhwloc_la_LDFLAGS = $(ldflags) -version-info $(libhwloc_so_version) $(HWLOC_LIBS) + +if HWLOC_HAVE_PLUGINS +AM_CPPFLAGS += $(LTDLINCL) +libhwloc_la_LDFLAGS += -export-dynamic +libhwloc_la_LIBADD = $(LIBLTDL) +endif + +# Embedded library (note the lack of a .so version number -- that +# intentionally only appears in the installable library). Also note +# the lack of _LDFLAGS -- all libs are added by the upper layer (via +# HWLOC_EMBEDDED_LIBS). + +libhwloc_embedded_la_SOURCES = $(sources) + +# XML data (only install if we're building in standalone mode) + +if HWLOC_BUILD_STANDALONE +xml_DATA = $(srcdir)/hwloc.dtd +xmldir = $(pkgdatadir) +EXTRA_DIST += hwloc.dtd +endif + +DISTCLEANFILES = static-components.h + +if HWLOC_HAVE_PLUGINS +check_LTLIBRARIES = hwloc_fake.la +hwloc_fake_la_SOURCES = topology-fake.c +hwloc_fake_la_LDFLAGS = $(plugins_ldflags) -rpath /nowhere # force libtool to build a shared-library even it's check-only +endif diff --git a/opal/mca/hwloc/hwloc1110/hwloc/src/base64.c b/opal/mca/hwloc/hwloc1110/hwloc/src/base64.c new file mode 100644 index 0000000000..7a3392fab8 --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/src/base64.c @@ -0,0 +1,306 @@ +/* + * Copyright © 2012 Inria. All rights reserved. + * See COPYING in top-level directory. + * + * Modifications after import: + * - removed all #if + * - updated prototypes + * - updated #include + */ + +/* $OpenBSD: base64.c,v 1.5 2006/10/21 09:55:03 otto Exp $ */ + +/* + * Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Portions Copyright (c) 1995 by International Business Machines, Inc. + * + * International Business Machines, Inc. (hereinafter called IBM) grants + * permission under its copyrights to use, copy, modify, and distribute this + * Software with or without fee, provided that the above copyright notice and + * all paragraphs of this notice appear in all copies, and that the name of IBM + * not be used in connection with the marketing of any product incorporating + * the Software or modifications thereof, without specific, written prior + * permission. + * + * To the extent it has a right to do so, IBM grants an immunity from suit + * under its patents, if any, for the use, sale or manufacture of products to + * the extent that such products are used for performing Domain Name System + * dynamic updates in TCP/IP networks by means of the Software. No immunity is + * granted for any product per se or for any other function of any product. + * + * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, + * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN + * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +/* OPENBSD ORIGINAL: lib/libc/net/base64.c */ + +static const char Base64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const char Pad64 = '='; + +/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt) + The following encoding technique is taken from RFC 1521 by Borenstein + and Freed. It is reproduced here in a slightly edited form for + convenience. + + A 65-character subset of US-ASCII is used, enabling 6 bits to be + represented per printable character. (The extra 65th character, "=", + is used to signify a special processing function.) + + The encoding process represents 24-bit groups of input bits as output + strings of 4 encoded characters. Proceeding from left to right, a + 24-bit input group is formed by concatenating 3 8-bit input groups. + These 24 bits are then treated as 4 concatenated 6-bit groups, each + of which is translated into a single digit in the base64 alphabet. + + Each 6-bit group is used as an index into an array of 64 printable + characters. The character referenced by the index is placed in the + output string. + + Table 1: The Base64 Alphabet + + Value Encoding Value Encoding Value Encoding Value Encoding + 0 A 17 R 34 i 51 z + 1 B 18 S 35 j 52 0 + 2 C 19 T 36 k 53 1 + 3 D 20 U 37 l 54 2 + 4 E 21 V 38 m 55 3 + 5 F 22 W 39 n 56 4 + 6 G 23 X 40 o 57 5 + 7 H 24 Y 41 p 58 6 + 8 I 25 Z 42 q 59 7 + 9 J 26 a 43 r 60 8 + 10 K 27 b 44 s 61 9 + 11 L 28 c 45 t 62 + + 12 M 29 d 46 u 63 / + 13 N 30 e 47 v + 14 O 31 f 48 w (pad) = + 15 P 32 g 49 x + 16 Q 33 h 50 y + + Special processing is performed if fewer than 24 bits are available + at the end of the data being encoded. A full encoding quantum is + always completed at the end of a quantity. When fewer than 24 input + bits are available in an input group, zero bits are added (on the + right) to form an integral number of 6-bit groups. Padding at the + end of the data is performed using the '=' character. + + Since all base64 input is an integral number of octets, only the + ------------------------------------------------- + following cases can arise: + + (1) the final quantum of encoding input is an integral + multiple of 24 bits; here, the final unit of encoded + output will be an integral multiple of 4 characters + with no "=" padding, + (2) the final quantum of encoding input is exactly 8 bits; + here, the final unit of encoded output will be two + characters followed by two "=" padding characters, or + (3) the final quantum of encoding input is exactly 16 bits; + here, the final unit of encoded output will be three + characters followed by one "=" padding character. + */ + +#include +#include +#include + +#include + +int +hwloc_encode_to_base64(const char *src, size_t srclength, char *target, size_t targsize) +{ + size_t datalength = 0; + unsigned char input[3]; + unsigned char output[4]; + unsigned int i; + + while (2 < srclength) { + input[0] = *src++; + input[1] = *src++; + input[2] = *src++; + srclength -= 3; + + output[0] = input[0] >> 2; + output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); + output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); + output[3] = input[2] & 0x3f; + + if (datalength + 4 > targsize) + return (-1); + target[datalength++] = Base64[output[0]]; + target[datalength++] = Base64[output[1]]; + target[datalength++] = Base64[output[2]]; + target[datalength++] = Base64[output[3]]; + } + + /* Now we worry about padding. */ + if (0 != srclength) { + /* Get what's left. */ + input[0] = input[1] = input[2] = '\0'; + for (i = 0; i < srclength; i++) + input[i] = *src++; + + output[0] = input[0] >> 2; + output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); + output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); + + if (datalength + 4 > targsize) + return (-1); + target[datalength++] = Base64[output[0]]; + target[datalength++] = Base64[output[1]]; + if (srclength == 1) + target[datalength++] = Pad64; + else + target[datalength++] = Base64[output[2]]; + target[datalength++] = Pad64; + } + if (datalength >= targsize) + return (-1); + target[datalength] = '\0'; /* Returned value doesn't count \0. */ + return (datalength); +} + +/* skips all whitespace anywhere. + converts characters, four at a time, starting at (or after) + src from base - 64 numbers into three 8 bit bytes in the target area. + it returns the number of data bytes stored at the target, or -1 on error. + */ + +int +hwloc_decode_from_base64(char const *src, char *target, size_t targsize) +{ + unsigned int tarindex, state; + int ch; + char *pos; + + state = 0; + tarindex = 0; + + while ((ch = *src++) != '\0') { + if (isspace(ch)) /* Skip whitespace anywhere. */ + continue; + + if (ch == Pad64) + break; + + pos = strchr(Base64, ch); + if (pos == 0) /* A non-base64 character. */ + return (-1); + + switch (state) { + case 0: + if (target) { + if (tarindex >= targsize) + return (-1); + target[tarindex] = (pos - Base64) << 2; + } + state = 1; + break; + case 1: + if (target) { + if (tarindex + 1 >= targsize) + return (-1); + target[tarindex] |= (pos - Base64) >> 4; + target[tarindex+1] = ((pos - Base64) & 0x0f) + << 4 ; + } + tarindex++; + state = 2; + break; + case 2: + if (target) { + if (tarindex + 1 >= targsize) + return (-1); + target[tarindex] |= (pos - Base64) >> 2; + target[tarindex+1] = ((pos - Base64) & 0x03) + << 6; + } + tarindex++; + state = 3; + break; + case 3: + if (target) { + if (tarindex >= targsize) + return (-1); + target[tarindex] |= (pos - Base64); + } + tarindex++; + state = 0; + break; + } + } + + /* + * We are done decoding Base-64 chars. Let's see if we ended + * on a byte boundary, and/or with erroneous trailing characters. + */ + + if (ch == Pad64) { /* We got a pad char. */ + ch = *src++; /* Skip it, get next. */ + switch (state) { + case 0: /* Invalid = in first position */ + case 1: /* Invalid = in second position */ + return (-1); + + case 2: /* Valid, means one byte of info */ + /* Skip any number of spaces. */ + for (; ch != '\0'; ch = *src++) + if (!isspace(ch)) + break; + /* Make sure there is another trailing = sign. */ + if (ch != Pad64) + return (-1); + ch = *src++; /* Skip the = */ + /* Fall through to "single trailing =" case. */ + /* FALLTHROUGH */ + + case 3: /* Valid, means two bytes of info */ + /* + * We know this char is an =. Is there anything but + * whitespace after it? + */ + for (; ch != '\0'; ch = *src++) + if (!isspace(ch)) + return (-1); + + /* + * Now make sure for cases 2 and 3 that the "extra" + * bits that slopped past the last full byte were + * zeros. If we don't check them, they become a + * subliminal channel. + */ + if (target && target[tarindex] != 0) + return (-1); + } + } else { + /* + * We ended by seeing the end of the string. Make sure we + * have no partial bytes lying around. + */ + if (state != 0) + return (-1); + } + + return (tarindex); +} diff --git a/opal/mca/hwloc/hwloc1110/hwloc/src/bind.c b/opal/mca/hwloc/hwloc1110/hwloc/src/bind.c new file mode 100644 index 0000000000..e2b5a063e4 --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/src/bind.c @@ -0,0 +1,781 @@ +/* + * Copyright © 2009 CNRS + * Copyright © 2009-2011 inria. All rights reserved. + * Copyright © 2009-2010, 2012 Université Bordeaux + * Copyright © 2011 Cisco Systems, Inc. All rights reserved. + * See COPYING in top-level directory. + */ + +#include +#include +#include +#include +#ifdef HAVE_SYS_MMAN_H +# include +#endif +/* is only needed if we don't have posix_memalign() */ +#if defined(hwloc_getpagesize) && !defined(HAVE_POSIX_MEMALIGN) && defined(HAVE_MEMALIGN) && defined(HAVE_MALLOC_H) +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include + +/* TODO: HWLOC_GNU_SYS, HWLOC_IRIX_SYS, + * + * IRIX: see MP_MUSTRUN / _DSM_MUSTRUN, pthread_setrunon_np, /hw, procss_cpulink, numa_create + * + * We could use glibc's sched_setaffinity generically when it is available + * + * Darwin and OpenBSD don't seem to have binding facilities. + */ + +static hwloc_const_bitmap_t +hwloc_fix_cpubind(hwloc_topology_t topology, hwloc_const_bitmap_t set) +{ + hwloc_const_bitmap_t topology_set = hwloc_topology_get_topology_cpuset(topology); + hwloc_const_bitmap_t complete_set = hwloc_topology_get_complete_cpuset(topology); + + if (!topology_set) { + /* The topology is composed of several systems, the cpuset is ambiguous. */ + errno = EXDEV; + return NULL; + } + + if (hwloc_bitmap_iszero(set)) { + errno = EINVAL; + return NULL; + } + + if (!hwloc_bitmap_isincluded(set, complete_set)) { + errno = EINVAL; + return NULL; + } + + if (hwloc_bitmap_isincluded(topology_set, set)) + set = complete_set; + + return set; +} + +int +hwloc_set_cpubind(hwloc_topology_t topology, hwloc_const_bitmap_t set, int flags) +{ + set = hwloc_fix_cpubind(topology, set); + if (!set) + return -1; + + if (flags & HWLOC_CPUBIND_PROCESS) { + if (topology->binding_hooks.set_thisproc_cpubind) + return topology->binding_hooks.set_thisproc_cpubind(topology, set, flags); + } else if (flags & HWLOC_CPUBIND_THREAD) { + if (topology->binding_hooks.set_thisthread_cpubind) + return topology->binding_hooks.set_thisthread_cpubind(topology, set, flags); + } else { + if (topology->binding_hooks.set_thisproc_cpubind) + return topology->binding_hooks.set_thisproc_cpubind(topology, set, flags); + else if (topology->binding_hooks.set_thisthread_cpubind) + return topology->binding_hooks.set_thisthread_cpubind(topology, set, flags); + } + + errno = ENOSYS; + return -1; +} + +int +hwloc_get_cpubind(hwloc_topology_t topology, hwloc_bitmap_t set, int flags) +{ + if (flags & HWLOC_CPUBIND_PROCESS) { + if (topology->binding_hooks.get_thisproc_cpubind) + return topology->binding_hooks.get_thisproc_cpubind(topology, set, flags); + } else if (flags & HWLOC_CPUBIND_THREAD) { + if (topology->binding_hooks.get_thisthread_cpubind) + return topology->binding_hooks.get_thisthread_cpubind(topology, set, flags); + } else { + if (topology->binding_hooks.get_thisproc_cpubind) + return topology->binding_hooks.get_thisproc_cpubind(topology, set, flags); + else if (topology->binding_hooks.get_thisthread_cpubind) + return topology->binding_hooks.get_thisthread_cpubind(topology, set, flags); + } + + errno = ENOSYS; + return -1; +} + +int +hwloc_set_proc_cpubind(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_const_bitmap_t set, int flags) +{ + set = hwloc_fix_cpubind(topology, set); + if (!set) + return -1; + + if (topology->binding_hooks.set_proc_cpubind) + return topology->binding_hooks.set_proc_cpubind(topology, pid, set, flags); + + errno = ENOSYS; + return -1; +} + +int +hwloc_get_proc_cpubind(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_bitmap_t set, int flags) +{ + if (topology->binding_hooks.get_proc_cpubind) + return topology->binding_hooks.get_proc_cpubind(topology, pid, set, flags); + + errno = ENOSYS; + return -1; +} + +#ifdef hwloc_thread_t +int +hwloc_set_thread_cpubind(hwloc_topology_t topology, hwloc_thread_t tid, hwloc_const_bitmap_t set, int flags) +{ + set = hwloc_fix_cpubind(topology, set); + if (!set) + return -1; + + if (topology->binding_hooks.set_thread_cpubind) + return topology->binding_hooks.set_thread_cpubind(topology, tid, set, flags); + + errno = ENOSYS; + return -1; +} + +int +hwloc_get_thread_cpubind(hwloc_topology_t topology, hwloc_thread_t tid, hwloc_bitmap_t set, int flags) +{ + if (topology->binding_hooks.get_thread_cpubind) + return topology->binding_hooks.get_thread_cpubind(topology, tid, set, flags); + + errno = ENOSYS; + return -1; +} +#endif + +int +hwloc_get_last_cpu_location(hwloc_topology_t topology, hwloc_bitmap_t set, int flags) +{ + if (flags & HWLOC_CPUBIND_PROCESS) { + if (topology->binding_hooks.get_thisproc_last_cpu_location) + return topology->binding_hooks.get_thisproc_last_cpu_location(topology, set, flags); + } else if (flags & HWLOC_CPUBIND_THREAD) { + if (topology->binding_hooks.get_thisthread_last_cpu_location) + return topology->binding_hooks.get_thisthread_last_cpu_location(topology, set, flags); + } else { + if (topology->binding_hooks.get_thisproc_last_cpu_location) + return topology->binding_hooks.get_thisproc_last_cpu_location(topology, set, flags); + else if (topology->binding_hooks.get_thisthread_last_cpu_location) + return topology->binding_hooks.get_thisthread_last_cpu_location(topology, set, flags); + } + + errno = ENOSYS; + return -1; +} + +int +hwloc_get_proc_last_cpu_location(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_bitmap_t set, int flags) +{ + if (topology->binding_hooks.get_proc_last_cpu_location) + return topology->binding_hooks.get_proc_last_cpu_location(topology, pid, set, flags); + + errno = ENOSYS; + return -1; +} + +static hwloc_const_nodeset_t +hwloc_fix_membind(hwloc_topology_t topology, hwloc_const_nodeset_t nodeset) +{ + hwloc_const_bitmap_t topology_nodeset = hwloc_topology_get_topology_nodeset(topology); + hwloc_const_bitmap_t complete_nodeset = hwloc_topology_get_complete_nodeset(topology); + + if (!hwloc_topology_get_topology_cpuset(topology)) { + /* The topology is composed of several systems, the nodeset is thus + * ambiguous. */ + errno = EXDEV; + return NULL; + } + + if (!complete_nodeset) { + /* There is no NUMA node */ + errno = ENODEV; + return NULL; + } + + if (hwloc_bitmap_iszero(nodeset)) { + errno = EINVAL; + return NULL; + } + + if (!hwloc_bitmap_isincluded(nodeset, complete_nodeset)) { + errno = EINVAL; + return NULL; + } + + if (hwloc_bitmap_isincluded(topology_nodeset, nodeset)) + return complete_nodeset; + + return nodeset; +} + +static int +hwloc_fix_membind_cpuset(hwloc_topology_t topology, hwloc_nodeset_t nodeset, hwloc_const_cpuset_t cpuset) +{ + hwloc_const_bitmap_t topology_set = hwloc_topology_get_topology_cpuset(topology); + hwloc_const_bitmap_t complete_set = hwloc_topology_get_complete_cpuset(topology); + hwloc_const_bitmap_t complete_nodeset = hwloc_topology_get_complete_nodeset(topology); + + if (!topology_set) { + /* The topology is composed of several systems, the cpuset is thus + * ambiguous. */ + errno = EXDEV; + return -1; + } + + if (!complete_nodeset) { + /* There is no NUMA node */ + errno = ENODEV; + return -1; + } + + if (hwloc_bitmap_iszero(cpuset)) { + errno = EINVAL; + return -1; + } + + if (!hwloc_bitmap_isincluded(cpuset, complete_set)) { + errno = EINVAL; + return -1; + } + + if (hwloc_bitmap_isincluded(topology_set, cpuset)) { + hwloc_bitmap_copy(nodeset, complete_nodeset); + return 0; + } + + hwloc_cpuset_to_nodeset(topology, cpuset, nodeset); + return 0; +} + +int +hwloc_set_membind_nodeset(hwloc_topology_t topology, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags) +{ + nodeset = hwloc_fix_membind(topology, nodeset); + if (!nodeset) + return -1; + + if (flags & HWLOC_MEMBIND_PROCESS) { + if (topology->binding_hooks.set_thisproc_membind) + return topology->binding_hooks.set_thisproc_membind(topology, nodeset, policy, flags); + } else if (flags & HWLOC_MEMBIND_THREAD) { + if (topology->binding_hooks.set_thisthread_membind) + return topology->binding_hooks.set_thisthread_membind(topology, nodeset, policy, flags); + } else { + if (topology->binding_hooks.set_thisproc_membind) + return topology->binding_hooks.set_thisproc_membind(topology, nodeset, policy, flags); + else if (topology->binding_hooks.set_thisthread_membind) + return topology->binding_hooks.set_thisthread_membind(topology, nodeset, policy, flags); + } + + errno = ENOSYS; + return -1; +} + +int +hwloc_set_membind(hwloc_topology_t topology, hwloc_const_cpuset_t set, hwloc_membind_policy_t policy, int flags) +{ + hwloc_nodeset_t nodeset = hwloc_bitmap_alloc(); + int ret; + + if (hwloc_fix_membind_cpuset(topology, nodeset, set)) + ret = -1; + else + ret = hwloc_set_membind_nodeset(topology, nodeset, policy, flags); + + hwloc_bitmap_free(nodeset); + return ret; +} + +int +hwloc_get_membind_nodeset(hwloc_topology_t topology, hwloc_nodeset_t nodeset, hwloc_membind_policy_t * policy, int flags) +{ + if (flags & HWLOC_MEMBIND_PROCESS) { + if (topology->binding_hooks.get_thisproc_membind) + return topology->binding_hooks.get_thisproc_membind(topology, nodeset, policy, flags); + } else if (flags & HWLOC_MEMBIND_THREAD) { + if (topology->binding_hooks.get_thisthread_membind) + return topology->binding_hooks.get_thisthread_membind(topology, nodeset, policy, flags); + } else { + if (topology->binding_hooks.get_thisproc_membind) + return topology->binding_hooks.get_thisproc_membind(topology, nodeset, policy, flags); + else if (topology->binding_hooks.get_thisthread_membind) + return topology->binding_hooks.get_thisthread_membind(topology, nodeset, policy, flags); + } + + errno = ENOSYS; + return -1; +} + +int +hwloc_get_membind(hwloc_topology_t topology, hwloc_cpuset_t set, hwloc_membind_policy_t * policy, int flags) +{ + hwloc_nodeset_t nodeset; + int ret; + + nodeset = hwloc_bitmap_alloc(); + ret = hwloc_get_membind_nodeset(topology, nodeset, policy, flags); + + if (!ret) + hwloc_cpuset_from_nodeset(topology, set, nodeset); + + hwloc_bitmap_free(nodeset); + return ret; +} + +int +hwloc_set_proc_membind_nodeset(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags) +{ + nodeset = hwloc_fix_membind(topology, nodeset); + if (!nodeset) + return -1; + + if (topology->binding_hooks.set_proc_membind) + return topology->binding_hooks.set_proc_membind(topology, pid, nodeset, policy, flags); + + errno = ENOSYS; + return -1; +} + + +int +hwloc_set_proc_membind(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_const_cpuset_t set, hwloc_membind_policy_t policy, int flags) +{ + hwloc_nodeset_t nodeset = hwloc_bitmap_alloc(); + int ret; + + if (hwloc_fix_membind_cpuset(topology, nodeset, set)) + ret = -1; + else + ret = hwloc_set_proc_membind_nodeset(topology, pid, nodeset, policy, flags); + + hwloc_bitmap_free(nodeset); + return ret; +} + +int +hwloc_get_proc_membind_nodeset(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_nodeset_t nodeset, hwloc_membind_policy_t * policy, int flags) +{ + if (topology->binding_hooks.get_proc_membind) + return topology->binding_hooks.get_proc_membind(topology, pid, nodeset, policy, flags); + + errno = ENOSYS; + return -1; +} + +int +hwloc_get_proc_membind(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_cpuset_t set, hwloc_membind_policy_t * policy, int flags) +{ + hwloc_nodeset_t nodeset; + int ret; + + nodeset = hwloc_bitmap_alloc(); + ret = hwloc_get_proc_membind_nodeset(topology, pid, nodeset, policy, flags); + + if (!ret) + hwloc_cpuset_from_nodeset(topology, set, nodeset); + + hwloc_bitmap_free(nodeset); + return ret; +} + +int +hwloc_set_area_membind_nodeset(hwloc_topology_t topology, const void *addr, size_t len, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags) +{ + nodeset = hwloc_fix_membind(topology, nodeset); + if (!nodeset) + return -1; + + if (topology->binding_hooks.set_area_membind) + return topology->binding_hooks.set_area_membind(topology, addr, len, nodeset, policy, flags); + + errno = ENOSYS; + return -1; +} + +int +hwloc_set_area_membind(hwloc_topology_t topology, const void *addr, size_t len, hwloc_const_cpuset_t set, hwloc_membind_policy_t policy, int flags) +{ + hwloc_nodeset_t nodeset = hwloc_bitmap_alloc(); + int ret; + + if (hwloc_fix_membind_cpuset(topology, nodeset, set)) + ret = -1; + else + ret = hwloc_set_area_membind_nodeset(topology, addr, len, nodeset, policy, flags); + + hwloc_bitmap_free(nodeset); + return ret; +} + +int +hwloc_get_area_membind_nodeset(hwloc_topology_t topology, const void *addr, size_t len, hwloc_nodeset_t nodeset, hwloc_membind_policy_t * policy, int flags) +{ + if (topology->binding_hooks.get_area_membind) + return topology->binding_hooks.get_area_membind(topology, addr, len, nodeset, policy, flags); + + errno = ENOSYS; + return -1; +} + +int +hwloc_get_area_membind(hwloc_topology_t topology, const void *addr, size_t len, hwloc_cpuset_t set, hwloc_membind_policy_t * policy, int flags) +{ + hwloc_nodeset_t nodeset; + int ret; + + nodeset = hwloc_bitmap_alloc(); + ret = hwloc_get_area_membind_nodeset(topology, addr, len, nodeset, policy, flags); + + if (!ret) + hwloc_cpuset_from_nodeset(topology, set, nodeset); + + hwloc_bitmap_free(nodeset); + return ret; +} + +void * +hwloc_alloc_heap(hwloc_topology_t topology __hwloc_attribute_unused, size_t len) +{ + void *p; +#if defined(hwloc_getpagesize) && defined(HAVE_POSIX_MEMALIGN) + errno = posix_memalign(&p, hwloc_getpagesize(), len); + if (errno) + p = NULL; +#elif defined(hwloc_getpagesize) && defined(HAVE_MEMALIGN) + p = memalign(hwloc_getpagesize(), len); +#else + p = malloc(len); +#endif + return p; +} + +#ifdef MAP_ANONYMOUS +void * +hwloc_alloc_mmap(hwloc_topology_t topology __hwloc_attribute_unused, size_t len) +{ + return mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); +} +#endif + +int +hwloc_free_heap(hwloc_topology_t topology __hwloc_attribute_unused, void *addr, size_t len __hwloc_attribute_unused) +{ + free(addr); + return 0; +} + +#ifdef MAP_ANONYMOUS +int +hwloc_free_mmap(hwloc_topology_t topology __hwloc_attribute_unused, void *addr, size_t len) +{ + if (!addr) + return 0; + return munmap(addr, len); +} +#endif + +void * +hwloc_alloc(hwloc_topology_t topology, size_t len) +{ + if (topology->binding_hooks.alloc) + return topology->binding_hooks.alloc(topology, len); + return hwloc_alloc_heap(topology, len); +} + +void * +hwloc_alloc_membind_nodeset(hwloc_topology_t topology, size_t len, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags) +{ + void *p; + nodeset = hwloc_fix_membind(topology, nodeset); + if (!nodeset) + goto fallback; + if (flags & HWLOC_MEMBIND_MIGRATE) { + errno = EINVAL; + goto fallback; + } + + if (topology->binding_hooks.alloc_membind) + return topology->binding_hooks.alloc_membind(topology, len, nodeset, policy, flags); + else if (topology->binding_hooks.set_area_membind) { + p = hwloc_alloc(topology, len); + if (!p) + return NULL; + if (topology->binding_hooks.set_area_membind(topology, p, len, nodeset, policy, flags) && flags & HWLOC_MEMBIND_STRICT) { + int error = errno; + free(p); + errno = error; + return NULL; + } + return p; + } else { + errno = ENOSYS; + } + +fallback: + if (flags & HWLOC_MEMBIND_STRICT) + /* Report error */ + return NULL; + /* Never mind, allocate anyway */ + return hwloc_alloc(topology, len); +} + +void * +hwloc_alloc_membind(hwloc_topology_t topology, size_t len, hwloc_const_cpuset_t set, hwloc_membind_policy_t policy, int flags) +{ + hwloc_nodeset_t nodeset = hwloc_bitmap_alloc(); + void *ret; + + if (hwloc_fix_membind_cpuset(topology, nodeset, set)) { + if (flags & HWLOC_MEMBIND_STRICT) + ret = NULL; + else + ret = hwloc_alloc(topology, len); + } else + ret = hwloc_alloc_membind_nodeset(topology, len, nodeset, policy, flags); + + hwloc_bitmap_free(nodeset); + return ret; +} + +int +hwloc_free(hwloc_topology_t topology, void *addr, size_t len) +{ + if (topology->binding_hooks.free_membind) + return topology->binding_hooks.free_membind(topology, addr, len); + return hwloc_free_heap(topology, addr, len); +} + +/* + * Empty binding hooks always returning success + */ + +static int dontset_return_complete_cpuset(hwloc_topology_t topology, hwloc_cpuset_t set) +{ + hwloc_const_cpuset_t cpuset = hwloc_topology_get_complete_cpuset(topology); + if (cpuset) { + hwloc_bitmap_copy(set, hwloc_topology_get_complete_cpuset(topology)); + return 0; + } else + return -1; +} + +static int dontset_thisthread_cpubind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_const_bitmap_t set __hwloc_attribute_unused, int flags __hwloc_attribute_unused) +{ + return 0; +} +static int dontget_thisthread_cpubind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_bitmap_t set, int flags __hwloc_attribute_unused) +{ + return dontset_return_complete_cpuset(topology, set); +} +static int dontset_thisproc_cpubind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_const_bitmap_t set __hwloc_attribute_unused, int flags __hwloc_attribute_unused) +{ + return 0; +} +static int dontget_thisproc_cpubind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_bitmap_t set, int flags __hwloc_attribute_unused) +{ + return dontset_return_complete_cpuset(topology, set); +} +static int dontset_proc_cpubind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_pid_t pid __hwloc_attribute_unused, hwloc_const_bitmap_t set __hwloc_attribute_unused, int flags __hwloc_attribute_unused) +{ + return 0; +} +static int dontget_proc_cpubind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_pid_t pid __hwloc_attribute_unused, hwloc_bitmap_t cpuset, int flags __hwloc_attribute_unused) +{ + return dontset_return_complete_cpuset(topology, cpuset); +} +#ifdef hwloc_thread_t +static int dontset_thread_cpubind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_thread_t tid __hwloc_attribute_unused, hwloc_const_bitmap_t set __hwloc_attribute_unused, int flags __hwloc_attribute_unused) +{ + return 0; +} +static int dontget_thread_cpubind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_thread_t tid __hwloc_attribute_unused, hwloc_bitmap_t cpuset, int flags __hwloc_attribute_unused) +{ + return dontset_return_complete_cpuset(topology, cpuset); +} +#endif + +static int dontset_return_complete_nodeset(hwloc_topology_t topology, hwloc_nodeset_t set, hwloc_membind_policy_t *policy) +{ + hwloc_const_nodeset_t nodeset = hwloc_topology_get_complete_nodeset(topology); + if (nodeset) { + hwloc_bitmap_copy(set, hwloc_topology_get_complete_nodeset(topology)); + *policy = HWLOC_MEMBIND_DEFAULT; + return 0; + } else + return -1; +} + +static int dontset_thisproc_membind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_const_bitmap_t set __hwloc_attribute_unused, hwloc_membind_policy_t policy __hwloc_attribute_unused, int flags __hwloc_attribute_unused) +{ + return 0; +} +static int dontget_thisproc_membind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_bitmap_t set, hwloc_membind_policy_t * policy, int flags __hwloc_attribute_unused) +{ + return dontset_return_complete_nodeset(topology, set, policy); +} + +static int dontset_thisthread_membind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_const_bitmap_t set __hwloc_attribute_unused, hwloc_membind_policy_t policy __hwloc_attribute_unused, int flags __hwloc_attribute_unused) +{ + return 0; +} +static int dontget_thisthread_membind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_bitmap_t set, hwloc_membind_policy_t * policy, int flags __hwloc_attribute_unused) +{ + return dontset_return_complete_nodeset(topology, set, policy); +} + +static int dontset_proc_membind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_pid_t pid __hwloc_attribute_unused, hwloc_const_bitmap_t set __hwloc_attribute_unused, hwloc_membind_policy_t policy __hwloc_attribute_unused, int flags __hwloc_attribute_unused) +{ + return 0; +} +static int dontget_proc_membind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_pid_t pid __hwloc_attribute_unused, hwloc_bitmap_t set, hwloc_membind_policy_t * policy, int flags __hwloc_attribute_unused) +{ + return dontset_return_complete_nodeset(topology, set, policy); +} + +static int dontset_area_membind(hwloc_topology_t topology __hwloc_attribute_unused, const void *addr __hwloc_attribute_unused, size_t size __hwloc_attribute_unused, hwloc_const_bitmap_t set __hwloc_attribute_unused, hwloc_membind_policy_t policy __hwloc_attribute_unused, int flags __hwloc_attribute_unused) +{ + return 0; +} +static int dontget_area_membind(hwloc_topology_t topology __hwloc_attribute_unused, const void *addr __hwloc_attribute_unused, size_t size __hwloc_attribute_unused, hwloc_bitmap_t set, hwloc_membind_policy_t * policy, int flags __hwloc_attribute_unused) +{ + return dontset_return_complete_nodeset(topology, set, policy); +} + +static void * dontalloc_membind(hwloc_topology_t topology __hwloc_attribute_unused, size_t size __hwloc_attribute_unused, hwloc_const_bitmap_t set __hwloc_attribute_unused, hwloc_membind_policy_t policy __hwloc_attribute_unused, int flags __hwloc_attribute_unused) +{ + return malloc(size); +} +static int dontfree_membind(hwloc_topology_t topology __hwloc_attribute_unused, void *addr __hwloc_attribute_unused, size_t size __hwloc_attribute_unused) +{ + free(addr); + return 0; +} + +static void hwloc_set_dummy_hooks(struct hwloc_binding_hooks *hooks, + struct hwloc_topology_support *support __hwloc_attribute_unused) +{ + hooks->set_thisproc_cpubind = dontset_thisproc_cpubind; + hooks->get_thisproc_cpubind = dontget_thisproc_cpubind; + hooks->set_thisthread_cpubind = dontset_thisthread_cpubind; + hooks->get_thisthread_cpubind = dontget_thisthread_cpubind; + hooks->set_proc_cpubind = dontset_proc_cpubind; + hooks->get_proc_cpubind = dontget_proc_cpubind; +#ifdef hwloc_thread_t + hooks->set_thread_cpubind = dontset_thread_cpubind; + hooks->get_thread_cpubind = dontget_thread_cpubind; +#endif + hooks->get_thisproc_last_cpu_location = dontget_thisproc_cpubind; /* cpubind instead of last_cpu_location is ok */ + hooks->get_thisthread_last_cpu_location = dontget_thisthread_cpubind; /* cpubind instead of last_cpu_location is ok */ + hooks->get_proc_last_cpu_location = dontget_proc_cpubind; /* cpubind instead of last_cpu_location is ok */ + /* TODO: get_thread_last_cpu_location */ + hooks->set_thisproc_membind = dontset_thisproc_membind; + hooks->get_thisproc_membind = dontget_thisproc_membind; + hooks->set_thisthread_membind = dontset_thisthread_membind; + hooks->get_thisthread_membind = dontget_thisthread_membind; + hooks->set_proc_membind = dontset_proc_membind; + hooks->get_proc_membind = dontget_proc_membind; + hooks->set_area_membind = dontset_area_membind; + hooks->get_area_membind = dontget_area_membind; + hooks->alloc_membind = dontalloc_membind; + hooks->free_membind = dontfree_membind; +} + +void +hwloc_set_native_binding_hooks(struct hwloc_binding_hooks *hooks, struct hwloc_topology_support *support) +{ +# ifdef HWLOC_LINUX_SYS + hwloc_set_linuxfs_hooks(hooks, support); +# endif /* HWLOC_LINUX_SYS */ + +# ifdef HWLOC_BGQ_SYS + hwloc_set_bgq_hooks(hooks, support); +# endif /* HWLOC_BGQ_SYS */ + +# ifdef HWLOC_AIX_SYS + hwloc_set_aix_hooks(hooks, support); +# endif /* HWLOC_AIX_SYS */ + +# ifdef HWLOC_OSF_SYS + hwloc_set_osf_hooks(hooks, support); +# endif /* HWLOC_OSF_SYS */ + +# ifdef HWLOC_SOLARIS_SYS + hwloc_set_solaris_hooks(hooks, support); +# endif /* HWLOC_SOLARIS_SYS */ + +# ifdef HWLOC_WIN_SYS + hwloc_set_windows_hooks(hooks, support); +# endif /* HWLOC_WIN_SYS */ + +# ifdef HWLOC_DARWIN_SYS + hwloc_set_darwin_hooks(hooks, support); +# endif /* HWLOC_DARWIN_SYS */ + +# ifdef HWLOC_FREEBSD_SYS + hwloc_set_freebsd_hooks(hooks, support); +# endif /* HWLOC_FREEBSD_SYS */ + +# ifdef HWLOC_NETBSD_SYS + hwloc_set_netbsd_hooks(hooks, support); +# endif /* HWLOC_NETBSD_SYS */ + +# ifdef HWLOC_HPUX_SYS + hwloc_set_hpux_hooks(hooks, support); +# endif /* HWLOC_HPUX_SYS */ +} + +/* If the represented system is actually not this system, use dummy binding hooks. */ +void +hwloc_set_binding_hooks(struct hwloc_topology *topology) +{ + if (topology->is_thissystem) { + hwloc_set_native_binding_hooks(&topology->binding_hooks, &topology->support); + /* every hook not set above will return ENOSYS */ + } else { + /* not this system, use dummy binding hooks that do nothing (but don't return ENOSYS) */ + hwloc_set_dummy_hooks(&topology->binding_hooks, &topology->support); + } + + /* if not is_thissystem, set_cpubind is fake + * and get_cpubind returns the whole system cpuset, + * so don't report that set/get_cpubind as supported + */ + if (topology->is_thissystem) { +#define DO(which,kind) \ + if (topology->binding_hooks.kind) \ + topology->support.which##bind->kind = 1; + DO(cpu,set_thisproc_cpubind); + DO(cpu,get_thisproc_cpubind); + DO(cpu,set_proc_cpubind); + DO(cpu,get_proc_cpubind); + DO(cpu,set_thisthread_cpubind); + DO(cpu,get_thisthread_cpubind); +#ifdef hwloc_thread_t + DO(cpu,set_thread_cpubind); + DO(cpu,get_thread_cpubind); +#endif + DO(cpu,get_thisproc_last_cpu_location); + DO(cpu,get_proc_last_cpu_location); + DO(cpu,get_thisthread_last_cpu_location); + DO(mem,set_thisproc_membind); + DO(mem,get_thisproc_membind); + DO(mem,set_thisthread_membind); + DO(mem,get_thisthread_membind); + DO(mem,set_proc_membind); + DO(mem,get_proc_membind); + DO(mem,set_area_membind); + DO(mem,get_area_membind); + DO(mem,alloc_membind); + } +} diff --git a/opal/mca/hwloc/hwloc1110/hwloc/src/bitmap.c b/opal/mca/hwloc/hwloc1110/hwloc/src/bitmap.c new file mode 100644 index 0000000000..1e78a96bf3 --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/src/bitmap.c @@ -0,0 +1,1485 @@ +/* + * Copyright © 2009 CNRS + * Copyright © 2009-2015 Inria. All rights reserved. + * Copyright © 2009-2011 Université Bordeaux + * Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved. + * See COPYING in top-level directory. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* TODO + * - have a way to change the initial allocation size + * - preallocate inside the bitmap structure (so that the whole structure is a cacheline for instance) + * and allocate a dedicated array only later when reallocating larger + */ + +/* magic number */ +#define HWLOC_BITMAP_MAGIC 0x20091007 + +/* actual opaque type internals */ +struct hwloc_bitmap_s { + unsigned ulongs_count; /* how many ulong bitmasks are valid, >= 1 */ + unsigned ulongs_allocated; /* how many ulong bitmasks are allocated, >= ulongs_count */ + unsigned long *ulongs; + int infinite; /* set to 1 if all bits beyond ulongs are set */ +#ifdef HWLOC_DEBUG + int magic; +#endif +}; + +/* overzealous check in debug-mode, not as powerful as valgrind but still useful */ +#ifdef HWLOC_DEBUG +#define HWLOC__BITMAP_CHECK(set) do { \ + assert((set)->magic == HWLOC_BITMAP_MAGIC); \ + assert((set)->ulongs_count >= 1); \ + assert((set)->ulongs_allocated >= (set)->ulongs_count); \ +} while (0) +#else +#define HWLOC__BITMAP_CHECK(set) +#endif + +/* extract a subset from a set using an index or a cpu */ +#define HWLOC_SUBBITMAP_INDEX(cpu) ((cpu)/(HWLOC_BITS_PER_LONG)) +#define HWLOC_SUBBITMAP_CPU_ULBIT(cpu) ((cpu)%(HWLOC_BITS_PER_LONG)) +/* Read from a bitmap ulong without knowing whether x is valid. + * Writers should make sure that x is valid and modify set->ulongs[x] directly. + */ +#define HWLOC_SUBBITMAP_READULONG(set,x) ((x) < (set)->ulongs_count ? (set)->ulongs[x] : (set)->infinite ? HWLOC_SUBBITMAP_FULL : HWLOC_SUBBITMAP_ZERO) + +/* predefined subset values */ +#define HWLOC_SUBBITMAP_ZERO 0UL +#define HWLOC_SUBBITMAP_FULL (~0UL) +#define HWLOC_SUBBITMAP_ULBIT(bit) (1UL<<(bit)) +#define HWLOC_SUBBITMAP_CPU(cpu) HWLOC_SUBBITMAP_ULBIT(HWLOC_SUBBITMAP_CPU_ULBIT(cpu)) +#define HWLOC_SUBBITMAP_ULBIT_TO(bit) (HWLOC_SUBBITMAP_FULL>>(HWLOC_BITS_PER_LONG-1-(bit))) +#define HWLOC_SUBBITMAP_ULBIT_FROM(bit) (HWLOC_SUBBITMAP_FULL<<(bit)) +#define HWLOC_SUBBITMAP_ULBIT_FROMTO(begin,end) (HWLOC_SUBBITMAP_ULBIT_TO(end) & HWLOC_SUBBITMAP_ULBIT_FROM(begin)) + +struct hwloc_bitmap_s * hwloc_bitmap_alloc(void) +{ + struct hwloc_bitmap_s * set; + + set = malloc(sizeof(struct hwloc_bitmap_s)); + if (!set) + return NULL; + + set->ulongs_count = 1; + set->ulongs_allocated = 64/sizeof(unsigned long); + set->ulongs = malloc(64); + if (!set->ulongs) { + free(set); + return NULL; + } + + set->ulongs[0] = HWLOC_SUBBITMAP_ZERO; + set->infinite = 0; +#ifdef HWLOC_DEBUG + set->magic = HWLOC_BITMAP_MAGIC; +#endif + return set; +} + +struct hwloc_bitmap_s * hwloc_bitmap_alloc_full(void) +{ + struct hwloc_bitmap_s * set = hwloc_bitmap_alloc(); + if (set) { + set->infinite = 1; + set->ulongs[0] = HWLOC_SUBBITMAP_FULL; + } + return set; +} + +void hwloc_bitmap_free(struct hwloc_bitmap_s * set) +{ + if (!set) + return; + + HWLOC__BITMAP_CHECK(set); +#ifdef HWLOC_DEBUG + set->magic = 0; +#endif + + free(set->ulongs); + free(set); +} + +/* enlarge until it contains at least needed_count ulongs. + */ +static void +hwloc_bitmap_enlarge_by_ulongs(struct hwloc_bitmap_s * set, unsigned needed_count) +{ + unsigned tmp = 1 << hwloc_flsl((unsigned long) needed_count - 1); + if (tmp > set->ulongs_allocated) { + set->ulongs = realloc(set->ulongs, tmp * sizeof(unsigned long)); + assert(set->ulongs); + set->ulongs_allocated = tmp; + } +} + +/* enlarge until it contains at least needed_count ulongs, + * and update new ulongs according to the infinite field. + */ +static void +hwloc_bitmap_realloc_by_ulongs(struct hwloc_bitmap_s * set, unsigned needed_count) +{ + unsigned i; + + HWLOC__BITMAP_CHECK(set); + + if (needed_count <= set->ulongs_count) + return; + + /* realloc larger if needed */ + hwloc_bitmap_enlarge_by_ulongs(set, needed_count); + + /* fill the newly allocated subset depending on the infinite flag */ + for(i=set->ulongs_count; iulongs[i] = set->infinite ? HWLOC_SUBBITMAP_FULL : HWLOC_SUBBITMAP_ZERO; + set->ulongs_count = needed_count; +} + +/* realloc until it contains at least cpu+1 bits */ +#define hwloc_bitmap_realloc_by_cpu_index(set, cpu) hwloc_bitmap_realloc_by_ulongs(set, ((cpu)/HWLOC_BITS_PER_LONG)+1) + +/* reset a bitmap to exactely the needed size. + * the caller must reinitialize all ulongs and the infinite flag later. + */ +static void +hwloc_bitmap_reset_by_ulongs(struct hwloc_bitmap_s * set, unsigned needed_count) +{ + hwloc_bitmap_enlarge_by_ulongs(set, needed_count); + set->ulongs_count = needed_count; +} + +/* reset until it contains exactly cpu+1 bits (roundup to a ulong). + * the caller must reinitialize all ulongs and the infinite flag later. + */ +#define hwloc_bitmap_reset_by_cpu_index(set, cpu) hwloc_bitmap_reset_by_ulongs(set, ((cpu)/HWLOC_BITS_PER_LONG)+1) + +struct hwloc_bitmap_s * hwloc_bitmap_dup(const struct hwloc_bitmap_s * old) +{ + struct hwloc_bitmap_s * new; + + if (!old) + return NULL; + + HWLOC__BITMAP_CHECK(old); + + new = malloc(sizeof(struct hwloc_bitmap_s)); + if (!new) + return NULL; + + new->ulongs = malloc(old->ulongs_allocated * sizeof(unsigned long)); + if (!new->ulongs) { + free(new); + return NULL; + } + new->ulongs_allocated = old->ulongs_allocated; + new->ulongs_count = old->ulongs_count; + memcpy(new->ulongs, old->ulongs, new->ulongs_count * sizeof(unsigned long)); + new->infinite = old->infinite; +#ifdef HWLOC_DEBUG + new->magic = HWLOC_BITMAP_MAGIC; +#endif + return new; +} + +void hwloc_bitmap_copy(struct hwloc_bitmap_s * dst, const struct hwloc_bitmap_s * src) +{ + HWLOC__BITMAP_CHECK(dst); + HWLOC__BITMAP_CHECK(src); + + hwloc_bitmap_reset_by_ulongs(dst, src->ulongs_count); + + memcpy(dst->ulongs, src->ulongs, src->ulongs_count * sizeof(unsigned long)); + dst->infinite = src->infinite; +} + +/* Strings always use 32bit groups */ +#define HWLOC_PRIxSUBBITMAP "%08lx" +#define HWLOC_BITMAP_SUBSTRING_SIZE 32 +#define HWLOC_BITMAP_SUBSTRING_LENGTH (HWLOC_BITMAP_SUBSTRING_SIZE/4) +#define HWLOC_BITMAP_STRING_PER_LONG (HWLOC_BITS_PER_LONG/HWLOC_BITMAP_SUBSTRING_SIZE) + +int hwloc_bitmap_snprintf(char * __hwloc_restrict buf, size_t buflen, const struct hwloc_bitmap_s * __hwloc_restrict set) +{ + ssize_t size = buflen; + char *tmp = buf; + int res, ret = 0; + int needcomma = 0; + int i; + unsigned long accum = 0; + int accumed = 0; +#if HWLOC_BITS_PER_LONG == HWLOC_BITMAP_SUBSTRING_SIZE + const unsigned long accum_mask = ~0UL; +#else /* HWLOC_BITS_PER_LONG != HWLOC_BITMAP_SUBSTRING_SIZE */ + const unsigned long accum_mask = ((1UL << HWLOC_BITMAP_SUBSTRING_SIZE) - 1) << (HWLOC_BITS_PER_LONG - HWLOC_BITMAP_SUBSTRING_SIZE); +#endif /* HWLOC_BITS_PER_LONG != HWLOC_BITMAP_SUBSTRING_SIZE */ + + HWLOC__BITMAP_CHECK(set); + + /* mark the end in case we do nothing later */ + if (buflen > 0) + tmp[0] = '\0'; + + if (set->infinite) { + res = hwloc_snprintf(tmp, size, "0xf...f"); + needcomma = 1; + if (res < 0) + return -1; + ret += res; + if (res >= size) + res = size>0 ? size - 1 : 0; + tmp += res; + size -= res; + } + + i=set->ulongs_count-1; + + if (set->infinite) { + /* ignore starting FULL since we have 0xf...f already */ + while (i>=0 && set->ulongs[i] == HWLOC_SUBBITMAP_FULL) + i--; + } else { + /* ignore starting ZERO except the last one */ + while (i>=0 && set->ulongs[i] == HWLOC_SUBBITMAP_ZERO) + i--; + } + + while (i>=0 || accumed) { + /* Refill accumulator */ + if (!accumed) { + accum = set->ulongs[i--]; + accumed = HWLOC_BITS_PER_LONG; + } + + if (accum & accum_mask) { + /* print the whole subset if not empty */ + res = hwloc_snprintf(tmp, size, needcomma ? ",0x" HWLOC_PRIxSUBBITMAP : "0x" HWLOC_PRIxSUBBITMAP, + (accum & accum_mask) >> (HWLOC_BITS_PER_LONG - HWLOC_BITMAP_SUBSTRING_SIZE)); + needcomma = 1; + } else if (i == -1 && accumed == HWLOC_BITMAP_SUBSTRING_SIZE) { + /* print a single 0 to mark the last subset */ + res = hwloc_snprintf(tmp, size, needcomma ? ",0x0" : "0x0"); + } else if (needcomma) { + res = hwloc_snprintf(tmp, size, ","); + } else { + res = 0; + } + if (res < 0) + return -1; + ret += res; + +#if HWLOC_BITS_PER_LONG == HWLOC_BITMAP_SUBSTRING_SIZE + accum = 0; + accumed = 0; +#else + accum <<= HWLOC_BITMAP_SUBSTRING_SIZE; + accumed -= HWLOC_BITMAP_SUBSTRING_SIZE; +#endif + + if (res >= size) + res = size>0 ? size - 1 : 0; + + tmp += res; + size -= res; + } + + /* if didn't display anything, display 0x0 */ + if (!ret) { + res = hwloc_snprintf(tmp, size, "0x0"); + if (res < 0) + return -1; + ret += res; + } + + return ret; +} + +int hwloc_bitmap_asprintf(char ** strp, const struct hwloc_bitmap_s * __hwloc_restrict set) +{ + int len; + char *buf; + + HWLOC__BITMAP_CHECK(set); + + len = hwloc_bitmap_snprintf(NULL, 0, set); + buf = malloc(len+1); + *strp = buf; + return hwloc_bitmap_snprintf(buf, len+1, set); +} + +int hwloc_bitmap_sscanf(struct hwloc_bitmap_s *set, const char * __hwloc_restrict string) +{ + const char * current = string; + unsigned long accum = 0; + int count=0; + int infinite = 0; + + /* count how many substrings there are */ + count++; + while ((current = strchr(current+1, ',')) != NULL) + count++; + + current = string; + if (!strncmp("0xf...f", current, 7)) { + current += 7; + if (*current != ',') { + /* special case for infinite/full bitmap */ + hwloc_bitmap_fill(set); + return 0; + } + current++; + infinite = 1; + count--; + } + + hwloc_bitmap_reset_by_ulongs(set, (count + HWLOC_BITMAP_STRING_PER_LONG - 1) / HWLOC_BITMAP_STRING_PER_LONG); + set->infinite = 0; + + while (*current != '\0') { + unsigned long val; + char *next; + val = strtoul(current, &next, 16); + + assert(count > 0); + count--; + + accum |= (val << ((count * HWLOC_BITMAP_SUBSTRING_SIZE) % HWLOC_BITS_PER_LONG)); + if (!(count % HWLOC_BITMAP_STRING_PER_LONG)) { + set->ulongs[count / HWLOC_BITMAP_STRING_PER_LONG] = accum; + accum = 0; + } + + if (*next != ',') { + if (*next || count > 0) + goto failed; + else + break; + } + current = (const char*) next+1; + } + + set->infinite = infinite; /* set at the end, to avoid spurious realloc with filled new ulongs */ + + return 0; + + failed: + /* failure to parse */ + hwloc_bitmap_zero(set); + return -1; +} + +int hwloc_bitmap_list_snprintf(char * __hwloc_restrict buf, size_t buflen, const struct hwloc_bitmap_s * __hwloc_restrict set) +{ + int prev = -1; + hwloc_bitmap_t reverse; + ssize_t size = buflen; + char *tmp = buf; + int res, ret = 0; + int needcomma = 0; + + HWLOC__BITMAP_CHECK(set); + + reverse = hwloc_bitmap_alloc(); /* FIXME: add hwloc_bitmap_alloc_size() + hwloc_bitmap_init_allocated() to avoid malloc? */ + hwloc_bitmap_not(reverse, set); + + /* mark the end in case we do nothing later */ + if (buflen > 0) + tmp[0] = '\0'; + + while (1) { + int begin, end; + + begin = hwloc_bitmap_next(set, prev); + if (begin == -1) + break; + end = hwloc_bitmap_next(reverse, begin); + + if (end == begin+1) { + res = hwloc_snprintf(tmp, size, needcomma ? ",%d" : "%d", begin); + } else if (end == -1) { + res = hwloc_snprintf(tmp, size, needcomma ? ",%d-" : "%d-", begin); + } else { + res = hwloc_snprintf(tmp, size, needcomma ? ",%d-%d" : "%d-%d", begin, end-1); + } + if (res < 0) { + hwloc_bitmap_free(reverse); + return -1; + } + ret += res; + + if (res >= size) + res = size>0 ? size - 1 : 0; + + tmp += res; + size -= res; + needcomma = 1; + + if (end == -1) + break; + else + prev = end - 1; + } + + hwloc_bitmap_free(reverse); + + return ret; +} + +int hwloc_bitmap_list_asprintf(char ** strp, const struct hwloc_bitmap_s * __hwloc_restrict set) +{ + int len; + char *buf; + + HWLOC__BITMAP_CHECK(set); + + len = hwloc_bitmap_list_snprintf(NULL, 0, set); + buf = malloc(len+1); + *strp = buf; + return hwloc_bitmap_list_snprintf(buf, len+1, set); +} + +int hwloc_bitmap_list_sscanf(struct hwloc_bitmap_s *set, const char * __hwloc_restrict string) +{ + const char * current = string; + char *next; + long begin = -1, val; + + hwloc_bitmap_zero(set); + + while (*current != '\0') { + + /* ignore empty ranges */ + while (*current == ',') + current++; + + val = strtoul(current, &next, 0); + /* make sure we got at least one digit */ + if (next == current) + goto failed; + + if (begin != -1) { + /* finishing a range */ + hwloc_bitmap_set_range(set, begin, val); + begin = -1; + + } else if (*next == '-') { + /* starting a new range */ + if (*(next+1) == '\0') { + /* infinite range */ + hwloc_bitmap_set_range(set, val, -1); + break; + } else { + /* normal range */ + begin = val; + } + + } else if (*next == ',' || *next == '\0') { + /* single digit */ + hwloc_bitmap_set(set, val); + } + + if (*next == '\0') + break; + current = next+1; + } + + return 0; + + failed: + /* failure to parse */ + hwloc_bitmap_zero(set); + return -1; +} + +int hwloc_bitmap_taskset_snprintf(char * __hwloc_restrict buf, size_t buflen, const struct hwloc_bitmap_s * __hwloc_restrict set) +{ + ssize_t size = buflen; + char *tmp = buf; + int res, ret = 0; + int started = 0; + int i; + + HWLOC__BITMAP_CHECK(set); + + /* mark the end in case we do nothing later */ + if (buflen > 0) + tmp[0] = '\0'; + + if (set->infinite) { + res = hwloc_snprintf(tmp, size, "0xf...f"); + started = 1; + if (res < 0) + return -1; + ret += res; + if (res >= size) + res = size>0 ? size - 1 : 0; + tmp += res; + size -= res; + } + + i=set->ulongs_count-1; + + if (set->infinite) { + /* ignore starting FULL since we have 0xf...f already */ + while (i>=0 && set->ulongs[i] == HWLOC_SUBBITMAP_FULL) + i--; + } else { + /* ignore starting ZERO except the last one */ + while (i>=1 && set->ulongs[i] == HWLOC_SUBBITMAP_ZERO) + i--; + } + + while (i>=0) { + unsigned long val = set->ulongs[i--]; + if (started) { + /* print the whole subset */ +#if HWLOC_BITS_PER_LONG == 64 + res = hwloc_snprintf(tmp, size, "%016lx", val); +#else + res = hwloc_snprintf(tmp, size, "%08lx", val); +#endif + } else if (val || i == -1) { + res = hwloc_snprintf(tmp, size, "0x%lx", val); + started = 1; + } else { + res = 0; + } + if (res < 0) + return -1; + ret += res; + if (res >= size) + res = size>0 ? size - 1 : 0; + tmp += res; + size -= res; + } + + /* if didn't display anything, display 0x0 */ + if (!ret) { + res = hwloc_snprintf(tmp, size, "0x0"); + if (res < 0) + return -1; + ret += res; + } + + return ret; +} + +int hwloc_bitmap_taskset_asprintf(char ** strp, const struct hwloc_bitmap_s * __hwloc_restrict set) +{ + int len; + char *buf; + + HWLOC__BITMAP_CHECK(set); + + len = hwloc_bitmap_taskset_snprintf(NULL, 0, set); + buf = malloc(len+1); + *strp = buf; + return hwloc_bitmap_taskset_snprintf(buf, len+1, set); +} + +int hwloc_bitmap_taskset_sscanf(struct hwloc_bitmap_s *set, const char * __hwloc_restrict string) +{ + const char * current = string; + int chars; + int count; + int infinite = 0; + + current = string; + if (!strncmp("0xf...f", current, 7)) { + /* infinite bitmap */ + infinite = 1; + current += 7; + if (*current == '\0') { + /* special case for infinite/full bitmap */ + hwloc_bitmap_fill(set); + return 0; + } + } else { + /* finite bitmap */ + if (!strncmp("0x", current, 2)) + current += 2; + if (*current == '\0') { + /* special case for empty bitmap */ + hwloc_bitmap_zero(set); + return 0; + } + } + /* we know there are other characters now */ + + chars = strlen(current); + count = (chars * 4 + HWLOC_BITS_PER_LONG - 1) / HWLOC_BITS_PER_LONG; + + hwloc_bitmap_reset_by_ulongs(set, count); + set->infinite = 0; + + while (*current != '\0') { + int tmpchars; + char ustr[17]; + unsigned long val; + char *next; + + tmpchars = chars % (HWLOC_BITS_PER_LONG/4); + if (!tmpchars) + tmpchars = (HWLOC_BITS_PER_LONG/4); + + memcpy(ustr, current, tmpchars); + ustr[tmpchars] = '\0'; + val = strtoul(ustr, &next, 16); + if (*next != '\0') + goto failed; + + set->ulongs[count-1] = val; + + current += tmpchars; + chars -= tmpchars; + count--; + } + + set->infinite = infinite; /* set at the end, to avoid spurious realloc with filled new ulongs */ + + return 0; + + failed: + /* failure to parse */ + hwloc_bitmap_zero(set); + return -1; +} + +static void hwloc_bitmap__zero(struct hwloc_bitmap_s *set) +{ + unsigned i; + for(i=0; iulongs_count; i++) + set->ulongs[i] = HWLOC_SUBBITMAP_ZERO; + set->infinite = 0; +} + +void hwloc_bitmap_zero(struct hwloc_bitmap_s * set) +{ + HWLOC__BITMAP_CHECK(set); + + hwloc_bitmap_reset_by_ulongs(set, 1); + hwloc_bitmap__zero(set); +} + +static void hwloc_bitmap__fill(struct hwloc_bitmap_s * set) +{ + unsigned i; + for(i=0; iulongs_count; i++) + set->ulongs[i] = HWLOC_SUBBITMAP_FULL; + set->infinite = 1; +} + +void hwloc_bitmap_fill(struct hwloc_bitmap_s * set) +{ + HWLOC__BITMAP_CHECK(set); + + hwloc_bitmap_reset_by_ulongs(set, 1); + hwloc_bitmap__fill(set); +} + +void hwloc_bitmap_from_ulong(struct hwloc_bitmap_s *set, unsigned long mask) +{ + HWLOC__BITMAP_CHECK(set); + + hwloc_bitmap_reset_by_ulongs(set, 1); + set->ulongs[0] = mask; /* there's always at least one ulong allocated */ + set->infinite = 0; +} + +void hwloc_bitmap_from_ith_ulong(struct hwloc_bitmap_s *set, unsigned i, unsigned long mask) +{ + unsigned j; + + HWLOC__BITMAP_CHECK(set); + + hwloc_bitmap_reset_by_ulongs(set, i+1); + set->ulongs[i] = mask; + for(j=0; julongs[j] = HWLOC_SUBBITMAP_ZERO; + set->infinite = 0; +} + +unsigned long hwloc_bitmap_to_ulong(const struct hwloc_bitmap_s *set) +{ + HWLOC__BITMAP_CHECK(set); + + return set->ulongs[0]; /* there's always at least one ulong allocated */ +} + +unsigned long hwloc_bitmap_to_ith_ulong(const struct hwloc_bitmap_s *set, unsigned i) +{ + HWLOC__BITMAP_CHECK(set); + + return HWLOC_SUBBITMAP_READULONG(set, i); +} + +void hwloc_bitmap_only(struct hwloc_bitmap_s * set, unsigned cpu) +{ + unsigned index_ = HWLOC_SUBBITMAP_INDEX(cpu); + + HWLOC__BITMAP_CHECK(set); + + hwloc_bitmap_reset_by_cpu_index(set, cpu); + hwloc_bitmap__zero(set); + set->ulongs[index_] |= HWLOC_SUBBITMAP_CPU(cpu); +} + +void hwloc_bitmap_allbut(struct hwloc_bitmap_s * set, unsigned cpu) +{ + unsigned index_ = HWLOC_SUBBITMAP_INDEX(cpu); + + HWLOC__BITMAP_CHECK(set); + + hwloc_bitmap_reset_by_cpu_index(set, cpu); + hwloc_bitmap__fill(set); + set->ulongs[index_] &= ~HWLOC_SUBBITMAP_CPU(cpu); +} + +void hwloc_bitmap_set(struct hwloc_bitmap_s * set, unsigned cpu) +{ + unsigned index_ = HWLOC_SUBBITMAP_INDEX(cpu); + + HWLOC__BITMAP_CHECK(set); + + /* nothing to do if setting inside the infinite part of the bitmap */ + if (set->infinite && cpu >= set->ulongs_count * HWLOC_BITS_PER_LONG) + return; + + hwloc_bitmap_realloc_by_cpu_index(set, cpu); + set->ulongs[index_] |= HWLOC_SUBBITMAP_CPU(cpu); +} + +void hwloc_bitmap_set_range(struct hwloc_bitmap_s * set, unsigned begincpu, int _endcpu) +{ + unsigned i; + unsigned beginset,endset; + unsigned endcpu = (unsigned) _endcpu; + + HWLOC__BITMAP_CHECK(set); + + if (_endcpu == -1) { + set->infinite = 1; + /* keep endcpu == -1 since this unsigned is actually larger than anything else */ + } + + if (set->infinite) { + /* truncate the range according to the infinite part of the bitmap */ + if (endcpu >= set->ulongs_count * HWLOC_BITS_PER_LONG) + endcpu = set->ulongs_count * HWLOC_BITS_PER_LONG - 1; + if (begincpu >= set->ulongs_count * HWLOC_BITS_PER_LONG) + return; + } + if (endcpu < begincpu) + return; + hwloc_bitmap_realloc_by_cpu_index(set, endcpu); + + beginset = HWLOC_SUBBITMAP_INDEX(begincpu); + endset = HWLOC_SUBBITMAP_INDEX(endcpu); + for(i=beginset+1; iulongs[i] = HWLOC_SUBBITMAP_FULL; + if (beginset == endset) { + set->ulongs[beginset] |= HWLOC_SUBBITMAP_ULBIT_FROMTO(HWLOC_SUBBITMAP_CPU_ULBIT(begincpu), HWLOC_SUBBITMAP_CPU_ULBIT(endcpu)); + } else { + set->ulongs[beginset] |= HWLOC_SUBBITMAP_ULBIT_FROM(HWLOC_SUBBITMAP_CPU_ULBIT(begincpu)); + set->ulongs[endset] |= HWLOC_SUBBITMAP_ULBIT_TO(HWLOC_SUBBITMAP_CPU_ULBIT(endcpu)); + } +} + +void hwloc_bitmap_set_ith_ulong(struct hwloc_bitmap_s *set, unsigned i, unsigned long mask) +{ + HWLOC__BITMAP_CHECK(set); + + hwloc_bitmap_realloc_by_ulongs(set, i+1); + set->ulongs[i] = mask; +} + +void hwloc_bitmap_clr(struct hwloc_bitmap_s * set, unsigned cpu) +{ + unsigned index_ = HWLOC_SUBBITMAP_INDEX(cpu); + + HWLOC__BITMAP_CHECK(set); + + /* nothing to do if clearing inside the infinitely-unset part of the bitmap */ + if (!set->infinite && cpu >= set->ulongs_count * HWLOC_BITS_PER_LONG) + return; + + hwloc_bitmap_realloc_by_cpu_index(set, cpu); + set->ulongs[index_] &= ~HWLOC_SUBBITMAP_CPU(cpu); +} + +void hwloc_bitmap_clr_range(struct hwloc_bitmap_s * set, unsigned begincpu, int _endcpu) +{ + unsigned i; + unsigned beginset,endset; + unsigned endcpu = (unsigned) _endcpu; + + HWLOC__BITMAP_CHECK(set); + + if (_endcpu == -1) { + set->infinite = 0; + /* keep endcpu == -1 since this unsigned is actually larger than anything else */ + } + + if (!set->infinite) { + /* truncate the range according to the infinitely-unset part of the bitmap */ + if (endcpu >= set->ulongs_count * HWLOC_BITS_PER_LONG) + endcpu = set->ulongs_count * HWLOC_BITS_PER_LONG - 1; + if (begincpu >= set->ulongs_count * HWLOC_BITS_PER_LONG) + return; + } + if (endcpu < begincpu) + return; + hwloc_bitmap_realloc_by_cpu_index(set, endcpu); + + beginset = HWLOC_SUBBITMAP_INDEX(begincpu); + endset = HWLOC_SUBBITMAP_INDEX(endcpu); + for(i=beginset+1; iulongs[i] = HWLOC_SUBBITMAP_ZERO; + if (beginset == endset) { + set->ulongs[beginset] &= ~HWLOC_SUBBITMAP_ULBIT_FROMTO(HWLOC_SUBBITMAP_CPU_ULBIT(begincpu), HWLOC_SUBBITMAP_CPU_ULBIT(endcpu)); + } else { + set->ulongs[beginset] &= ~HWLOC_SUBBITMAP_ULBIT_FROM(HWLOC_SUBBITMAP_CPU_ULBIT(begincpu)); + set->ulongs[endset] &= ~HWLOC_SUBBITMAP_ULBIT_TO(HWLOC_SUBBITMAP_CPU_ULBIT(endcpu)); + } +} + +int hwloc_bitmap_isset(const struct hwloc_bitmap_s * set, unsigned cpu) +{ + unsigned index_ = HWLOC_SUBBITMAP_INDEX(cpu); + + HWLOC__BITMAP_CHECK(set); + + return (HWLOC_SUBBITMAP_READULONG(set, index_) & HWLOC_SUBBITMAP_CPU(cpu)) != 0; +} + +int hwloc_bitmap_iszero(const struct hwloc_bitmap_s *set) +{ + unsigned i; + + HWLOC__BITMAP_CHECK(set); + + if (set->infinite) + return 0; + for(i=0; iulongs_count; i++) + if (set->ulongs[i] != HWLOC_SUBBITMAP_ZERO) + return 0; + return 1; +} + +int hwloc_bitmap_isfull(const struct hwloc_bitmap_s *set) +{ + unsigned i; + + HWLOC__BITMAP_CHECK(set); + + if (!set->infinite) + return 0; + for(i=0; iulongs_count; i++) + if (set->ulongs[i] != HWLOC_SUBBITMAP_FULL) + return 0; + return 1; +} + +int hwloc_bitmap_isequal (const struct hwloc_bitmap_s *set1, const struct hwloc_bitmap_s *set2) +{ + unsigned count1 = set1->ulongs_count; + unsigned count2 = set2->ulongs_count; + unsigned min_count = count1 < count2 ? count1 : count2; + unsigned i; + + HWLOC__BITMAP_CHECK(set1); + HWLOC__BITMAP_CHECK(set2); + + for(i=0; iulongs[i] != set2->ulongs[i]) + return 0; + + if (count1 != count2) { + unsigned long w1 = set1->infinite ? HWLOC_SUBBITMAP_FULL : HWLOC_SUBBITMAP_ZERO; + unsigned long w2 = set2->infinite ? HWLOC_SUBBITMAP_FULL : HWLOC_SUBBITMAP_ZERO; + for(i=min_count; iulongs[i] != w2) + return 0; + } + for(i=min_count; iulongs[i] != w1) + return 0; + } + } + + if (set1->infinite != set2->infinite) + return 0; + + return 1; +} + +int hwloc_bitmap_intersects (const struct hwloc_bitmap_s *set1, const struct hwloc_bitmap_s *set2) +{ + unsigned count1 = set1->ulongs_count; + unsigned count2 = set2->ulongs_count; + unsigned min_count = count1 < count2 ? count1 : count2; + unsigned i; + + HWLOC__BITMAP_CHECK(set1); + HWLOC__BITMAP_CHECK(set2); + + for(i=0; iulongs[i] & set2->ulongs[i]) + return 1; + + if (count1 != count2) { + if (set2->infinite) { + for(i=min_count; iulongs_count; i++) + if (set1->ulongs[i]) + return 1; + } + if (set1->infinite) { + for(i=min_count; iulongs_count; i++) + if (set2->ulongs[i]) + return 1; + } + } + + if (set1->infinite && set2->infinite) + return 1; + + return 0; +} + +int hwloc_bitmap_isincluded (const struct hwloc_bitmap_s *sub_set, const struct hwloc_bitmap_s *super_set) +{ + unsigned super_count = super_set->ulongs_count; + unsigned sub_count = sub_set->ulongs_count; + unsigned min_count = super_count < sub_count ? super_count : sub_count; + unsigned i; + + HWLOC__BITMAP_CHECK(sub_set); + HWLOC__BITMAP_CHECK(super_set); + + for(i=0; iulongs[i] != (super_set->ulongs[i] | sub_set->ulongs[i])) + return 0; + + if (super_count != sub_count) { + if (!super_set->infinite) + for(i=min_count; iulongs[i]) + return 0; + if (sub_set->infinite) + for(i=min_count; iulongs[i] != HWLOC_SUBBITMAP_FULL) + return 0; + } + + if (sub_set->infinite && !super_set->infinite) + return 0; + + return 1; +} + +void hwloc_bitmap_or (struct hwloc_bitmap_s *res, const struct hwloc_bitmap_s *set1, const struct hwloc_bitmap_s *set2) +{ + /* cache counts so that we can reset res even if it's also set1 or set2 */ + unsigned count1 = set1->ulongs_count; + unsigned count2 = set2->ulongs_count; + unsigned max_count = count1 > count2 ? count1 : count2; + unsigned min_count = count1 + count2 - max_count; + unsigned i; + + HWLOC__BITMAP_CHECK(res); + HWLOC__BITMAP_CHECK(set1); + HWLOC__BITMAP_CHECK(set2); + + hwloc_bitmap_reset_by_ulongs(res, max_count); + + for(i=0; iulongs[i] = set1->ulongs[i] | set2->ulongs[i]; + + if (count1 != count2) { + if (min_count < count1) { + if (set2->infinite) { + res->ulongs_count = min_count; + } else { + for(i=min_count; iulongs[i] = set1->ulongs[i]; + } + } else { + if (set1->infinite) { + res->ulongs_count = min_count; + } else { + for(i=min_count; iulongs[i] = set2->ulongs[i]; + } + } + } + + res->infinite = set1->infinite || set2->infinite; +} + +void hwloc_bitmap_and (struct hwloc_bitmap_s *res, const struct hwloc_bitmap_s *set1, const struct hwloc_bitmap_s *set2) +{ + /* cache counts so that we can reset res even if it's also set1 or set2 */ + unsigned count1 = set1->ulongs_count; + unsigned count2 = set2->ulongs_count; + unsigned max_count = count1 > count2 ? count1 : count2; + unsigned min_count = count1 + count2 - max_count; + unsigned i; + + HWLOC__BITMAP_CHECK(res); + HWLOC__BITMAP_CHECK(set1); + HWLOC__BITMAP_CHECK(set2); + + hwloc_bitmap_reset_by_ulongs(res, max_count); + + for(i=0; iulongs[i] = set1->ulongs[i] & set2->ulongs[i]; + + if (count1 != count2) { + if (min_count < count1) { + if (set2->infinite) { + for(i=min_count; iulongs[i] = set1->ulongs[i]; + } else { + res->ulongs_count = min_count; + } + } else { + if (set1->infinite) { + for(i=min_count; iulongs[i] = set2->ulongs[i]; + } else { + res->ulongs_count = min_count; + } + } + } + + res->infinite = set1->infinite && set2->infinite; +} + +void hwloc_bitmap_andnot (struct hwloc_bitmap_s *res, const struct hwloc_bitmap_s *set1, const struct hwloc_bitmap_s *set2) +{ + /* cache counts so that we can reset res even if it's also set1 or set2 */ + unsigned count1 = set1->ulongs_count; + unsigned count2 = set2->ulongs_count; + unsigned max_count = count1 > count2 ? count1 : count2; + unsigned min_count = count1 + count2 - max_count; + unsigned i; + + HWLOC__BITMAP_CHECK(res); + HWLOC__BITMAP_CHECK(set1); + HWLOC__BITMAP_CHECK(set2); + + hwloc_bitmap_reset_by_ulongs(res, max_count); + + for(i=0; iulongs[i] = set1->ulongs[i] & ~set2->ulongs[i]; + + if (count1 != count2) { + if (min_count < count1) { + if (!set2->infinite) { + for(i=min_count; iulongs[i] = set1->ulongs[i]; + } else { + res->ulongs_count = min_count; + } + } else { + if (set1->infinite) { + for(i=min_count; iulongs[i] = ~set2->ulongs[i]; + } else { + res->ulongs_count = min_count; + } + } + } + + res->infinite = set1->infinite && !set2->infinite; +} + +void hwloc_bitmap_xor (struct hwloc_bitmap_s *res, const struct hwloc_bitmap_s *set1, const struct hwloc_bitmap_s *set2) +{ + /* cache counts so that we can reset res even if it's also set1 or set2 */ + unsigned count1 = set1->ulongs_count; + unsigned count2 = set2->ulongs_count; + unsigned max_count = count1 > count2 ? count1 : count2; + unsigned min_count = count1 + count2 - max_count; + unsigned i; + + HWLOC__BITMAP_CHECK(res); + HWLOC__BITMAP_CHECK(set1); + HWLOC__BITMAP_CHECK(set2); + + hwloc_bitmap_reset_by_ulongs(res, max_count); + + for(i=0; iulongs[i] = set1->ulongs[i] ^ set2->ulongs[i]; + + if (count1 != count2) { + if (min_count < count1) { + unsigned long w2 = set2->infinite ? HWLOC_SUBBITMAP_FULL : HWLOC_SUBBITMAP_ZERO; + for(i=min_count; iulongs[i] = set1->ulongs[i] ^ w2; + } else { + unsigned long w1 = set1->infinite ? HWLOC_SUBBITMAP_FULL : HWLOC_SUBBITMAP_ZERO; + for(i=min_count; iulongs[i] = set2->ulongs[i] ^ w1; + } + } + + res->infinite = (!set1->infinite) != (!set2->infinite); +} + +void hwloc_bitmap_not (struct hwloc_bitmap_s *res, const struct hwloc_bitmap_s *set) +{ + unsigned count = set->ulongs_count; + unsigned i; + + HWLOC__BITMAP_CHECK(res); + HWLOC__BITMAP_CHECK(set); + + hwloc_bitmap_reset_by_ulongs(res, count); + + for(i=0; iulongs[i] = ~set->ulongs[i]; + + res->infinite = !set->infinite; +} + +int hwloc_bitmap_first(const struct hwloc_bitmap_s * set) +{ + unsigned i; + + HWLOC__BITMAP_CHECK(set); + + for(i=0; iulongs_count; i++) { + /* subsets are unsigned longs, use ffsl */ + unsigned long w = set->ulongs[i]; + if (w) + return hwloc_ffsl(w) - 1 + HWLOC_BITS_PER_LONG*i; + } + + if (set->infinite) + return set->ulongs_count * HWLOC_BITS_PER_LONG; + + return -1; +} + +int hwloc_bitmap_last(const struct hwloc_bitmap_s * set) +{ + int i; + + HWLOC__BITMAP_CHECK(set); + + if (set->infinite) + return -1; + + for(i=set->ulongs_count-1; i>=0; i--) { + /* subsets are unsigned longs, use flsl */ + unsigned long w = set->ulongs[i]; + if (w) + return hwloc_flsl(w) - 1 + HWLOC_BITS_PER_LONG*i; + } + + return -1; +} + +int hwloc_bitmap_next(const struct hwloc_bitmap_s * set, int prev_cpu) +{ + unsigned i = HWLOC_SUBBITMAP_INDEX(prev_cpu + 1); + + HWLOC__BITMAP_CHECK(set); + + if (i >= set->ulongs_count) { + if (set->infinite) + return prev_cpu + 1; + else + return -1; + } + + for(; iulongs_count; i++) { + /* subsets are unsigned longs, use ffsl */ + unsigned long w = set->ulongs[i]; + + /* if the prev cpu is in the same word as the possible next one, + we need to mask out previous cpus */ + if (prev_cpu >= 0 && HWLOC_SUBBITMAP_INDEX((unsigned) prev_cpu) == i) + w &= ~HWLOC_SUBBITMAP_ULBIT_TO(HWLOC_SUBBITMAP_CPU_ULBIT(prev_cpu)); + + if (w) + return hwloc_ffsl(w) - 1 + HWLOC_BITS_PER_LONG*i; + } + + if (set->infinite) + return set->ulongs_count * HWLOC_BITS_PER_LONG; + + return -1; +} + +void hwloc_bitmap_singlify(struct hwloc_bitmap_s * set) +{ + unsigned i; + int found = 0; + + HWLOC__BITMAP_CHECK(set); + + for(i=0; iulongs_count; i++) { + if (found) { + set->ulongs[i] = HWLOC_SUBBITMAP_ZERO; + continue; + } else { + /* subsets are unsigned longs, use ffsl */ + unsigned long w = set->ulongs[i]; + if (w) { + int _ffs = hwloc_ffsl(w); + set->ulongs[i] = HWLOC_SUBBITMAP_CPU(_ffs-1); + found = 1; + } + } + } + + if (set->infinite) { + if (found) { + set->infinite = 0; + } else { + /* set the first non allocated bit */ + unsigned first = set->ulongs_count * HWLOC_BITS_PER_LONG; + set->infinite = 0; /* do not let realloc fill the newly allocated sets */ + hwloc_bitmap_set(set, first); + } + } +} + +int hwloc_bitmap_compare_first(const struct hwloc_bitmap_s * set1, const struct hwloc_bitmap_s * set2) +{ + unsigned count1 = set1->ulongs_count; + unsigned count2 = set2->ulongs_count; + unsigned max_count = count1 > count2 ? count1 : count2; + unsigned min_count = count1 + count2 - max_count; + unsigned i; + + HWLOC__BITMAP_CHECK(set1); + HWLOC__BITMAP_CHECK(set2); + + for(i=0; iulongs[i]; + unsigned long w2 = set2->ulongs[i]; + if (w1 || w2) { + int _ffs1 = hwloc_ffsl(w1); + int _ffs2 = hwloc_ffsl(w2); + /* if both have a bit set, compare for real */ + if (_ffs1 && _ffs2) + return _ffs1-_ffs2; + /* one is empty, and it is considered higher, so reverse-compare them */ + return _ffs2-_ffs1; + } + } + + if (count1 != count2) { + if (min_count < count2) { + for(i=min_count; iulongs[i]; + if (set1->infinite) + return -!(w2 & 1); + else if (w2) + return 1; + } + } else { + for(i=min_count; iulongs[i]; + if (set2->infinite) + return !(w1 & 1); + else if (w1) + return -1; + } + } + } + + return !!set1->infinite - !!set2->infinite; +} + +int hwloc_bitmap_compare(const struct hwloc_bitmap_s * set1, const struct hwloc_bitmap_s * set2) +{ + unsigned count1 = set1->ulongs_count; + unsigned count2 = set2->ulongs_count; + unsigned max_count = count1 > count2 ? count1 : count2; + unsigned min_count = count1 + count2 - max_count; + int i; + + HWLOC__BITMAP_CHECK(set1); + HWLOC__BITMAP_CHECK(set2); + + if ((!set1->infinite) != (!set2->infinite)) + return !!set1->infinite - !!set2->infinite; + + if (count1 != count2) { + if (min_count < count2) { + unsigned long val1 = set1->infinite ? HWLOC_SUBBITMAP_FULL : HWLOC_SUBBITMAP_ZERO; + for(i=max_count-1; i>=(signed) min_count; i--) { + unsigned long val2 = set2->ulongs[i]; + if (val1 == val2) + continue; + return val1 < val2 ? -1 : 1; + } + } else { + unsigned long val2 = set2->infinite ? HWLOC_SUBBITMAP_FULL : HWLOC_SUBBITMAP_ZERO; + for(i=max_count-1; i>=(signed) min_count; i--) { + unsigned long val1 = set1->ulongs[i]; + if (val1 == val2) + continue; + return val1 < val2 ? -1 : 1; + } + } + } + + for(i=min_count-1; i>=0; i--) { + unsigned long val1 = set1->ulongs[i]; + unsigned long val2 = set2->ulongs[i]; + if (val1 == val2) + continue; + return val1 < val2 ? -1 : 1; + } + + return 0; +} + +int hwloc_bitmap_weight(const struct hwloc_bitmap_s * set) +{ + int weight = 0; + unsigned i; + + HWLOC__BITMAP_CHECK(set); + + if (set->infinite) + return -1; + + for(i=0; iulongs_count; i++) + weight += hwloc_weight_long(set->ulongs[i]); + return weight; +} + +int hwloc_bitmap_compare_inclusion(const struct hwloc_bitmap_s * set1, const struct hwloc_bitmap_s * set2) +{ + unsigned max_count = set1->ulongs_count > set2->ulongs_count ? set1->ulongs_count : set2->ulongs_count; + int result = HWLOC_BITMAP_EQUAL; /* means empty sets return equal */ + int empty1 = 1; + int empty2 = 1; + unsigned i; + + HWLOC__BITMAP_CHECK(set1); + HWLOC__BITMAP_CHECK(set2); + + for(i=0; iinfinite) { + if (set2->infinite) { + /* set2 infinite only */ + if (result == HWLOC_BITMAP_CONTAINS) { + if (!empty2) + return HWLOC_BITMAP_INTERSECTS; + result = HWLOC_BITMAP_DIFFERENT; + } else if (result == HWLOC_BITMAP_EQUAL) { + result = HWLOC_BITMAP_INCLUDED; + } + /* no change otherwise */ + } + } else if (!set2->infinite) { + /* set1 infinite only */ + if (result == HWLOC_BITMAP_INCLUDED) { + if (!empty1) + return HWLOC_BITMAP_INTERSECTS; + result = HWLOC_BITMAP_DIFFERENT; + } else if (result == HWLOC_BITMAP_EQUAL) { + result = HWLOC_BITMAP_CONTAINS; + } + /* no change otherwise */ + } else { + /* both infinite */ + if (result == HWLOC_BITMAP_DIFFERENT) + return HWLOC_BITMAP_INTERSECTS; + /* equal/contains/included unchanged */ + } + + return result; +} diff --git a/opal/mca/hwloc/hwloc1110/hwloc/src/components.c b/opal/mca/hwloc/hwloc1110/hwloc/src/components.c new file mode 100644 index 0000000000..dc656e3985 --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/src/components.c @@ -0,0 +1,811 @@ +/* + * Copyright © 2009-2015 Inria. All rights reserved. + * Copyright © 2012 Université Bordeau 1 + * See COPYING in top-level directory. + */ + +#include +#include +#include +#include + +#define HWLOC_COMPONENT_STOP_NAME "stop" +#define HWLOC_COMPONENT_EXCLUDE_CHAR '-' +#define HWLOC_COMPONENT_SEPS "," + +/* list of all registered discovery components, sorted by priority, higher priority first. + * noos is last because its priority is 0. + * others' priority is 10. + */ +static struct hwloc_disc_component * hwloc_disc_components = NULL; + +static unsigned hwloc_components_users = 0; /* first one initializes, last ones destroys */ + +static int hwloc_components_verbose = 0; +#ifdef HWLOC_HAVE_PLUGINS +static int hwloc_plugins_verbose = 0; +#endif + +/* hwloc_components_mutex serializes: + * - loading/unloading plugins, and modifications of the hwloc_plugins list + * - calls to ltdl, including in hwloc_check_plugin_namespace() + * - registration of components with hwloc_disc_component_register() + * and hwloc_xml_callbacks_register() + */ +#ifdef HWLOC_WIN_SYS +/* Basic mutex on top of InterlockedCompareExchange() on windows, + * Far from perfect, but easy to maintain, and way enough given that this code will never be needed for real. */ +#include +static LONG hwloc_components_mutex = 0; +#define HWLOC_COMPONENTS_LOCK() do { \ + while (InterlockedCompareExchange(&hwloc_components_mutex, 1, 0) != 0) \ + SwitchToThread(); \ +} while (0) +#define HWLOC_COMPONENTS_UNLOCK() do { \ + assert(hwloc_components_mutex == 1); \ + hwloc_components_mutex = 0; \ +} while (0) + +#elif defined HWLOC_HAVE_PTHREAD_MUTEX +/* pthread mutex if available (except on windows) */ +#include +static pthread_mutex_t hwloc_components_mutex = PTHREAD_MUTEX_INITIALIZER; +#define HWLOC_COMPONENTS_LOCK() pthread_mutex_lock(&hwloc_components_mutex) +#define HWLOC_COMPONENTS_UNLOCK() pthread_mutex_unlock(&hwloc_components_mutex) + +#else /* HWLOC_WIN_SYS || HWLOC_HAVE_PTHREAD_MUTEX */ +#error No mutex implementation available +#endif + + +#ifdef HWLOC_HAVE_PLUGINS + +#include + +/* array of pointers to dynamically loaded plugins */ +static struct hwloc__plugin_desc { + char *name; + struct hwloc_component *component; + char *filename; + lt_dlhandle handle; + struct hwloc__plugin_desc *next; +} *hwloc_plugins = NULL; + +static int +hwloc__dlforeach_cb(const char *filename, void *_data __hwloc_attribute_unused) +{ + const char *basename; + lt_dlhandle handle; + char *componentsymbolname = NULL; + struct hwloc_component *component; + struct hwloc__plugin_desc *desc, **prevdesc; + + if (hwloc_plugins_verbose) + fprintf(stderr, "Plugin dlforeach found `%s'\n", filename); + + basename = strrchr(filename, '/'); + if (!basename) + basename = filename; + else + basename++; + + /* dlopen and get the component structure */ + handle = lt_dlopenext(filename); + if (!handle) { + if (hwloc_plugins_verbose) + fprintf(stderr, "Failed to load plugin: %s\n", lt_dlerror()); + goto out; + } + componentsymbolname = malloc(strlen(basename)+10+1); + sprintf(componentsymbolname, "%s_component", basename); + component = lt_dlsym(handle, componentsymbolname); + if (!component) { + if (hwloc_plugins_verbose) + fprintf(stderr, "Failed to find component symbol `%s'\n", + componentsymbolname); + goto out_with_handle; + } + if (component->abi != HWLOC_COMPONENT_ABI) { + if (hwloc_plugins_verbose) + fprintf(stderr, "Plugin symbol ABI %u instead of %u\n", + component->abi, HWLOC_COMPONENT_ABI); + goto out_with_handle; + } + if (hwloc_plugins_verbose) + fprintf(stderr, "Plugin contains expected symbol `%s'\n", + componentsymbolname); + free(componentsymbolname); + componentsymbolname = NULL; + + if (HWLOC_COMPONENT_TYPE_DISC == component->type) { + if (strncmp(basename, "hwloc_", 6)) { + if (hwloc_plugins_verbose) + fprintf(stderr, "Plugin name `%s' doesn't match its type DISCOVERY\n", basename); + goto out_with_handle; + } + } else if (HWLOC_COMPONENT_TYPE_XML == component->type) { + if (strncmp(basename, "hwloc_xml_", 10)) { + if (hwloc_plugins_verbose) + fprintf(stderr, "Plugin name `%s' doesn't match its type XML\n", basename); + goto out_with_handle; + } + } else { + if (hwloc_plugins_verbose) + fprintf(stderr, "Plugin name `%s' has invalid type %u\n", + basename, (unsigned) component->type); + goto out_with_handle; + } + + /* allocate a plugin_desc and queue it */ + desc = malloc(sizeof(*desc)); + if (!desc) + goto out_with_handle; + desc->name = strdup(basename); + desc->filename = strdup(filename); + desc->component = component; + desc->handle = handle; + desc->next = NULL; + if (hwloc_plugins_verbose) + fprintf(stderr, "Plugin descriptor `%s' ready\n", basename); + + /* append to the list */ + prevdesc = &hwloc_plugins; + while (*prevdesc) + prevdesc = &((*prevdesc)->next); + *prevdesc = desc; + if (hwloc_plugins_verbose) + fprintf(stderr, "Plugin descriptor `%s' queued\n", basename); + return 0; + + out_with_handle: + lt_dlclose(handle); + free(componentsymbolname); /* NULL if already freed */ + out: + return 0; +} + +static void +hwloc_plugins_exit(void) +{ + struct hwloc__plugin_desc *desc, *next; + + if (hwloc_plugins_verbose) + fprintf(stderr, "Closing all plugins\n"); + + desc = hwloc_plugins; + while (desc) { + next = desc->next; + lt_dlclose(desc->handle); + free(desc->name); + free(desc->filename); + free(desc); + desc = next; + } + hwloc_plugins = NULL; + + lt_dlexit(); +} + +static int +hwloc_plugins_init(void) +{ + const char *verboseenv; + char *path = HWLOC_PLUGINS_PATH; + const char *env; + int err; + + verboseenv = getenv("HWLOC_PLUGINS_VERBOSE"); + hwloc_plugins_verbose = verboseenv ? atoi(verboseenv) : 0; + + err = lt_dlinit(); + if (err) + goto out; + + env = getenv("HWLOC_PLUGINS_PATH"); + if (env) + path = env; + + hwloc_plugins = NULL; + + if (hwloc_plugins_verbose) + fprintf(stderr, "Starting plugin dlforeach in %s\n", path); + err = lt_dlforeachfile(path, hwloc__dlforeach_cb, NULL); + if (err) + goto out_with_init; + + return 0; + + out_with_init: + hwloc_plugins_exit(); + out: + return -1; +} + +#endif /* HWLOC_HAVE_PLUGINS */ + +static const char * +hwloc_disc_component_type_string(hwloc_disc_component_type_t type) +{ + switch (type) { + case HWLOC_DISC_COMPONENT_TYPE_CPU: return "cpu"; + case HWLOC_DISC_COMPONENT_TYPE_GLOBAL: return "global"; + case HWLOC_DISC_COMPONENT_TYPE_MISC: return "misc"; + default: return "**unknown**"; + } +} + +static int +hwloc_disc_component_register(struct hwloc_disc_component *component, + const char *filename) +{ + struct hwloc_disc_component **prev; + + /* check that the component name is valid */ + if (!strcmp(component->name, HWLOC_COMPONENT_STOP_NAME)) { + if (hwloc_components_verbose) + fprintf(stderr, "Cannot register discovery component with reserved name `" HWLOC_COMPONENT_STOP_NAME "'\n"); + return -1; + } + if (strchr(component->name, HWLOC_COMPONENT_EXCLUDE_CHAR) + || strcspn(component->name, HWLOC_COMPONENT_SEPS) != strlen(component->name)) { + if (hwloc_components_verbose) + fprintf(stderr, "Cannot register discovery component with name `%s' containing reserved characters `%c" HWLOC_COMPONENT_SEPS "'\n", + component->name, HWLOC_COMPONENT_EXCLUDE_CHAR); + return -1; + } + /* check that the component type is valid */ + switch ((unsigned) component->type) { + case HWLOC_DISC_COMPONENT_TYPE_CPU: + case HWLOC_DISC_COMPONENT_TYPE_GLOBAL: + case HWLOC_DISC_COMPONENT_TYPE_MISC: + break; + default: + fprintf(stderr, "Cannot register discovery component `%s' with unknown type %u\n", + component->name, (unsigned) component->type); + return -1; + } + + prev = &hwloc_disc_components; + while (NULL != *prev) { + if (!strcmp((*prev)->name, component->name)) { + /* if two components have the same name, only keep the highest priority one */ + if ((*prev)->priority < component->priority) { + /* drop the existing component */ + if (hwloc_components_verbose) + fprintf(stderr, "Dropping previously registered discovery component `%s', priority %u lower than new one %u\n", + (*prev)->name, (*prev)->priority, component->priority); + *prev = (*prev)->next; + } else { + /* drop the new one */ + if (hwloc_components_verbose) + fprintf(stderr, "Ignoring new discovery component `%s', priority %u lower than previously registered one %u\n", + component->name, component->priority, (*prev)->priority); + return -1; + } + } + prev = &((*prev)->next); + } + if (hwloc_components_verbose) + fprintf(stderr, "Registered %s discovery component `%s' with priority %u (%s%s)\n", + hwloc_disc_component_type_string(component->type), component->name, component->priority, + filename ? "from plugin " : "statically build", filename ? filename : ""); + + prev = &hwloc_disc_components; + while (NULL != *prev) { + if ((*prev)->priority < component->priority) + break; + prev = &((*prev)->next); + } + component->next = *prev; + *prev = component; + return 0; +} + +#include + +static void (**hwloc_component_finalize_cbs)(unsigned long); +static unsigned hwloc_component_finalize_cb_count; + +void +hwloc_components_init(struct hwloc_topology *topology __hwloc_attribute_unused) +{ +#ifdef HWLOC_HAVE_PLUGINS + struct hwloc__plugin_desc *desc; +#endif + const char *verboseenv; + unsigned i; + + HWLOC_COMPONENTS_LOCK(); + assert((unsigned) -1 != hwloc_components_users); + if (0 != hwloc_components_users++) { + HWLOC_COMPONENTS_UNLOCK(); + goto ok; + } + + verboseenv = getenv("HWLOC_COMPONENTS_VERBOSE"); + hwloc_components_verbose = verboseenv ? atoi(verboseenv) : 0; + +#ifdef HWLOC_HAVE_PLUGINS + hwloc_plugins_init(); +#endif + + hwloc_component_finalize_cbs = NULL; + hwloc_component_finalize_cb_count = 0; + /* count the max number of finalize callbacks */ + for(i=0; NULL != hwloc_static_components[i]; i++) + hwloc_component_finalize_cb_count++; +#ifdef HWLOC_HAVE_PLUGINS + for(desc = hwloc_plugins; NULL != desc; desc = desc->next) + hwloc_component_finalize_cb_count++; +#endif + if (hwloc_component_finalize_cb_count) { + hwloc_component_finalize_cbs = calloc(hwloc_component_finalize_cb_count, + sizeof(*hwloc_component_finalize_cbs)); + assert(hwloc_component_finalize_cbs); + /* forget that max number and recompute the real one below */ + hwloc_component_finalize_cb_count = 0; + } + + /* hwloc_static_components is created by configure in static-components.h */ + for(i=0; NULL != hwloc_static_components[i]; i++) { + if (hwloc_static_components[i]->flags) { + fprintf(stderr, "Ignoring static component with invalid flags %lx\n", + hwloc_static_components[i]->flags); + continue; + } + + /* initialize the component */ + if (hwloc_static_components[i]->init && hwloc_static_components[i]->init(0) < 0) { + if (hwloc_components_verbose) + fprintf(stderr, "Ignoring static component, failed to initialize\n"); + continue; + } + /* queue ->finalize() callback if any */ + if (hwloc_static_components[i]->finalize) + hwloc_component_finalize_cbs[hwloc_component_finalize_cb_count++] = hwloc_static_components[i]->finalize; + + /* register for real now */ + if (HWLOC_COMPONENT_TYPE_DISC == hwloc_static_components[i]->type) + hwloc_disc_component_register(hwloc_static_components[i]->data, NULL); + else if (HWLOC_COMPONENT_TYPE_XML == hwloc_static_components[i]->type) + hwloc_xml_callbacks_register(hwloc_static_components[i]->data); + else + assert(0); + } + + /* dynamic plugins */ +#ifdef HWLOC_HAVE_PLUGINS + for(desc = hwloc_plugins; NULL != desc; desc = desc->next) { + if (desc->component->flags) { + fprintf(stderr, "Ignoring plugin `%s' component with invalid flags %lx\n", + desc->name, desc->component->flags); + continue; + } + + /* initialize the component */ + if (desc->component->init && desc->component->init(0) < 0) { + if (hwloc_components_verbose) + fprintf(stderr, "Ignoring plugin `%s', failed to initialize\n", desc->name); + continue; + } + /* queue ->finalize() callback if any */ + if (desc->component->finalize) + hwloc_component_finalize_cbs[hwloc_component_finalize_cb_count++] = desc->component->finalize; + + /* register for real now */ + if (HWLOC_COMPONENT_TYPE_DISC == desc->component->type) + hwloc_disc_component_register(desc->component->data, desc->filename); + else if (HWLOC_COMPONENT_TYPE_XML == desc->component->type) + hwloc_xml_callbacks_register(desc->component->data); + else + assert(0); + } +#endif + + HWLOC_COMPONENTS_UNLOCK(); + + ok: + topology->backends = NULL; +} + +static struct hwloc_disc_component * +hwloc_disc_component_find(int type /* hwloc_disc_component_type_t or -1 if any */, + const char *name /* name of NULL if any */) +{ + struct hwloc_disc_component *comp = hwloc_disc_components; + while (NULL != comp) { + if ((-1 == type || type == (int) comp->type) + && (NULL == name || !strcmp(name, comp->name))) + return comp; + comp = comp->next; + } + return NULL; +} + +/* used by set_xml(), set_synthetic(), ... environment variables, ... to force the first backend */ +int +hwloc_disc_component_force_enable(struct hwloc_topology *topology, + int envvar_forced, + int type, const char *name, + const void *data1, const void *data2, const void *data3) +{ + struct hwloc_disc_component *comp; + struct hwloc_backend *backend; + + if (topology->is_loaded) { + errno = EBUSY; + return -1; + } + + comp = hwloc_disc_component_find(type, name); + if (!comp) { + errno = ENOSYS; + return -1; + } + + backend = comp->instantiate(comp, data1, data2, data3); + if (backend) { + backend->envvar_forced = envvar_forced; + if (topology->backends) + hwloc_backends_disable_all(topology); + return hwloc_backend_enable(topology, backend); + } else + return -1; +} + +static int +hwloc_disc_component_try_enable(struct hwloc_topology *topology, + struct hwloc_disc_component *comp, + const char *comparg, + unsigned *excludes, + int envvar_forced, + int verbose_errors) +{ + struct hwloc_backend *backend; + int err; + + if ((*excludes) & comp->type) { + if (hwloc_components_verbose || verbose_errors) + fprintf(stderr, "Excluding %s discovery component `%s', conflicts with excludes 0x%x\n", + hwloc_disc_component_type_string(comp->type), comp->name, *excludes); + return -1; + } + + backend = comp->instantiate(comp, comparg, NULL, NULL); + if (!backend) { + if (hwloc_components_verbose || verbose_errors) + fprintf(stderr, "Failed to instantiate discovery component `%s'\n", comp->name); + return -1; + } + + backend->envvar_forced = envvar_forced; + err = hwloc_backend_enable(topology, backend); + if (err < 0) + return -1; + + *excludes |= comp->excludes; + + return 0; +} + +void +hwloc_disc_components_enable_others(struct hwloc_topology *topology) +{ + struct hwloc_disc_component *comp; + struct hwloc_backend *backend; + unsigned excludes = 0; + int tryall = 1; + const char *_env; + char *env; /* we'll to modify the env value, so duplicate it */ + + _env = getenv("HWLOC_COMPONENTS"); + env = _env ? strdup(_env) : NULL; + + /* compute current excludes */ + backend = topology->backends; + while (backend) { + excludes |= backend->component->excludes; + backend = backend->next; + } + + /* enable explicitly listed components */ + if (env) { + char *curenv = env; + size_t s; + + while (*curenv) { + s = strcspn(curenv, HWLOC_COMPONENT_SEPS); + if (s) { + char *arg; + char c, d; + + /* replace libpci with pci for backward compatibility with v1.6 */ + if (!strncmp(curenv, "libpci", s)) { + curenv[0] = curenv[1] = curenv[2] = *HWLOC_COMPONENT_SEPS; + curenv += 3; + s -= 3; + } else if (curenv[0] == HWLOC_COMPONENT_EXCLUDE_CHAR && !strncmp(curenv+1, "libpci", s-1)) { + curenv[3] = curenv[0]; + curenv[0] = curenv[1] = curenv[2] = *HWLOC_COMPONENT_SEPS; + curenv += 3; + s -= 3; + /* skip this name, it's a negated one */ + goto nextname; + } + + if (curenv[0] == HWLOC_COMPONENT_EXCLUDE_CHAR) + goto nextname; + + if (!strncmp(curenv, HWLOC_COMPONENT_STOP_NAME, s)) { + tryall = 0; + break; + } + + /* save the last char and replace with \0 */ + c = curenv[s]; + curenv[s] = '\0'; + + arg = strchr(curenv, '='); + if (arg) { + d = *arg; + *arg = '\0'; + } + + comp = hwloc_disc_component_find(-1, curenv); + if (comp) { + hwloc_disc_component_try_enable(topology, comp, arg ? arg+1 : NULL, &excludes, 1 /* envvar forced */, 1 /* envvar forced need warnings */); + } else { + fprintf(stderr, "Cannot find discovery component `%s'\n", curenv); + } + + /* restore chars (the second loop below needs env to be unmodified) */ + curenv[s] = c; + if (arg) + *arg = d; + } + +nextname: + curenv += s; + if (*curenv) + /* Skip comma */ + curenv++; + } + } + + /* env is still the same, the above loop didn't modify it */ + + /* now enable remaining components (except the explicitly '-'-listed ones) */ + if (tryall) { + comp = hwloc_disc_components; + while (NULL != comp) { + /* check if this component was explicitly excluded in env */ + if (env) { + char *curenv = env; + while (*curenv) { + size_t s = strcspn(curenv, HWLOC_COMPONENT_SEPS); + if (curenv[0] == HWLOC_COMPONENT_EXCLUDE_CHAR && !strncmp(curenv+1, comp->name, s-1)) { + if (hwloc_components_verbose) + fprintf(stderr, "Excluding %s discovery component `%s' because of HWLOC_COMPONENTS environment variable\n", + hwloc_disc_component_type_string(comp->type), comp->name); + goto nextcomp; + } + curenv += s; + if (*curenv) + /* Skip comma */ + curenv++; + } + } + hwloc_disc_component_try_enable(topology, comp, NULL, &excludes, 0 /* defaults, not envvar forced */, 0 /* defaults don't need warnings on conflicts */); +nextcomp: + comp = comp->next; + } + } + + if (hwloc_components_verbose) { + /* print a summary */ + int first = 1; + backend = topology->backends; + fprintf(stderr, "Final list of enabled discovery components: "); + while (backend != NULL) { + fprintf(stderr, "%s%s", first ? "" : ",", backend->component->name); + backend = backend->next; + first = 0; + } + fprintf(stderr, "\n"); + } + + if (env) + free(env); +} + +void +hwloc_components_destroy_all(struct hwloc_topology *topology __hwloc_attribute_unused) +{ + unsigned i; + + HWLOC_COMPONENTS_LOCK(); + assert(0 != hwloc_components_users); + if (0 != --hwloc_components_users) { + HWLOC_COMPONENTS_UNLOCK(); + return; + } + + for(i=0; icomponent = component; + backend->flags = 0; + backend->discover = NULL; + backend->get_obj_cpuset = NULL; + backend->notify_new_object = NULL; + backend->disable = NULL; + backend->is_custom = 0; + backend->is_thissystem = -1; + backend->next = NULL; + backend->envvar_forced = 0; + return backend; +} + +static void +hwloc_backend_disable(struct hwloc_backend *backend) +{ + if (backend->disable) + backend->disable(backend); + free(backend); +} + +int +hwloc_backend_enable(struct hwloc_topology *topology, struct hwloc_backend *backend) +{ + struct hwloc_backend **pprev; + + /* check backend flags */ + if (backend->flags & (~(HWLOC_BACKEND_FLAG_NEED_LEVELS))) { + fprintf(stderr, "Cannot enable %s discovery component `%s' with unknown flags %lx\n", + hwloc_disc_component_type_string(backend->component->type), backend->component->name, backend->flags); + return -1; + } + + /* make sure we didn't already enable this backend, we don't want duplicates */ + pprev = &topology->backends; + while (NULL != *pprev) { + if ((*pprev)->component == backend->component) { + if (hwloc_components_verbose) + fprintf(stderr, "Cannot enable %s discovery component `%s' twice\n", + hwloc_disc_component_type_string(backend->component->type), backend->component->name); + hwloc_backend_disable(backend); + errno = EBUSY; + return -1; + } + pprev = &((*pprev)->next); + } + + if (hwloc_components_verbose) + fprintf(stderr, "Enabling %s discovery component `%s'\n", + hwloc_disc_component_type_string(backend->component->type), backend->component->name); + + /* enqueue at the end */ + pprev = &topology->backends; + while (NULL != *pprev) + pprev = &((*pprev)->next); + backend->next = *pprev; + *pprev = backend; + + backend->topology = topology; + + return 0; +} + +void +hwloc_backends_is_thissystem(struct hwloc_topology *topology) +{ + struct hwloc_backend *backend; + const char *local_env; + + /* Apply is_thissystem topology flag before we enforce envvar backends. + * If the application changed the backend with set_foo(), + * it may use set_flags() update the is_thissystem flag here. + * If it changes the backend with environment variables below, + * it may use HWLOC_THISSYSTEM envvar below as well. + */ + + topology->is_thissystem = 1; + + /* apply thissystem from normally-given backends (envvar_forced=0, either set_foo() or defaults) */ + backend = topology->backends; + while (backend != NULL) { + if (backend->envvar_forced == 0 && backend->is_thissystem != -1) { + assert(backend->is_thissystem == 0); + topology->is_thissystem = 0; + } + backend = backend->next; + } + + /* override set_foo() with flags */ + if (topology->flags & HWLOC_TOPOLOGY_FLAG_IS_THISSYSTEM) + topology->is_thissystem = 1; + + /* now apply envvar-forced backend (envvar_forced=1) */ + backend = topology->backends; + while (backend != NULL) { + if (backend->envvar_forced == 1 && backend->is_thissystem != -1) { + assert(backend->is_thissystem == 0); + topology->is_thissystem = 0; + } + backend = backend->next; + } + + /* override with envvar-given flag */ + local_env = getenv("HWLOC_THISSYSTEM"); + if (local_env) + topology->is_thissystem = atoi(local_env); +} + +int +hwloc_backends_get_obj_cpuset(struct hwloc_backend *caller, struct hwloc_obj *obj, hwloc_bitmap_t cpuset) +{ + struct hwloc_topology *topology = caller->topology; + struct hwloc_backend *backend = topology->backends; + /* use the first backend's get_obj_cpuset callback */ + while (backend != NULL) { + if (backend->get_obj_cpuset) + return backend->get_obj_cpuset(backend, caller, obj, cpuset); + backend = backend->next; + } + return -1; +} + +int +hwloc_backends_notify_new_object(struct hwloc_backend *caller, struct hwloc_obj *obj) +{ + struct hwloc_backend *backend; + int res = 0; + + backend = caller->topology->backends; + while (NULL != backend) { + if (backend != caller && backend->notify_new_object) + res += backend->notify_new_object(backend, caller, obj); + backend = backend->next; + } + + return res; +} + +void +hwloc_backends_disable_all(struct hwloc_topology *topology) +{ + struct hwloc_backend *backend; + + while (NULL != (backend = topology->backends)) { + struct hwloc_backend *next = backend->next; + if (hwloc_components_verbose) + fprintf(stderr, "Disabling %s discovery component `%s'\n", + hwloc_disc_component_type_string(backend->component->type), backend->component->name); + hwloc_backend_disable(backend); + topology->backends = next; + } + topology->backends = NULL; +} diff --git a/opal/mca/hwloc/hwloc1110/hwloc/src/diff.c b/opal/mca/hwloc/hwloc1110/hwloc/src/diff.c new file mode 100644 index 0000000000..060aa93f55 --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/src/diff.c @@ -0,0 +1,408 @@ +/* + * Copyright © 2013-2014 Inria. All rights reserved. + * See COPYING in top-level directory. + */ + +#include +#include +#include + +int hwloc_topology_diff_destroy(hwloc_topology_t topology __hwloc_attribute_unused, + hwloc_topology_diff_t diff) +{ + hwloc_topology_diff_t next; + while (diff) { + next = diff->generic.next; + switch (diff->generic.type) { + default: + break; + case HWLOC_TOPOLOGY_DIFF_OBJ_ATTR: + switch (diff->obj_attr.diff.generic.type) { + default: + break; + case HWLOC_TOPOLOGY_DIFF_OBJ_ATTR_NAME: + case HWLOC_TOPOLOGY_DIFF_OBJ_ATTR_INFO: + free(diff->obj_attr.diff.string.name); + free(diff->obj_attr.diff.string.oldvalue); + free(diff->obj_attr.diff.string.newvalue); + break; + } + break; + } + free(diff); + diff = next; + } + return 0; +} + +/************************ + * Computing diffs + */ + +static void hwloc_append_diff(hwloc_topology_diff_t newdiff, + hwloc_topology_diff_t *firstdiffp, + hwloc_topology_diff_t *lastdiffp) +{ + if (*firstdiffp) + (*lastdiffp)->generic.next = newdiff; + else + *firstdiffp = newdiff; + *lastdiffp = newdiff; + newdiff->generic.next = NULL; +} + +static int hwloc_append_diff_too_complex(hwloc_obj_t obj1, + hwloc_topology_diff_t *firstdiffp, + hwloc_topology_diff_t *lastdiffp) +{ + hwloc_topology_diff_t newdiff; + newdiff = malloc(sizeof(*newdiff)); + if (!newdiff) + return -1; + + newdiff->too_complex.type = HWLOC_TOPOLOGY_DIFF_TOO_COMPLEX; + newdiff->too_complex.obj_depth = obj1->depth; + newdiff->too_complex.obj_index = obj1->logical_index; + hwloc_append_diff(newdiff, firstdiffp, lastdiffp); + return 0; +} + +static int hwloc_append_diff_obj_attr_string(hwloc_obj_t obj, + hwloc_topology_diff_obj_attr_type_t type, + const char *name, + const char *oldvalue, + const char *newvalue, + hwloc_topology_diff_t *firstdiffp, + hwloc_topology_diff_t *lastdiffp) +{ + hwloc_topology_diff_t newdiff; + + if (obj->type == HWLOC_OBJ_MISC) + /* TODO: add a custom level/depth for Misc */ + return hwloc_append_diff_too_complex(obj, firstdiffp, lastdiffp); + + newdiff = malloc(sizeof(*newdiff)); + if (!newdiff) + return -1; + + newdiff->obj_attr.type = HWLOC_TOPOLOGY_DIFF_OBJ_ATTR; + newdiff->obj_attr.obj_depth = obj->depth; + newdiff->obj_attr.obj_index = obj->logical_index; + newdiff->obj_attr.diff.string.type = type; + newdiff->obj_attr.diff.string.name = name ? strdup(name) : NULL; + newdiff->obj_attr.diff.string.oldvalue = oldvalue ? strdup(oldvalue) : NULL; + newdiff->obj_attr.diff.string.newvalue = newvalue ? strdup(newvalue) : NULL; + hwloc_append_diff(newdiff, firstdiffp, lastdiffp); + return 0; +} + +static int hwloc_append_diff_obj_attr_uint64(hwloc_obj_t obj, + hwloc_topology_diff_obj_attr_type_t type, + hwloc_uint64_t idx, + hwloc_uint64_t oldvalue, + hwloc_uint64_t newvalue, + hwloc_topology_diff_t *firstdiffp, + hwloc_topology_diff_t *lastdiffp) +{ + hwloc_topology_diff_t newdiff; + + if (obj->type == HWLOC_OBJ_MISC) + /* TODO: add a custom level/depth for Misc */ + return hwloc_append_diff_too_complex(obj, firstdiffp, lastdiffp); + + newdiff = malloc(sizeof(*newdiff)); + if (!newdiff) + return -1; + + newdiff->obj_attr.type = HWLOC_TOPOLOGY_DIFF_OBJ_ATTR; + newdiff->obj_attr.obj_depth = obj->depth; + newdiff->obj_attr.obj_index = obj->logical_index; + newdiff->obj_attr.diff.uint64.type = type; + newdiff->obj_attr.diff.uint64.index = idx; + newdiff->obj_attr.diff.uint64.oldvalue = oldvalue; + newdiff->obj_attr.diff.uint64.newvalue = newvalue; + hwloc_append_diff(newdiff, firstdiffp, lastdiffp); + return 0; +} + +static int +hwloc_diff_trees(hwloc_topology_t topo1, hwloc_obj_t obj1, + hwloc_topology_t topo2, hwloc_obj_t obj2, + unsigned flags, + hwloc_topology_diff_t *firstdiffp, hwloc_topology_diff_t *lastdiffp) +{ + unsigned i; + int err; + + if (obj1->depth != obj2->depth) + goto out_too_complex; + if (obj1->type != obj2->type) + goto out_too_complex; + + if (obj1->os_index != obj2->os_index) + /* we could allow different os_index for non-PU non-NUMAnode objects + * but it's likely useless anyway */ + goto out_too_complex; + +#define _SETS_DIFFERENT(_set1, _set2) \ + ( ( !(_set1) != !(_set2) ) \ + || ( (_set1) && !hwloc_bitmap_isequal(_set1, _set2) ) ) +#define SETS_DIFFERENT(_set, _obj1, _obj2) _SETS_DIFFERENT((_obj1)->_set, (_obj2)->_set) + if (SETS_DIFFERENT(cpuset, obj1, obj2) + || SETS_DIFFERENT(complete_cpuset, obj1, obj2) + || SETS_DIFFERENT(online_cpuset, obj1, obj2) + || SETS_DIFFERENT(allowed_cpuset, obj1, obj2) + || SETS_DIFFERENT(nodeset, obj1, obj2) + || SETS_DIFFERENT(complete_nodeset, obj1, obj2) + || SETS_DIFFERENT(allowed_nodeset, obj1, obj2)) + goto out_too_complex; + + /* no need to check logical_index, sibling_rank, symmetric_subtree, + * the parents did it */ + + if ((!obj1->name) != (!obj2->name) + || (obj1->name && strcmp(obj1->name, obj2->name))) { + err = hwloc_append_diff_obj_attr_string(obj1, + HWLOC_TOPOLOGY_DIFF_OBJ_ATTR_NAME, + NULL, + obj1->name, + obj2->name, + firstdiffp, lastdiffp); + if (err < 0) + return err; + } + + /* memory */ + if (obj1->memory.local_memory != obj2->memory.local_memory) { + err = hwloc_append_diff_obj_attr_uint64(obj1, + HWLOC_TOPOLOGY_DIFF_OBJ_ATTR_SIZE, + 0, + obj1->memory.local_memory, + obj2->memory.local_memory, + firstdiffp, lastdiffp); + if (err < 0) + return err; + } + /* ignore memory page_types */ + + /* ignore os_level */ + + /* type-specific attrs */ + switch (obj1->type) { + default: + break; + case HWLOC_OBJ_CACHE: + if (memcmp(obj1->attr, obj2->attr, sizeof(obj1->attr->cache))) + goto out_too_complex; + break; + case HWLOC_OBJ_GROUP: + if (memcmp(obj1->attr, obj2->attr, sizeof(obj1->attr->group))) + goto out_too_complex; + break; + case HWLOC_OBJ_PCI_DEVICE: + if (memcmp(obj1->attr, obj2->attr, sizeof(obj1->attr->pcidev))) + goto out_too_complex; + break; + case HWLOC_OBJ_BRIDGE: + if (memcmp(obj1->attr, obj2->attr, sizeof(obj1->attr->bridge))) + goto out_too_complex; + break; + case HWLOC_OBJ_OS_DEVICE: + if (memcmp(obj1->attr, obj2->attr, sizeof(obj1->attr->osdev))) + goto out_too_complex; + break; + } + + /* distances */ + if (obj1->distances_count != obj2->distances_count) + goto out_too_complex; + for(i=0; idistances_count; i++) { + struct hwloc_distances_s *d1 = obj1->distances[i], *d2 = obj2->distances[i]; + if (d1->relative_depth != d2->relative_depth + || d1->nbobjs != d2->nbobjs + || d1->latency_max != d2->latency_max + || d1->latency_base != d2->latency_base + || memcmp(d1->latency, d2->latency, d1->nbobjs * d1->nbobjs * sizeof(*d1->latency))) + goto out_too_complex; + } + + /* infos */ + if (obj1->infos_count != obj2->infos_count) + goto out_too_complex; + for(i=0; iinfos_count; i++) { + if (strcmp(obj1->infos[i].name, obj2->infos[i].name)) + goto out_too_complex; + if (strcmp(obj1->infos[i].value, obj2->infos[i].value)) { + err = hwloc_append_diff_obj_attr_string(obj1, + HWLOC_TOPOLOGY_DIFF_OBJ_ATTR_INFO, + obj1->infos[i].name, + obj1->infos[i].value, + obj2->infos[i].value, + firstdiffp, lastdiffp); + if (err < 0) + return err; + } + } + + /* ignore userdata */ + + /* children */ + if (obj1->arity != obj2->arity) + goto out_too_complex; + for(i=0; iarity; i++) { + err = hwloc_diff_trees(topo1, obj1->children[i], + topo2, obj2->children[i], + flags, + firstdiffp, lastdiffp); + if (err < 0) + return err; + } + + return 0; + +out_too_complex: + hwloc_append_diff_too_complex(obj1, firstdiffp, lastdiffp); + return 0; +} + +int hwloc_topology_diff_build(hwloc_topology_t topo1, + hwloc_topology_t topo2, + unsigned long flags, + hwloc_topology_diff_t *diffp) +{ + hwloc_topology_diff_t lastdiff, tmpdiff; + int err; + + if (flags != 0) { + errno = EINVAL; + return -1; + } + + *diffp = NULL; + err = hwloc_diff_trees(topo1, hwloc_get_root_obj(topo1), + topo2, hwloc_get_root_obj(topo2), + flags, + diffp, &lastdiff); + + if (!err) { + tmpdiff = *diffp; + while (tmpdiff) { + if (tmpdiff->generic.type == HWLOC_TOPOLOGY_DIFF_TOO_COMPLEX) { + err = 1; + break; + } + tmpdiff = tmpdiff->generic.next; + } + } + + return err; +} + +/******************** + * Applying diffs + */ + +static int +hwloc_apply_diff_one(hwloc_topology_t topology, + hwloc_topology_diff_t diff, + unsigned long flags) +{ + int reverse = !!(flags & HWLOC_TOPOLOGY_DIFF_APPLY_REVERSE); + + switch (diff->generic.type) { + case HWLOC_TOPOLOGY_DIFF_OBJ_ATTR: { + struct hwloc_topology_diff_obj_attr_s *obj_attr = &diff->obj_attr; + hwloc_obj_t obj = hwloc_get_obj_by_depth(topology, obj_attr->obj_depth, obj_attr->obj_index); + if (!obj) + return -1; + + switch (obj_attr->diff.generic.type) { + case HWLOC_TOPOLOGY_DIFF_OBJ_ATTR_SIZE: { + hwloc_obj_t tmpobj; + hwloc_uint64_t oldvalue = reverse ? obj_attr->diff.uint64.newvalue : obj_attr->diff.uint64.oldvalue; + hwloc_uint64_t newvalue = reverse ? obj_attr->diff.uint64.oldvalue : obj_attr->diff.uint64.newvalue; + hwloc_uint64_t valuediff = newvalue - oldvalue; + if (obj->memory.local_memory != oldvalue) + return -1; + obj->memory.local_memory = newvalue; + tmpobj = obj; + while (tmpobj) { + tmpobj->memory.total_memory += valuediff; + tmpobj = tmpobj->parent; + } + break; + } + case HWLOC_TOPOLOGY_DIFF_OBJ_ATTR_NAME: { + const char *oldvalue = reverse ? obj_attr->diff.string.newvalue : obj_attr->diff.string.oldvalue; + const char *newvalue = reverse ? obj_attr->diff.string.oldvalue : obj_attr->diff.string.newvalue; + if (!obj->name || strcmp(obj->name, oldvalue)) + return -1; + free(obj->name); + obj->name = strdup(newvalue); + break; + } + case HWLOC_TOPOLOGY_DIFF_OBJ_ATTR_INFO: { + const char *name = obj_attr->diff.string.name; + const char *oldvalue = reverse ? obj_attr->diff.string.newvalue : obj_attr->diff.string.oldvalue; + const char *newvalue = reverse ? obj_attr->diff.string.oldvalue : obj_attr->diff.string.newvalue; + unsigned i; + int found = 0; + for(i=0; iinfos_count; i++) { + if (!strcmp(obj->infos[i].name, name) + && !strcmp(obj->infos[i].value, oldvalue)) { + free(obj->infos[i].value); + obj->infos[i].value = strdup(newvalue); + found = 1; + break; + } + } + if (!found) + return -1; + break; + } + default: + return -1; + } + + break; + } + default: + return -1; + } + + return 0; +} + +int hwloc_topology_diff_apply(hwloc_topology_t topology, + hwloc_topology_diff_t diff, + unsigned long flags) +{ + hwloc_topology_diff_t tmpdiff, tmpdiff2; + int err, nr; + + if (flags & ~HWLOC_TOPOLOGY_DIFF_APPLY_REVERSE) { + errno = EINVAL; + return -1; + } + + tmpdiff = diff; + nr = 0; + while (tmpdiff) { + nr++; + err = hwloc_apply_diff_one(topology, tmpdiff, flags); + if (err < 0) + goto cancel; + tmpdiff = tmpdiff->generic.next; + } + return 0; + +cancel: + tmpdiff2 = tmpdiff; + tmpdiff = diff; + while (tmpdiff != tmpdiff2) { + hwloc_apply_diff_one(topology, tmpdiff, flags ^ HWLOC_TOPOLOGY_DIFF_APPLY_REVERSE); + tmpdiff = tmpdiff->generic.next; + } + errno = EINVAL; + return -nr; /* return the index (starting at 1) of the first element that couldn't be applied */ +} diff --git a/opal/mca/hwloc/hwloc1110/hwloc/src/distances.c b/opal/mca/hwloc/hwloc1110/hwloc/src/distances.c new file mode 100644 index 0000000000..5288680368 --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/src/distances.c @@ -0,0 +1,1040 @@ +/* + * Copyright © 2010-2015 Inria. All rights reserved. + * Copyright © 2011-2012 Université Bordeaux + * Copyright © 2011 Cisco Systems, Inc. All rights reserved. + * See COPYING in top-level directory. + */ + +#include +#include +#include +#include + +#include +#include + +/************************** + * Main Init/Clear/Destroy + */ + +/* called during topology init */ +void hwloc_distances_init(struct hwloc_topology *topology) +{ + topology->first_osdist = topology->last_osdist = NULL; +} + +/* called during topology destroy */ +void hwloc_distances_destroy(struct hwloc_topology * topology) +{ + struct hwloc_os_distances_s *osdist, *next = topology->first_osdist; + while ((osdist = next) != NULL) { + next = osdist->next; + /* remove final distance matrics AND physically-ordered ones */ + free(osdist->indexes); + free(osdist->objs); + free(osdist->distances); + free(osdist); + } + topology->first_osdist = topology->last_osdist = NULL; +} + +/****************************************************** + * Inserting distances in the topology + * from a backend, from the environment or by the user + */ + +/* insert a distance matrix in the topology. + * the caller gives us those pointers, we take care of freeing them later and so on. + */ +void hwloc_distances_set(hwloc_topology_t __hwloc_restrict topology, hwloc_obj_type_t type, + unsigned nbobjs, unsigned *indexes, hwloc_obj_t *objs, float *distances, + int force) +{ + struct hwloc_os_distances_s *osdist, *next = topology->first_osdist; + /* look for existing distances for the same type */ + while ((osdist = next) != NULL) { + next = osdist->next; + if (osdist->type == type) { + if (osdist->forced && !force) { + /* there is a forced distance element, ignore the new non-forced one */ + free(indexes); + free(objs); + free(distances); + return; + } else if (force) { + /* we're forcing a new distance, remove the old ones */ + free(osdist->indexes); + free(osdist->objs); + free(osdist->distances); + /* remove current object */ + if (osdist->prev) + osdist->prev->next = next; + else + topology->first_osdist = next; + if (next) + next->prev = osdist->prev; + else + topology->last_osdist = osdist->prev; + /* free current object */ + free(osdist); + } + } + } + + if (!nbobjs) + /* we're just clearing, return now */ + return; + + /* create the new element */ + osdist = malloc(sizeof(struct hwloc_os_distances_s)); + osdist->nbobjs = nbobjs; + osdist->indexes = indexes; + osdist->objs = objs; + osdist->distances = distances; + osdist->forced = force; + osdist->type = type; + /* insert it */ + osdist->next = NULL; + osdist->prev = topology->last_osdist; + if (topology->last_osdist) + topology->last_osdist->next = osdist; + else + topology->first_osdist = osdist; + topology->last_osdist = osdist; +} + +/* make sure a user-given distance matrix is sane */ +static int hwloc_distances__check_matrix(hwloc_topology_t __hwloc_restrict topology __hwloc_attribute_unused, hwloc_obj_type_t type __hwloc_attribute_unused, + unsigned nbobjs, unsigned *indexes, hwloc_obj_t *objs __hwloc_attribute_unused, float *distances __hwloc_attribute_unused) +{ + unsigned i,j; + /* make sure we don't have the same index twice */ + for(i=0; i= 2) { + /* generate the matrix to create x groups of y elements */ + if (x*y*z != nbobjs) { + fprintf(stderr, "Ignoring %s distances from environment variable, invalid grouping (%u*%u*%u=%u instead of %u)\n", + hwloc_obj_type_string(type), x, y, z, x*y*z, nbobjs); + free(indexes); + free(distances); + return; + } + for(i=0; ifirst_osdist; osdist; osdist = osdist->next) { + /* remove the objs array, we'll rebuild it from the indexes + * depending on remaining objects */ + free(osdist->objs); + osdist->objs = NULL; + } +} + + +/* cleanup everything we created from distances so that we may rebuild them + * at the end of restrict() + */ +void hwloc_distances_restrict(struct hwloc_topology *topology, unsigned long flags) +{ + if (flags & HWLOC_RESTRICT_FLAG_ADAPT_DISTANCES) { + /* some objects may have been removed, clear objects arrays so that finalize_os rebuilds them properly */ + hwloc_distances_restrict_os(topology); + } else { + /* if not adapting distances, drop everything */ + hwloc_distances_destroy(topology); + } +} + +/************************************************************** + * Convert user/env given array of indexes into actual objects + */ + +static hwloc_obj_t hwloc_find_obj_by_type_and_os_index(hwloc_obj_t root, hwloc_obj_type_t type, unsigned os_index) +{ + hwloc_obj_t child; + if (root->type == type && root->os_index == os_index) + return root; + child = root->first_child; + while (child) { + hwloc_obj_t found = hwloc_find_obj_by_type_and_os_index(child, type, os_index); + if (found) + return found; + child = child->next_sibling; + } + return NULL; +} + +/* convert distance indexes that were previously stored in the topology + * into actual objects if not done already. + * it's already done when distances come from backends (this function should not be called then). + * it's not done when distances come from the user. + * + * returns -1 if the matrix was invalid + */ +static int +hwloc_distances__finalize_os(struct hwloc_topology *topology, struct hwloc_os_distances_s *osdist) +{ + unsigned nbobjs = osdist->nbobjs; + unsigned *indexes = osdist->indexes; + float *distances = osdist->distances; + unsigned i, j; + hwloc_obj_type_t type = osdist->type; + hwloc_obj_t *objs = calloc(nbobjs, sizeof(hwloc_obj_t)); + + assert(!osdist->objs); + + /* traverse the topology and look for the relevant objects */ + for(i=0; ilevels[0][0], type, indexes[i]); + if (!obj) { + + /* shift the matrix */ +#define OLDPOS(i,j) (distances+(i)*nbobjs+(j)) +#define NEWPOS(i,j) (distances+(i)*(nbobjs-1)+(j)) + if (i>0) { + /** no need to move beginning of 0th line */ + for(j=0; jnbobjs = nbobjs; + if (!nbobjs) { + /* the whole matrix was invalid, let the caller remove this distances */ + free(objs); + return -1; + } + + /* setup the objs array */ + osdist->objs = objs; + return 0; +} + + +void hwloc_distances_finalize_os(struct hwloc_topology *topology) +{ + int dropall = !topology->levels[0][0]->cpuset; /* we don't support distances on multinode systems */ + + struct hwloc_os_distances_s *osdist, *next = topology->first_osdist; + while ((osdist = next) != NULL) { + int err; + next = osdist->next; + + if (dropall) + goto drop; + + /* remove final distance matrics AND physically-ordered ones */ + + if (osdist->objs) + /* nothing to do, switch to the next element */ + continue; + + err = hwloc_distances__finalize_os(topology, osdist); + if (!err) + /* convert ok, switch to the next element */ + continue; + + drop: + /* remove this element */ + free(osdist->indexes); + free(osdist->distances); + /* remove current object */ + if (osdist->prev) + osdist->prev->next = next; + else + topology->first_osdist = next; + if (next) + next->prev = osdist->prev; + else + topology->last_osdist = osdist->prev; + /* free current object */ + free(osdist); + } +} + +/*********************************************************** + * Convert internal distances given by the backend/env/user + * into exported logical distances attached to objects + */ + +static void +hwloc_distances__finalize_logical(struct hwloc_topology *topology, + unsigned nbobjs, + hwloc_obj_t *objs, float *osmatrix) +{ + unsigned i, j, li, lj, minl; + float min = FLT_MAX, max = FLT_MIN; + hwloc_obj_t root; + float *matrix; + hwloc_cpuset_t cpuset, complete_cpuset; + hwloc_nodeset_t nodeset, complete_nodeset; + unsigned relative_depth; + int idx; + + /* find the root */ + cpuset = hwloc_bitmap_alloc(); + complete_cpuset = hwloc_bitmap_alloc(); + nodeset = hwloc_bitmap_alloc(); + complete_nodeset = hwloc_bitmap_alloc(); + for(i=0; icpuset); + if (objs[i]->complete_cpuset) + hwloc_bitmap_or(complete_cpuset, complete_cpuset, objs[i]->complete_cpuset); + if (objs[i]->nodeset) + hwloc_bitmap_or(nodeset, nodeset, objs[i]->nodeset); + if (objs[i]->complete_nodeset) + hwloc_bitmap_or(complete_nodeset, complete_nodeset, objs[i]->complete_nodeset); + } + /* find the object covering cpuset, we'll take care of the nodeset later */ + root = hwloc_get_obj_covering_cpuset(topology, cpuset); + /* walk up to find a parent that also covers the nodeset */ + while (root && + (!hwloc_bitmap_isincluded(nodeset, root->nodeset) + || !hwloc_bitmap_isincluded(complete_nodeset, root->complete_nodeset) + || !hwloc_bitmap_isincluded(complete_cpuset, root->complete_cpuset))) + root = root->parent; + if (!root) { + /* should not happen, ignore the distance matrix and report an error. */ + if (!hwloc_hide_errors()) { + char *a, *b; + hwloc_bitmap_asprintf(&a, cpuset); + hwloc_bitmap_asprintf(&b, nodeset); + fprintf(stderr, "****************************************************************************\n"); + fprintf(stderr, "* hwloc %s has encountered an error when adding a distance matrix to the topology.\n", HWLOC_VERSION); + fprintf(stderr, "*\n"); + fprintf(stderr, "* hwloc_distances__finalize_logical() could not find any object covering\n"); + fprintf(stderr, "* cpuset %s and nodeset %s\n", a, b); + fprintf(stderr, "*\n"); + fprintf(stderr, "* Please report this error message to the hwloc user's mailing list,\n"); +#ifdef HWLOC_LINUX_SYS + fprintf(stderr, "* along with the output from the hwloc-gather-topology script.\n"); +#else + fprintf(stderr, "* along with any relevant topology information from your platform.\n"); +#endif + fprintf(stderr, "****************************************************************************\n"); + free(a); + free(b); + } + hwloc_bitmap_free(cpuset); + hwloc_bitmap_free(complete_cpuset); + hwloc_bitmap_free(nodeset); + hwloc_bitmap_free(complete_nodeset); + return; + } + /* don't attach to Misc objects */ + while (root->type == HWLOC_OBJ_MISC) + root = root->parent; + /* ideally, root has the exact cpuset and nodeset. + * but ignoring or other things that remove objects may cause the object array to reduce */ + assert(hwloc_bitmap_isincluded(cpuset, root->cpuset)); + assert(hwloc_bitmap_isincluded(complete_cpuset, root->complete_cpuset)); + assert(hwloc_bitmap_isincluded(nodeset, root->nodeset)); + assert(hwloc_bitmap_isincluded(complete_nodeset, root->complete_nodeset)); + hwloc_bitmap_free(cpuset); + hwloc_bitmap_free(complete_cpuset); + hwloc_bitmap_free(nodeset); + hwloc_bitmap_free(complete_nodeset); + if (root->depth >= objs[0]->depth) { + /* strange topology led us to find invalid relative depth, ignore */ + return; + } + relative_depth = objs[0]->depth - root->depth; /* this assume that we have distances between objects of the same level */ + + if (nbobjs != hwloc_get_nbobjs_inside_cpuset_by_depth(topology, root->cpuset, root->depth + relative_depth)) + /* the root does not cover the right number of objects, maybe we failed to insert a root (bad intersect or so). */ + return; + + /* get the logical index offset, it's the min of all logical indexes */ + minl = UINT_MAX; + for(i=0; i objs[i]->logical_index) + minl = objs[i]->logical_index; + + /* compute/check min/max values */ + for(i=0; i max) + max = val; + } + if (!min) { + /* Linux up to 2.6.36 reports ACPI SLIT distances, which should be memory latencies. + * Except of SGI IP27 (SGI Origin 200/2000 with MIPS processors) where the distances + * are the number of hops between routers. + */ + hwloc_debug("%s", "minimal distance is 0, matrix does not seem to contain latencies, ignoring\n"); + return; + } + + /* store the normalized latency matrix in the root object */ + idx = root->distances_count++; + root->distances = realloc(root->distances, root->distances_count * sizeof(struct hwloc_distances_s *)); + root->distances[idx] = malloc(sizeof(struct hwloc_distances_s)); + root->distances[idx]->relative_depth = relative_depth; + root->distances[idx]->nbobjs = nbobjs; + root->distances[idx]->latency = matrix = malloc(nbobjs*nbobjs*sizeof(float)); + root->distances[idx]->latency_base = (float) min; +#define NORMALIZE_LATENCY(d) ((d)/(min)) + root->distances[idx]->latency_max = NORMALIZE_LATENCY(max); + for(i=0; ilogical_index - minl; + matrix[li*nbobjs+li] = NORMALIZE_LATENCY(osmatrix[i*nbobjs+i]); + for(j=i+1; jlogical_index - minl; + matrix[li*nbobjs+lj] = NORMALIZE_LATENCY(osmatrix[i*nbobjs+j]); + matrix[lj*nbobjs+li] = NORMALIZE_LATENCY(osmatrix[j*nbobjs+i]); + } + } +} + +/* convert internal distances into logically-ordered distances + * that can be exposed in the API + */ +void +hwloc_distances_finalize_logical(struct hwloc_topology *topology) +{ + unsigned nbobjs; + int depth; + struct hwloc_os_distances_s * osdist; + for(osdist = topology->first_osdist; osdist; osdist = osdist->next) { + + nbobjs = osdist->nbobjs; + if (!nbobjs) + continue; + + depth = hwloc_get_type_depth(topology, osdist->type); + if (depth == HWLOC_TYPE_DEPTH_UNKNOWN || depth == HWLOC_TYPE_DEPTH_MULTIPLE) + continue; + + if (osdist->objs) { + assert(osdist->distances); + hwloc_distances__finalize_logical(topology, nbobjs, + osdist->objs, + osdist->distances); + } + } +} + +/*************************************************** + * Destroying logical distances attached to objects + */ + +/* destroy an object distances structure */ +void +hwloc_clear_object_distances_one(struct hwloc_distances_s * distances) +{ + free(distances->latency); + free(distances); + +} + +void +hwloc_clear_object_distances(hwloc_obj_t obj) +{ + unsigned i; + for (i=0; idistances_count; i++) + hwloc_clear_object_distances_one(obj->distances[i]); + free(obj->distances); + obj->distances = NULL; + obj->distances_count = 0; +} + +/****************************************** + * 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 has encountered what looks like an error from user-given distances.\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 interface or environment\n"); + fprintf(stderr, "* variables do not contradict any other topology information.\n"); + fprintf(stderr, "****************************************************************************\n"); + reported = 1; + } +} + +static int hwloc_compare_distances(float a, float b, float accuracy) +{ + if (accuracy != 0.0 && fabsf(a-b) < a * accuracy) + return 0; + return a < b ? -1 : a == b ? 0 : 1; +} + +/* + * Place objects in groups if they are in a transitive graph of minimal distances. + * Return how many groups were created, or 0 if some incomplete distance graphs were found. + */ +static unsigned +hwloc__find_groups_by_min_distance(unsigned nbobjs, + float *_distances, + float accuracy, + unsigned *groupids, + int verbose) +{ + float min_distance = FLT_MAX; + unsigned groupid = 1; + unsigned i,j,k; + unsigned skipped = 0; + +#define DISTANCE(i, j) _distances[(i) * nbobjs + (j)] + + memset(groupids, 0, nbobjs*sizeof(*groupids)); + + /* find the minimal distance */ + for(i=0; itype), accuracies[i]); + if (needcheck && hwloc__check_grouping_matrix(nbobjs, _distances, accuracies[i], verbose) < 0) + continue; + nbgroups = hwloc__find_groups_by_min_distance(nbobjs, _distances, accuracies[i], groupids, verbose); + if (nbgroups) + break; + } + if (!nbgroups) + goto outter_free; + + /* For convenience, put these declarations inside a block. It's a + crying shame we can't use C99 syntax here, and have to do a bunch + of mallocs. :-( */ + { + hwloc_obj_t *groupobjs = NULL; + unsigned *groupsizes = NULL; + float *groupdistances = NULL; + unsigned failed = 0; + + groupobjs = malloc(sizeof(hwloc_obj_t) * nbgroups); + groupsizes = malloc(sizeof(unsigned) * nbgroups); + groupdistances = malloc(sizeof(float) * nbgroups * nbgroups); + if (NULL == groupobjs || NULL == groupsizes || NULL == groupdistances) { + goto inner_free; + } + /* create new Group objects and record their size */ + memset(&(groupsizes[0]), 0, sizeof(groupsizes[0]) * nbgroups); + for(i=0; icpuset = hwloc_bitmap_alloc(); + group_obj->attr->group.depth = topology->next_group_depth; + for (j=0; jcpuset, group_obj->cpuset, objs[j]->cpuset); + if (objs[i]->complete_cpuset) { + if (!group_obj->complete_cpuset) + group_obj->complete_cpuset = hwloc_bitmap_alloc(); + hwloc_bitmap_or(group_obj->complete_cpuset, group_obj->complete_cpuset, objs[j]->complete_cpuset); + } + /* if one obj has a nodeset, assemble a group nodeset */ + if (objs[j]->nodeset) { + if (!group_obj->nodeset) + group_obj->nodeset = hwloc_bitmap_alloc(); + hwloc_bitmap_or(group_obj->nodeset, group_obj->nodeset, objs[j]->nodeset); + } + if (objs[i]->complete_nodeset) { + if (!group_obj->complete_nodeset) + group_obj->complete_nodeset = hwloc_bitmap_alloc(); + hwloc_bitmap_or(group_obj->complete_nodeset, group_obj->complete_nodeset, objs[j]->complete_nodeset); + } + groupsizes[i]++; + } + hwloc_debug_1arg_bitmap("adding Group object with %u objects and cpuset %s\n", + groupsizes[i], group_obj->cpuset); + res_obj = hwloc__insert_object_by_cpuset(topology, group_obj, + fromuser ? hwloc_report_user_distance_error : hwloc_report_os_error); + /* res_obj may be NULL on failure to insert. */ + if (!res_obj) + failed++; + /* or it may be different from groupobjs if we got groups from XML import before grouping */ + groupobjs[i] = res_obj; + } + + if (failed) + /* don't try to group above if we got a NULL group here, just keep this incomplete level */ + goto inner_free; + + /* factorize distances */ + memset(&(groupdistances[0]), 0, sizeof(groupdistances[0]) * nbgroups * nbgroups); +#undef DISTANCE +#define DISTANCE(i, j) _distances[(i) * nbobjs + (j)] +#define GROUP_DISTANCE(i, j) groupdistances[(i) * nbgroups + (j)] + for(i=0; inext_group_depth++; + hwloc__groups_by_distances(topology, nbgroups, groupobjs, (float*) groupdistances, nbaccuracies, accuracies, fromuser, 0 /* no need to check generated matrix */, verbose); + + inner_free: + /* Safely free everything */ + if (NULL != groupobjs) { + free(groupobjs); + } + if (NULL != groupsizes) { + free(groupsizes); + } + if (NULL != groupdistances) { + free(groupdistances); + } + } + + outter_free: + if (NULL != groupids) { + free(groupids); + } +} + +void +hwloc_group_by_distances(struct hwloc_topology *topology) +{ + unsigned nbobjs; + struct hwloc_os_distances_s * osdist; + const char *env; + float accuracies[5] = { 0.0f, 0.01f, 0.02f, 0.05f, 0.1f }; + unsigned nbaccuracies = 5; + hwloc_obj_t group_obj; + int verbose = 0; + unsigned i; + hwloc_localeswitch_declare; +#ifdef HWLOC_DEBUG + unsigned j; +#endif + + env = getenv("HWLOC_GROUPING"); + if (env && !atoi(env)) + return; + /* backward compat with v1.2 */ + if (getenv("HWLOC_IGNORE_DISTANCES")) + return; + + hwloc_localeswitch_init(); + env = getenv("HWLOC_GROUPING_ACCURACY"); + if (!env) { + /* only use 0.0 */ + nbaccuracies = 1; + } else if (strcmp(env, "try")) { + /* use the given value */ + nbaccuracies = 1; + accuracies[0] = (float) atof(env); + } /* otherwise try all values */ + hwloc_localeswitch_fini(); + +#ifdef HWLOC_DEBUG + verbose = 1; +#else + env = getenv("HWLOC_GROUPING_VERBOSE"); + if (env) + verbose = atoi(env); +#endif + + for(osdist = topology->first_osdist; osdist; osdist = osdist->next) { + + nbobjs = osdist->nbobjs; + if (!nbobjs) + continue; + + if (osdist->objs) { + /* if we have objs, we must have distances as well, + * thanks to hwloc_convert_distances_indexes_into_objects() + */ + assert(osdist->distances); + +#ifdef HWLOC_DEBUG + hwloc_debug("%s", "trying to group objects using distance matrix:\n"); + hwloc_debug("%s", " index"); + for(j=0; jobjs[j]->os_index); + hwloc_debug("%s", "\n"); + for(i=0; iobjs[i]->os_index); + for(j=0; jdistances[i*nbobjs + j]); + hwloc_debug("%s", "\n"); + } +#endif + + hwloc__groups_by_distances(topology, nbobjs, + osdist->objs, + osdist->distances, + nbaccuracies, accuracies, + osdist->indexes != NULL, + 1 /* check the first matrice */, + verbose); + + /* add a final group object covering everybody so that the distance matrix can be stored somewhere. + * this group will be merged into a regular object if the matrix isn't strangely incomplete + */ + group_obj = hwloc_alloc_setup_object(HWLOC_OBJ_GROUP, -1); + group_obj->attr->group.depth = (unsigned) -1; + group_obj->cpuset = hwloc_bitmap_alloc(); + for(i=0; icpuset, group_obj->cpuset, osdist->objs[i]->cpuset); + if (osdist->objs[i]->complete_cpuset) { + if (!group_obj->complete_cpuset) + group_obj->complete_cpuset = hwloc_bitmap_alloc(); + hwloc_bitmap_or(group_obj->complete_cpuset, group_obj->complete_cpuset, osdist->objs[i]->complete_cpuset); + } + /* if one obj has a nodeset, assemble a group nodeset */ + if (osdist->objs[i]->nodeset) { + if (!group_obj->nodeset) + group_obj->nodeset = hwloc_bitmap_alloc(); + hwloc_bitmap_or(group_obj->nodeset, group_obj->nodeset, osdist->objs[i]->nodeset); + } + if (osdist->objs[i]->complete_nodeset) { + if (!group_obj->complete_nodeset) + group_obj->complete_nodeset = hwloc_bitmap_alloc(); + hwloc_bitmap_or(group_obj->complete_nodeset, group_obj->complete_nodeset, osdist->objs[i]->complete_nodeset); + } + } + hwloc_debug_1arg_bitmap("adding Group object (as root of distance matrix with %u objects) with cpuset %s\n", + nbobjs, group_obj->cpuset); + hwloc__insert_object_by_cpuset(topology, group_obj, + osdist->indexes != NULL ? hwloc_report_user_distance_error : hwloc_report_os_error); + } + } +} diff --git a/opal/mca/hwloc/hwloc1110/hwloc/src/dolib.c b/opal/mca/hwloc/hwloc1110/hwloc/src/dolib.c new file mode 100644 index 0000000000..0b2835a5da --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/src/dolib.c @@ -0,0 +1,47 @@ +/* + * Copyright © 2009 CNRS + * Copyright © 2009 inria. All rights reserved. + * Copyright © 2009, 2012 Université Bordeaux + * See COPYING in top-level directory. + */ + +/* Wrapper to avoid msys' tendency to turn / into \ and : into ; */ + +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include + +int main(int argc, char *argv[]) { + char *prog, *arch, *def, *version, *lib; + char s[1024]; + char name[16]; + int current, age, revision; + + if (argc != 6) { + fprintf(stderr,"bad number of arguments"); + exit(EXIT_FAILURE); + } + + prog = argv[1]; + arch = argv[2]; + def = argv[3]; + version = argv[4]; + lib = argv[5]; + + if (sscanf(version, "%d:%d:%d", ¤t, &revision, &age) != 3) + exit(EXIT_FAILURE); + + _snprintf(name, sizeof(name), "libhwloc-%d", current - age); + printf("using soname %s\n", name); + + _snprintf(s, sizeof(s), "\"%s\" /machine:%s /def:%s /name:%s /out:%s", + prog, arch, def, name, lib); + if (system(s)) { + fprintf(stderr, "%s failed\n", s); + exit(EXIT_FAILURE); + } + + exit(EXIT_SUCCESS); +} diff --git a/opal/mca/hwloc/hwloc1110/hwloc/src/hwloc.dtd b/opal/mca/hwloc/hwloc1110/hwloc/src/hwloc.dtd new file mode 100644 index 0000000000..5e494f80a8 --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/src/hwloc.dtd @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/opal/mca/hwloc/hwloc1110/hwloc/src/misc.c b/opal/mca/hwloc/hwloc1110/hwloc/src/misc.c new file mode 100644 index 0000000000..3da6687d4e --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/src/misc.c @@ -0,0 +1,166 @@ +/* + * Copyright © 2009 CNRS + * Copyright © 2009-2014 Inria. All rights reserved. + * Copyright © 2009-2010 Université Bordeaux + * Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved. + * See COPYING in top-level directory. + */ + +#include +#include +#include + +#include +#ifdef HAVE_SYS_UTSNAME_H +#include +#endif +#include +#include +#include +#include +#include + +#ifdef HAVE_PROGRAM_INVOCATION_NAME +#include +extern char *program_invocation_name; +#endif +#ifdef HAVE___PROGNAME +extern char *__progname; +#endif + +int hwloc_snprintf(char *str, size_t size, const char *format, ...) +{ + int ret; + va_list ap; + static char bin; + size_t fakesize; + char *fakestr; + + /* Some systems crash on str == NULL */ + if (!size) { + str = &bin; + size = 1; + } + + va_start(ap, format); + ret = vsnprintf(str, size, format, ap); + va_end(ap); + + if (ret >= 0 && (size_t) ret != size-1) + return ret; + + /* vsnprintf returned size-1 or -1. That could be a system which reports the + * written data and not the actually required room. Try increasing buffer + * size to get the latter. */ + + fakesize = size; + fakestr = NULL; + do { + fakesize *= 2; + free(fakestr); + fakestr = malloc(fakesize); + if (NULL == fakestr) + return -1; + va_start(ap, format); + errno = 0; + ret = vsnprintf(fakestr, fakesize, format, ap); + va_end(ap); + } while ((size_t) ret == fakesize-1 || (ret < 0 && (!errno || errno == ERANGE))); + + if (ret >= 0 && size) { + if (size > (size_t) ret+1) + size = ret+1; + memcpy(str, fakestr, size-1); + str[size-1] = 0; + } + free(fakestr); + + return ret; +} + +int hwloc_namecoloncmp(const char *haystack, const char *needle, size_t n) +{ + size_t i = 0; + while (*haystack && *haystack != ':') { + int ha = *haystack++; + int low_h = tolower(ha); + int ne = *needle++; + int low_n = tolower(ne); + if (low_h != low_n) + return 1; + i++; + } + return i < n; +} + +void hwloc_add_uname_info(struct hwloc_topology *topology __hwloc_attribute_unused, + void *cached_uname __hwloc_attribute_unused) +{ +#ifdef HAVE_UNAME + struct utsname _utsname, *utsname; + + if (hwloc_obj_get_info_by_name(topology->levels[0][0], "OSName")) + /* don't annotate twice */ + return; + + if (cached_uname) + utsname = (struct utsname *) cached_uname; + else { + utsname = &_utsname; + if (uname(utsname) < 0) + return; + } + + if (*utsname->sysname) + hwloc_obj_add_info(topology->levels[0][0], "OSName", utsname->sysname); + if (*utsname->release) + hwloc_obj_add_info(topology->levels[0][0], "OSRelease", utsname->release); + if (*utsname->version) + hwloc_obj_add_info(topology->levels[0][0], "OSVersion", utsname->version); + if (*utsname->nodename) + hwloc_obj_add_info(topology->levels[0][0], "HostName", utsname->nodename); + if (*utsname->machine) + hwloc_obj_add_info(topology->levels[0][0], "Architecture", utsname->machine); +#endif /* HAVE_UNAME */ +} + +char * +hwloc_progname(struct hwloc_topology *topology __hwloc_attribute_unused) +{ +#if HAVE_DECL_GETMODULEFILENAME + char name[256], *basename; + unsigned res = GetModuleFileName(NULL, name, sizeof(name)); + if (res == sizeof(name) || !res) + return NULL; + basename = strrchr(name, '\\'); + if (!basename) + basename = name; + else + basename++; + return strdup(basename); +#else /* !HAVE_GETMODULEFILENAME */ + const char *name, *basename; +#if HAVE_DECL_GETPROGNAME + name = getprogname(); /* FreeBSD, NetBSD, some Solaris */ +#elif HAVE_DECL_GETEXECNAME + name = getexecname(); /* Solaris */ +#elif defined HAVE_PROGRAM_INVOCATION_NAME + name = program_invocation_name; /* Glibc. BGQ CNK. */ + /* could use program_invocation_short_name directly, but we have the code to remove the path below anyway */ +#elif defined HAVE___PROGNAME + name = __progname; /* fallback for most unix, used for OpenBSD */ +#else + /* TODO: _NSGetExecutablePath(path, &size) on Darwin */ + /* TODO: AIX, HPUX, OSF */ + name = NULL; +#endif + if (!name) + return NULL; + basename = strrchr(name, '/'); + if (!basename) + basename = name; + else + basename++; + return strdup(basename); +#endif /* !HAVE_GETMODULEFILENAME */ +} diff --git a/opal/mca/hwloc/hwloc1110/hwloc/src/pci-common.c b/opal/mca/hwloc/hwloc1110/hwloc/src/pci-common.c new file mode 100644 index 0000000000..01d4e79b66 --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/src/pci-common.c @@ -0,0 +1,514 @@ +/* + * Copyright © 2009-2015 Inria. All rights reserved. + * See COPYING in top-level directory. + */ + +#include +#include +#include +#include + +#ifdef HWLOC_DEBUG +static void +hwloc_pci_traverse_print_cb(void * cbdata __hwloc_attribute_unused, + struct hwloc_obj *pcidev) +{ + char busid[14]; + hwloc_obj_t parent; + + /* indent */ + parent = pcidev->parent; + while (parent) { + hwloc_debug("%s", " "); + parent = parent->parent; + } + + snprintf(busid, sizeof(busid), "%04x:%02x:%02x.%01x", + pcidev->attr->pcidev.domain, pcidev->attr->pcidev.bus, pcidev->attr->pcidev.dev, pcidev->attr->pcidev.func); + + if (pcidev->type == HWLOC_OBJ_BRIDGE) { + if (pcidev->attr->bridge.upstream_type == HWLOC_OBJ_BRIDGE_HOST) + hwloc_debug("HostBridge"); + else + hwloc_debug("Bridge [%04x:%04x]", busid, + pcidev->attr->pcidev.vendor_id, pcidev->attr->pcidev.device_id); + hwloc_debug(" to %04x:[%02x:%02x]\n", + pcidev->attr->bridge.downstream.pci.domain, pcidev->attr->bridge.downstream.pci.secondary_bus, pcidev->attr->bridge.downstream.pci.subordinate_bus); + } else + hwloc_debug("%s Device [%04x:%04x (%04x:%04x) rev=%02x class=%04x]\n", busid, + pcidev->attr->pcidev.vendor_id, pcidev->attr->pcidev.device_id, + pcidev->attr->pcidev.subvendor_id, pcidev->attr->pcidev.subdevice_id, + pcidev->attr->pcidev.revision, pcidev->attr->pcidev.class_id); +} +#endif /* HWLOC_DEBUG */ + +static void +hwloc_pci_traverse_lookuposdevices_cb(void * cbdata, + struct hwloc_obj *pcidev) +{ + struct hwloc_backend *backend = cbdata; + + if (pcidev->type == HWLOC_OBJ_BRIDGE) + return; + + hwloc_backends_notify_new_object(backend, pcidev); +} + +static void +hwloc_pci__traverse(void * cbdata, struct hwloc_obj *root, + void (*cb)(void * cbdata, struct hwloc_obj *)) +{ + struct hwloc_obj *child = root->first_child; + while (child) { + cb(cbdata, child); + if (child->type == HWLOC_OBJ_BRIDGE) + hwloc_pci__traverse(cbdata, child, cb); + child = child->next_sibling; + } +} + +static void +hwloc_pci_traverse(void * cbdata, struct hwloc_obj *root, + void (*cb)(void * cbdata, struct hwloc_obj *)) +{ + hwloc_pci__traverse(cbdata, root, cb); +} + +enum hwloc_pci_busid_comparison_e { + HWLOC_PCI_BUSID_LOWER, + HWLOC_PCI_BUSID_HIGHER, + HWLOC_PCI_BUSID_INCLUDED, + HWLOC_PCI_BUSID_SUPERSET +}; + +static enum hwloc_pci_busid_comparison_e +hwloc_pci_compare_busids(struct hwloc_obj *a, struct hwloc_obj *b) +{ + if (a->type == HWLOC_OBJ_BRIDGE) + assert(a->attr->bridge.upstream_type == HWLOC_OBJ_BRIDGE_PCI); + if (b->type == HWLOC_OBJ_BRIDGE) + assert(b->attr->bridge.upstream_type == HWLOC_OBJ_BRIDGE_PCI); + + if (a->attr->pcidev.domain < b->attr->pcidev.domain) + return HWLOC_PCI_BUSID_LOWER; + if (a->attr->pcidev.domain > b->attr->pcidev.domain) + return HWLOC_PCI_BUSID_HIGHER; + + if (a->type == HWLOC_OBJ_BRIDGE + && b->attr->pcidev.bus >= a->attr->bridge.downstream.pci.secondary_bus + && b->attr->pcidev.bus <= a->attr->bridge.downstream.pci.subordinate_bus) + return HWLOC_PCI_BUSID_SUPERSET; + if (b->type == HWLOC_OBJ_BRIDGE + && a->attr->pcidev.bus >= b->attr->bridge.downstream.pci.secondary_bus + && a->attr->pcidev.bus <= b->attr->bridge.downstream.pci.subordinate_bus) + return HWLOC_PCI_BUSID_INCLUDED; + + if (a->attr->pcidev.bus < b->attr->pcidev.bus) + return HWLOC_PCI_BUSID_LOWER; + if (a->attr->pcidev.bus > b->attr->pcidev.bus) + return HWLOC_PCI_BUSID_HIGHER; + + if (a->attr->pcidev.dev < b->attr->pcidev.dev) + return HWLOC_PCI_BUSID_LOWER; + if (a->attr->pcidev.dev > b->attr->pcidev.dev) + return HWLOC_PCI_BUSID_HIGHER; + + if (a->attr->pcidev.func < b->attr->pcidev.func) + return HWLOC_PCI_BUSID_LOWER; + if (a->attr->pcidev.func > b->attr->pcidev.func) + return HWLOC_PCI_BUSID_HIGHER; + + /* Should never reach here. Abort on both debug builds and + non-debug builds */ + assert(0); + fprintf(stderr, "Bad assertion in hwloc %s:%d (aborting)\n", __FILE__, __LINE__); + exit(1); +} + +static void +hwloc_pci_add_child_before(struct hwloc_obj *root, struct hwloc_obj *child, struct hwloc_obj *new) +{ + if (child) { + new->prev_sibling = child->prev_sibling; + child->prev_sibling = new; + } else { + new->prev_sibling = root->last_child; + root->last_child = new; + } + + if (new->prev_sibling) + new->prev_sibling->next_sibling = new; + else + root->first_child = new; + new->next_sibling = child; + + new->parent = root; /* so that hwloc_pci_traverse_print_cb() can indent by depth */ +} + +static void +hwloc_pci_remove_child(struct hwloc_obj *root, struct hwloc_obj *child) +{ + if (child->next_sibling) + child->next_sibling->prev_sibling = child->prev_sibling; + else + root->last_child = child->prev_sibling; + if (child->prev_sibling) + child->prev_sibling->next_sibling = child->next_sibling; + else + root->first_child = child->next_sibling; + child->prev_sibling = NULL; + child->next_sibling = NULL; +} + +static void hwloc_pci_add_object(struct hwloc_obj *root, struct hwloc_obj *new); + +static void +hwloc_pci_try_insert_siblings_below_new_bridge(struct hwloc_obj *root, struct hwloc_obj *new) +{ + enum hwloc_pci_busid_comparison_e comp; + struct hwloc_obj *current, *next; + + next = new->next_sibling; + while (next) { + current = next; + next = current->next_sibling; + + comp = hwloc_pci_compare_busids(current, new); + assert(comp != HWLOC_PCI_BUSID_SUPERSET); + if (comp == HWLOC_PCI_BUSID_HIGHER) + continue; + assert(comp == HWLOC_PCI_BUSID_INCLUDED); + + /* move this object below the new bridge */ + hwloc_pci_remove_child(root, current); + hwloc_pci_add_object(new, current); + } +} + +static void +hwloc_pci_add_object(struct hwloc_obj *root, struct hwloc_obj *new) +{ + struct hwloc_obj *current; + + current = root->first_child; + while (current) { + enum hwloc_pci_busid_comparison_e comp = hwloc_pci_compare_busids(new, current); + switch (comp) { + case HWLOC_PCI_BUSID_HIGHER: + /* go further */ + current = current->next_sibling; + continue; + case HWLOC_PCI_BUSID_INCLUDED: + /* insert below current bridge */ + hwloc_pci_add_object(current, new); + return; + case HWLOC_PCI_BUSID_LOWER: + case HWLOC_PCI_BUSID_SUPERSET: + /* insert before current object */ + hwloc_pci_add_child_before(root, current, new); + /* walk next siblings and move them below new bridge if needed */ + hwloc_pci_try_insert_siblings_below_new_bridge(root, new); + return; + } + } + /* add to the end of the list if higher than everybody */ + hwloc_pci_add_child_before(root, NULL, new); +} + +static struct hwloc_obj * +hwloc_pci_fixup_hostbridge_parent(struct hwloc_topology *topology __hwloc_attribute_unused, + struct hwloc_obj *hostbridge, + struct hwloc_obj *parent) +{ + /* Xeon E5v3 in cluster-on-die mode only have PCI on the first NUMA node of each package. + * 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", + hostbridge->first_child->attr->pcidev.domain, hostbridge->first_child->attr->pcidev.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", + hostbridge->first_child->attr->pcidev.domain, hostbridge->first_child->attr->pcidev.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; +} + +static struct hwloc_obj * +hwloc_pci_find_hostbridge_parent(struct hwloc_topology *topology, struct hwloc_backend *backend, + struct hwloc_obj *hostbridge) +{ + hwloc_bitmap_t cpuset = hwloc_bitmap_alloc(); + struct hwloc_obj *parent; + const char *env; + int err; + + /* override the cpuset with the environment if given */ + int forced = 0; + char envname[256]; + snprintf(envname, sizeof(envname), "HWLOC_PCI_%04x_%02x_LOCALCPUS", + hostbridge->first_child->attr->pcidev.domain, hostbridge->first_child->attr->pcidev.bus); + env = getenv(envname); + if (env) + /* if env exists but is empty, don't let quirks change what the OS reports */ + forced = 1; + if (env && *env) { + /* force the hostbridge cpuset */ + hwloc_debug("Overriding localcpus using %s in the environment\n", envname); + hwloc_bitmap_sscanf(cpuset, env); + } else { + /* get the hostbridge cpuset by acking the OS backend. + * it's not a PCI device, so we use its first child locality info. + */ + err = hwloc_backends_get_obj_cpuset(backend, hostbridge->first_child, cpuset); + if (err < 0) + /* if we got nothing, assume the hostbridge is attached to the top of hierarchy */ + hwloc_bitmap_copy(cpuset, hwloc_topology_get_topology_cpuset(topology)); + } + + hwloc_debug_bitmap("Attaching hostbridge to cpuset %s\n", cpuset); + + /* restrict to the existing topology cpuset to avoid errors later */ + hwloc_bitmap_and(cpuset, cpuset, hwloc_topology_get_topology_cpuset(topology)); + + /* if the remaining cpuset is empty, take the root */ + if (hwloc_bitmap_iszero(cpuset)) + hwloc_bitmap_copy(cpuset, hwloc_topology_get_topology_cpuset(topology)); + + /* attach the hostbridge now that it contains the right objects */ + parent = hwloc_get_obj_covering_cpuset(topology, cpuset); + /* in the worst case, we got the root object */ + + if (hwloc_bitmap_isequal(cpuset, parent->cpuset)) { + /* this object has the right cpuset, but it could be a cache or so, + * go up as long as the cpuset is the same + */ + while (parent->parent && hwloc_bitmap_isequal(parent->cpuset, parent->parent->cpuset)) + parent = parent->parent; + + if (!forced) + parent = hwloc_pci_fixup_hostbridge_parent(topology, hostbridge, parent); + + } else { + /* the object we found is too large, insert an intermediate group */ + hwloc_obj_t group_obj = hwloc_alloc_setup_object(HWLOC_OBJ_GROUP, -1); + if (group_obj) { + group_obj->cpuset = hwloc_bitmap_dup(cpuset); + group_obj->complete_cpuset = hwloc_bitmap_dup(cpuset); + group_obj->attr->group.depth = (unsigned) -1; + parent = hwloc__insert_object_by_cpuset(topology, group_obj, hwloc_report_os_error); + if (parent == group_obj) + /* if didn't get merged, setup its sets */ + hwloc_fill_object_sets(group_obj); + if (!parent) + /* Failed to insert the parent, maybe a conflicting cpuset, attach to the root object instead */ + parent = hwloc_get_root_obj(topology); + } + } + + hwloc_bitmap_free(cpuset); + + return parent; +} + +int +hwloc_insert_pci_device_list(struct hwloc_backend *backend, + struct hwloc_obj *first_obj) +{ + struct hwloc_topology *topology = backend->topology; + struct hwloc_obj fakeparent; + struct hwloc_obj *obj; + unsigned current_hostbridge; + + if (!first_obj) + /* found nothing, exit */ + return 0; + + /* first, organise object as tree under a fake parent object */ + fakeparent.parent = NULL; + fakeparent.first_child = NULL; + fakeparent.last_child = NULL; + while (first_obj) { + obj = first_obj; + first_obj = obj->next_sibling; + hwloc_pci_add_object(&fakeparent, obj); + } + +#ifdef HWLOC_DEBUG + hwloc_debug("%s", "\nPCI hierarchy under fake parent:\n"); + hwloc_pci_traverse(NULL, &fakeparent, hwloc_pci_traverse_print_cb); + hwloc_debug("%s", "\n"); +#endif + + /* walk the hierarchy, and lookup OS devices */ + hwloc_pci_traverse(backend, &fakeparent, hwloc_pci_traverse_lookuposdevices_cb); + + /* + * fakeparent lists all objects connected to any upstream bus in the machine. + * We now create one real hostbridge object per upstream bus. + * It's not actually a PCI device so we have to create it. + */ + current_hostbridge = 0; + while (fakeparent.first_child) { + /* start a new host bridge */ + struct hwloc_obj *hostbridge = hwloc_alloc_setup_object(HWLOC_OBJ_BRIDGE, current_hostbridge++); + struct hwloc_obj *child = fakeparent.first_child; + struct hwloc_obj *next_child; + struct hwloc_obj *parent; + unsigned short current_domain = child->attr->pcidev.domain; + unsigned char current_bus = child->attr->pcidev.bus; + unsigned char current_subordinate = current_bus; + + hwloc_debug("Starting new PCI hostbridge %04x:%02x\n", current_domain, current_bus); + + /* + * attach all objects from the same upstream domain/bus + */ + next_child: + next_child = child->next_sibling; + hwloc_pci_remove_child(&fakeparent, child); + hwloc_pci_add_child_before(hostbridge, NULL, child); + + /* compute hostbridge secondary/subordinate buses */ + if (child->type == HWLOC_OBJ_BRIDGE + && child->attr->bridge.downstream.pci.subordinate_bus > current_subordinate) + current_subordinate = child->attr->bridge.downstream.pci.subordinate_bus; + + /* use next child if it has the same domains/bus */ + child = next_child; + if (child + && child->attr->pcidev.domain == current_domain + && child->attr->pcidev.bus == current_bus) + goto next_child; + + /* finish setting up this hostbridge */ + hostbridge->attr->bridge.upstream_type = HWLOC_OBJ_BRIDGE_HOST; + hostbridge->attr->bridge.downstream_type = HWLOC_OBJ_BRIDGE_PCI; + hostbridge->attr->bridge.downstream.pci.domain = current_domain; + hostbridge->attr->bridge.downstream.pci.secondary_bus = current_bus; + hostbridge->attr->bridge.downstream.pci.subordinate_bus = current_subordinate; + hwloc_debug("New PCI hostbridge %04x:[%02x-%02x]\n", + current_domain, current_bus, current_subordinate); + + /* attach the hostbridge where it belongs */ + parent = hwloc_pci_find_hostbridge_parent(topology, backend, hostbridge); + hwloc_insert_object_by_parent(topology, parent, hostbridge); + } + + return 1; +} + +#define HWLOC_PCI_STATUS 0x06 +#define HWLOC_PCI_STATUS_CAP_LIST 0x10 +#define HWLOC_PCI_CAPABILITY_LIST 0x34 +#define HWLOC_PCI_CAP_LIST_ID 0 +#define HWLOC_PCI_CAP_LIST_NEXT 1 + +unsigned +hwloc_pci_find_cap(const unsigned char *config, unsigned cap) +{ + unsigned char seen[256] = { 0 }; + unsigned char ptr; /* unsigned char to make sure we stay within the 256-byte config space */ + + if (!(config[HWLOC_PCI_STATUS] & HWLOC_PCI_STATUS_CAP_LIST)) + return 0; + + for (ptr = config[HWLOC_PCI_CAPABILITY_LIST] & ~3; + ptr; /* exit if next is 0 */ + ptr = config[ptr + HWLOC_PCI_CAP_LIST_NEXT] & ~3) { + unsigned char id; + + /* Looped around! */ + if (seen[ptr]) + break; + seen[ptr] = 1; + + id = config[ptr + HWLOC_PCI_CAP_LIST_ID]; + if (id == cap) + return ptr; + if (id == 0xff) /* exit if id is 0 or 0xff */ + break; + } + return 0; +} + +#define HWLOC_PCI_EXP_LNKSTA 0x12 +#define HWLOC_PCI_EXP_LNKSTA_SPEED 0x000f +#define HWLOC_PCI_EXP_LNKSTA_WIDTH 0x03f0 + +int +hwloc_pci_find_linkspeed(const unsigned char *config, + unsigned offset, float *linkspeed) +{ + unsigned linksta, speed, width; + float lanespeed; + + memcpy(&linksta, &config[offset + HWLOC_PCI_EXP_LNKSTA], 4); + speed = linksta & HWLOC_PCI_EXP_LNKSTA_SPEED; /* PCIe generation */ + width = (linksta & HWLOC_PCI_EXP_LNKSTA_WIDTH) >> 4; /* how many lanes */ + /* PCIe Gen1 = 2.5GT/s signal-rate per lane with 8/10 encoding = 0.25GB/s data-rate per lane + * PCIe Gen2 = 5 GT/s signal-rate per lane with 8/10 encoding = 0.5 GB/s data-rate per lane + * PCIe Gen3 = 8 GT/s signal-rate per lane with 128/130 encoding = 1 GB/s data-rate per lane + */ + lanespeed = speed <= 2 ? 2.5 * speed * 0.8 : 8.0 * 128/130; /* Gbit/s per lane */ + *linkspeed = lanespeed * width / 8; /* GB/s */ + return 0; +} + +#define HWLOC_PCI_HEADER_TYPE 0x0e +#define HWLOC_PCI_HEADER_TYPE_BRIDGE 1 +#define HWLOC_PCI_CLASS_BRIDGE_PCI 0x0604 +#define HWLOC_PCI_PRIMARY_BUS 0x18 +#define HWLOC_PCI_SECONDARY_BUS 0x19 +#define HWLOC_PCI_SUBORDINATE_BUS 0x1a + +int +hwloc_pci_prepare_bridge(hwloc_obj_t obj, + const unsigned char *config) +{ + unsigned char headertype; + unsigned isbridge; + struct hwloc_pcidev_attr_s *pattr = &obj->attr->pcidev; + struct hwloc_bridge_attr_s *battr; + + headertype = config[HWLOC_PCI_HEADER_TYPE] & 0x7f; + isbridge = (pattr->class_id == HWLOC_PCI_CLASS_BRIDGE_PCI + && headertype == HWLOC_PCI_HEADER_TYPE_BRIDGE); + + if (!isbridge) + return 0; + + battr = &obj->attr->bridge; + + if (config[HWLOC_PCI_PRIMARY_BUS] != pattr->bus) + hwloc_debug(" %04x:%02x:%02x.%01x bridge with (ignored) invalid PCI_PRIMARY_BUS %02x\n", + pattr->domain, pattr->bus, pattr->dev, pattr->func, config[HWLOC_PCI_PRIMARY_BUS]); + + obj->type = HWLOC_OBJ_BRIDGE; + battr->upstream_type = HWLOC_OBJ_BRIDGE_PCI; + battr->downstream_type = HWLOC_OBJ_BRIDGE_PCI; + battr->downstream.pci.domain = pattr->domain; + battr->downstream.pci.secondary_bus = config[HWLOC_PCI_SECONDARY_BUS]; + battr->downstream.pci.subordinate_bus = config[HWLOC_PCI_SUBORDINATE_BUS]; + + return 0; +} diff --git a/opal/mca/hwloc/hwloc1110/hwloc/src/topology-aix.c b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-aix.c new file mode 100644 index 0000000000..1b98ba6b92 --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-aix.c @@ -0,0 +1,872 @@ +/* + * Copyright © 2009 CNRS + * Copyright © 2009-2015 Inria. All rights reserved. + * Copyright © 2009-2011, 2013 Université Bordeaux + * Copyright © 2011 Cisco Systems, Inc. All rights reserved. + * See COPYING in top-level directory. + */ + +/* TODO: use SIGRECONFIG & dr_reconfig for state change */ + +#include + +#include +#ifdef HAVE_DIRENT_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifndef __power_pc +#define __power_pc() 0 +#endif +#ifndef __power_4 +#define __power_4() 0 +#endif +#ifndef __power_5 +#define __power_5() 0 +#endif +#ifndef __power_6 +#define __power_6() 0 +#endif +#ifndef __power_7 +#define __power_7() 0 +#endif + +static int +hwloc_aix_set_sth_cpubind(hwloc_topology_t topology, rstype_t what, rsid_t who, pid_t pid, hwloc_const_bitmap_t hwloc_set, int flags __hwloc_attribute_unused) +{ + rsethandle_t rad; + int res; + unsigned cpu; + + if (flags & HWLOC_CPUBIND_NOMEMBIND) { + errno = ENOSYS; + return -1; + } + + /* The resulting binding is always strict */ + + if (hwloc_bitmap_isequal(hwloc_set, hwloc_topology_get_complete_cpuset(topology))) { + if (ra_detachrset(what, who, 0)) + return -1; + return 0; + } + + rad = rs_alloc(RS_EMPTY); + hwloc_bitmap_foreach_begin(cpu, hwloc_set) + rs_op(RS_ADDRESOURCE, rad, NULL, R_PROCS, cpu); + hwloc_bitmap_foreach_end(); + + res = ra_attachrset(what, who, rad, 0); + if (res < 0 && errno == EPERM) { + /* EPERM may mean that one thread has ben bound with bindprocessor(). + * Unbind the entire process (we can't unbind individual threads) + * and try again. + */ + bindprocessor(BINDPROCESS, pid, PROCESSOR_CLASS_ANY); + res = ra_attachrset(what, who, rad, 0); + } + + rs_free(rad); + return res; +} + +static int +hwloc_aix_get_sth_rset_cpubind(hwloc_topology_t topology, rstype_t what, rsid_t who, hwloc_bitmap_t hwloc_set, int flags __hwloc_attribute_unused, int *boundp) +{ + rsethandle_t rset; + unsigned cpu, maxcpus; + int res = -1; + int bound = 0; + + rset = rs_alloc(RS_EMPTY); + + if (ra_getrset(what, who, 0, rset) == -1) + goto out; + + hwloc_bitmap_zero(hwloc_set); + maxcpus = rs_getinfo(rset, R_MAXPROCS, 0); + for (cpu = 0; cpu < maxcpus; cpu++) + if (rs_op(RS_TESTRESOURCE, rset, NULL, R_PROCS, cpu) == 1) + hwloc_bitmap_set(hwloc_set, cpu); + else + bound = 1; + hwloc_bitmap_and(hwloc_set, hwloc_set, hwloc_topology_get_complete_cpuset(topology)); + res = 0; + *boundp = bound; + +out: + rs_free(rset); + return res; +} + +static int +hwloc_aix_get_pid_getthrds_cpubind(hwloc_topology_t topology __hwloc_attribute_unused, pid_t pid, hwloc_bitmap_t hwloc_set, int flags __hwloc_attribute_unused) +{ +#if HWLOC_BITS_PER_LONG == 64 + struct thrdentry64 thread_info; + tid64_t next_thread; +#else + struct thrdsinfo thread_info; + tid_t next_thread; +#endif + + next_thread = 0; + /* TODO: get multiple at once */ +#if HWLOC_BITS_PER_LONG == 64 + while (getthrds64 (pid, &thread_info, sizeof (thread_info), + &next_thread, 1) == 1) { +#else + while (getthrds (pid, &thread_info, sizeof (thread_info), + &next_thread, 1) == 1) { +#endif + if (PROCESSOR_CLASS_ANY != thread_info.ti_cpuid) + hwloc_bitmap_set(hwloc_set, thread_info.ti_cpuid); + else + hwloc_bitmap_fill(hwloc_set); + } + /* TODO: what if the thread list changes and we get nothing? */ + + return 0; +} + +static int +hwloc_aix_get_tid_getthrds_cpubind(hwloc_topology_t topology __hwloc_attribute_unused, tid_t tid, hwloc_bitmap_t hwloc_set, int flags __hwloc_attribute_unused) +{ +#if HWLOC_BITS_PER_LONG == 64 + struct thrdentry64 thread_info; + tid64_t next_thread; +#else + struct thrdsinfo thread_info; + tid_t next_thread; +#endif + pid_t pid = getpid(); + + next_thread = 0; + /* TODO: get multiple at once */ +#if HWLOC_BITS_PER_LONG == 64 + while (getthrds64 (pid, &thread_info, sizeof (thread_info), + &next_thread, 1) == 1) { +#else + while (getthrds (pid, &thread_info, sizeof (thread_info), + &next_thread, 1) == 1) { +#endif + if (thread_info.ti_tid == tid) { + if (PROCESSOR_CLASS_ANY != thread_info.ti_cpuid) + hwloc_bitmap_set(hwloc_set, thread_info.ti_cpuid); + else + hwloc_bitmap_fill(hwloc_set); + break; + } + } + /* TODO: what if the thread goes away in the meantime? */ + + return 0; +} + +static int +hwloc_aix_set_thisproc_cpubind(hwloc_topology_t topology, hwloc_const_bitmap_t hwloc_set, int flags) +{ + rsid_t who; + who.at_pid = getpid(); + return hwloc_aix_set_sth_cpubind(topology, R_PROCESS, who, who.at_pid, hwloc_set, flags); +} + +static int +hwloc_aix_get_thisproc_cpubind(hwloc_topology_t topology, hwloc_bitmap_t hwloc_set, int flags) +{ + int ret, bound; + rsid_t who; + who.at_pid = getpid(); + ret = hwloc_aix_get_sth_rset_cpubind(topology, R_PROCESS, who, hwloc_set, flags, &bound); + if (!ret && !bound) { + hwloc_bitmap_zero(hwloc_set); + ret = hwloc_aix_get_pid_getthrds_cpubind(topology, who.at_pid, hwloc_set, flags); + } + return ret; +} + +#ifdef R_THREAD +static int +hwloc_aix_set_thisthread_cpubind(hwloc_topology_t topology, hwloc_const_bitmap_t hwloc_set, int flags) +{ + rsid_t who; + who.at_tid = thread_self(); + return hwloc_aix_set_sth_cpubind(topology, R_THREAD, who, getpid(), hwloc_set, flags); +} + +static int +hwloc_aix_get_thisthread_cpubind(hwloc_topology_t topology, hwloc_bitmap_t hwloc_set, int flags) +{ + int ret, bound; + rsid_t who; + who.at_tid = thread_self(); + ret = hwloc_aix_get_sth_rset_cpubind(topology, R_THREAD, who, hwloc_set, flags, &bound); + if (!ret && !bound) { + hwloc_bitmap_zero(hwloc_set); + ret = hwloc_aix_get_tid_getthrds_cpubind(topology, who.at_tid, hwloc_set, flags); + } + return ret; +} +#endif /* R_THREAD */ + +static int +hwloc_aix_set_proc_cpubind(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_const_bitmap_t hwloc_set, int flags) +{ + rsid_t who; + who.at_pid = pid; + return hwloc_aix_set_sth_cpubind(topology, R_PROCESS, who, pid, hwloc_set, flags); +} + +static int +hwloc_aix_get_proc_cpubind(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_bitmap_t hwloc_set, int flags) +{ + int ret, bound; + rsid_t who; + who.at_pid = pid; + ret = hwloc_aix_get_sth_rset_cpubind(topology, R_PROCESS, who, hwloc_set, flags, &bound); + if (!ret && !bound) { + hwloc_bitmap_zero(hwloc_set); + ret = hwloc_aix_get_pid_getthrds_cpubind(topology, who.at_pid, hwloc_set, flags); + } + return ret; +} + +#ifdef R_THREAD +#ifdef HWLOC_HAVE_PTHREAD_GETTHRDS_NP +static int +hwloc_aix_set_thread_cpubind(hwloc_topology_t topology, hwloc_thread_t pthread, hwloc_const_bitmap_t hwloc_set, int flags) +{ + struct __pthrdsinfo info; + int size; + if ((errno = pthread_getthrds_np(&pthread, PTHRDSINFO_QUERY_TID, &info, sizeof(info), NULL, &size))) + return -1; + { + rsid_t who; + who.at_tid = info.__pi_tid; + return hwloc_aix_set_sth_cpubind(topology, R_THREAD, who, getpid(), hwloc_set, flags); + } +} + +static int +hwloc_aix_get_thread_cpubind(hwloc_topology_t topology, hwloc_thread_t pthread, hwloc_bitmap_t hwloc_set, int flags) +{ + struct __pthrdsinfo info; + int size; + if (pthread_getthrds_np(&pthread, PTHRDSINFO_QUERY_TID, &info, sizeof(info), NULL, &size)) + return -1; + { + int ret, bound; + rsid_t who; + who.at_tid = info.__pi_tid; + ret = hwloc_aix_get_sth_rset_cpubind(topology, R_THREAD, who, hwloc_set, flags, &bound); + if (!ret && !bound) { + hwloc_bitmap_zero(hwloc_set); + ret = hwloc_aix_get_tid_getthrds_cpubind(topology, who.at_tid, hwloc_set, flags); + } + return ret; + } +} +#endif /* HWLOC_HAVE_PTHREAD_GETTHRDS_NP */ +#endif /* R_THREAD */ + +static int +hwloc_aix_get_thisthread_last_cpu_location(hwloc_topology_t topology, hwloc_bitmap_t hwloc_set, int flags __hwloc_attribute_unused) +{ + cpu_t cpu; + + if (topology->pid) { + errno = ENOSYS; + return -1; + } + + cpu = mycpu(); + if (cpu < 0) + return -1; + + hwloc_bitmap_only(hwloc_set, cpu); + return 0; +} + +#ifdef P_DEFAULT + +static int +hwloc_aix_membind_policy_from_hwloc(uint_t *aix_policy, int policy) +{ + switch (policy) { + case HWLOC_MEMBIND_DEFAULT: + case HWLOC_MEMBIND_BIND: + *aix_policy = P_DEFAULT; + break; + case HWLOC_MEMBIND_FIRSTTOUCH: + *aix_policy = P_FIRST_TOUCH; + break; + case HWLOC_MEMBIND_INTERLEAVE: + *aix_policy = P_BALANCED; + break; + default: + errno = ENOSYS; + return -1; + } + return 0; +} + +static int +hwloc_aix_prepare_membind(hwloc_topology_t topology, rsethandle_t *rad, hwloc_const_nodeset_t nodeset, int flags __hwloc_attribute_unused) +{ + rsethandle_t rset, noderad; + int MCMlevel; + int node; + + MCMlevel = rs_getinfo(NULL, R_MCMSDL, 0); + if ((topology->flags & HWLOC_TOPOLOGY_FLAG_WHOLE_SYSTEM)) + rset = rs_alloc(RS_ALL); + else + rset = rs_alloc(RS_PARTITION); + *rad = rs_alloc(RS_EMPTY); + noderad = rs_alloc(RS_EMPTY); + + hwloc_bitmap_foreach_begin(node, nodeset) + /* we used MCMlevel rad number for node->os_index during lookup */ + rs_getrad(rset, noderad, MCMlevel, node, 0); + rs_op(RS_UNION, noderad, *rad, 0, 0); + hwloc_bitmap_foreach_end(); + + rs_free(rset); + rs_free(noderad); + + return 0; +} + +static int +hwloc_aix_set_sth_membind(hwloc_topology_t topology, rstype_t what, rsid_t who, pid_t pid, hwloc_const_bitmap_t nodeset, hwloc_membind_policy_t policy, int flags) +{ + rsethandle_t rad; + int res; + + if (flags & HWLOC_MEMBIND_NOCPUBIND) { + errno = ENOSYS; + return -1; + } + + switch (policy) { + case HWLOC_MEMBIND_DEFAULT: + case HWLOC_MEMBIND_BIND: + break; + default: + errno = ENOSYS; + return -1; + } + + if (hwloc_aix_prepare_membind(topology, &rad, nodeset, flags)) + return -1; + + res = ra_attachrset(what, who, rad, 0); + if (res < 0 && errno == EPERM) { + /* EPERM may mean that one thread has ben bound with bindprocessor(). + * Unbind the entire process (we can't unbind individual threads) + * and try again. + */ + bindprocessor(BINDPROCESS, pid, PROCESSOR_CLASS_ANY); + res = ra_attachrset(what, who, rad, 0); + } + + rs_free(rad); + return res; +} + +static int +hwloc_aix_get_sth_membind(hwloc_topology_t topology, rstype_t what, rsid_t who, hwloc_bitmap_t nodeset, hwloc_membind_policy_t *policy, int flags __hwloc_attribute_unused) +{ + hwloc_bitmap_t hwloc_set; + rsethandle_t rset; + unsigned cpu, maxcpus; + int res = -1; + int depth, n, i; + + depth = hwloc_get_type_depth(topology, HWLOC_OBJ_NUMANODE); + if (depth < 0) { + errno = EXDEV; + return -1; + } + n = hwloc_get_nbobjs_by_depth(topology, depth); + + rset = rs_alloc(RS_EMPTY); + + if (ra_getrset(what, who, 0, rset) == -1) + goto out; + + hwloc_set = hwloc_bitmap_alloc(); + + maxcpus = rs_getinfo(rset, R_MAXPROCS, 0); + for (cpu = 0; cpu < maxcpus; cpu++) + if (rs_op(RS_TESTRESOURCE, rset, NULL, R_PROCS, cpu) == 1) + hwloc_bitmap_set(hwloc_set, cpu); + hwloc_bitmap_and(hwloc_set, hwloc_set, hwloc_topology_get_complete_cpuset(topology)); + + hwloc_bitmap_zero(nodeset); + for (i = 0; i < n; i++) { + hwloc_obj_t obj = hwloc_get_obj_by_depth(topology, depth, i); + if (hwloc_bitmap_isincluded(obj->cpuset, hwloc_set)) + hwloc_bitmap_set(nodeset, obj->os_index); + } + + hwloc_bitmap_free(hwloc_set); + + *policy = HWLOC_MEMBIND_DEFAULT; + res = 0; + +out: + rs_free(rset); + return res; +} + +static int +hwloc_aix_set_thisproc_membind(hwloc_topology_t topology, hwloc_const_bitmap_t hwloc_set, hwloc_membind_policy_t policy, int flags) +{ + rsid_t who; + who.at_pid = getpid(); + return hwloc_aix_set_sth_membind(topology, R_PROCESS, who, who.at_pid, hwloc_set, policy, flags); +} + +static int +hwloc_aix_get_thisproc_membind(hwloc_topology_t topology, hwloc_bitmap_t hwloc_set, hwloc_membind_policy_t *policy, int flags) +{ + rsid_t who; + who.at_pid = getpid(); + return hwloc_aix_get_sth_membind(topology, R_PROCESS, who, hwloc_set, policy, flags); +} + +#ifdef R_THREAD +static int +hwloc_aix_set_thisthread_membind(hwloc_topology_t topology, hwloc_const_bitmap_t hwloc_set, hwloc_membind_policy_t policy, int flags) +{ + rsid_t who; + who.at_tid = thread_self(); + return hwloc_aix_set_sth_membind(topology, R_THREAD, who, getpid(), hwloc_set, policy, flags); +} + +static int +hwloc_aix_get_thisthread_membind(hwloc_topology_t topology, hwloc_bitmap_t hwloc_set, hwloc_membind_policy_t *policy, int flags) +{ + rsid_t who; + who.at_tid = thread_self(); + return hwloc_aix_get_sth_membind(topology, R_THREAD, who, hwloc_set, policy, flags); +} +#endif /* R_THREAD */ + +static int +hwloc_aix_set_proc_membind(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_const_bitmap_t hwloc_set, hwloc_membind_policy_t policy, int flags) +{ + rsid_t who; + who.at_pid = pid; + return hwloc_aix_set_sth_membind(topology, R_PROCESS, who, pid, hwloc_set, policy, flags); +} + +static int +hwloc_aix_get_proc_membind(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_bitmap_t hwloc_set, hwloc_membind_policy_t *policy, int flags) +{ + rsid_t who; + who.at_pid = pid; + return hwloc_aix_get_sth_membind(topology, R_PROCESS, who, hwloc_set, policy, flags); +} + +#ifdef R_THREAD +#if 0 /* def HWLOC_HAVE_PTHREAD_GETTHRDS_NP */ +static int +hwloc_aix_set_thread_membind(hwloc_topology_t topology, hwloc_thread_t pthread, hwloc_const_bitmap_t hwloc_set, hwloc_membind_policy_t policy, int flags) +{ + struct __pthrdsinfo info; + int size; + if ((errno = pthread_getthrds_np(&pthread, PTHRDSINFO_QUERY_TID, &info, sizeof(info), NULL, &size))) + return -1; + { + rsid_t who; + who.at_tid = info.__pi_tid; + return hwloc_aix_set_sth_membind(topology, R_THREAD, who, getpid(), hwloc_set, policy, flags); + } +} + +static int +hwloc_aix_get_thread_membind(hwloc_topology_t topology, hwloc_thread_t pthread, hwloc_bitmap_t hwloc_set, hwloc_membind_policy_t *policy, int flags) +{ + struct __pthrdsinfo info; + int size; + if (pthread_getthrds_np(&pthread, PTHRDSINFO_QUERY_TID, &info, sizeof(info), NULL, &size)) + return -1; + { + rsid_t who; + who.at_tid = info.__pi_tid; + return hwloc_aix_get_sth_membind(topology, R_THREAD, who, hwloc_set, policy, flags); + } +} +#endif /* HWLOC_HAVE_PTHREAD_GETTHRDS_NP */ +#endif /* R_THREAD */ + +#if 0 +/* TODO: seems to be right, but doesn't seem to be working (EINVAL), even after + * aligning the range on 64K... */ +static int +hwloc_aix_set_area_membind(hwloc_topology_t topology, const void *addr, size_t len, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags) +{ + subrange_t subrange; + rsid_t rsid = { .at_subrange = &subrange }; + uint_t aix_policy; + int ret; + fprintf(stderr,"yop\n"); + + if ((flags & (HWLOC_MEMBIND_MIGRATE|HWLOC_MEMBIND_STRICT)) + == (HWLOC_MEMBIND_MIGRATE|HWLOC_MEMBIND_STRICT)) { + errno = ENOSYS; + return -1; + } + + subrange.su_offset = (uintptr_t) addr; + subrange.su_length = len; + subrange.su_rstype = R_RSET; + + if (hwloc_aix_membind_policy_from_hwloc(&aix_policy, policy)) + return -1; + + if (hwloc_aix_prepare_membind(topology, &subrange.su_rsid.at_rset, nodeset, flags)) + return -1; + + subrange.su_policy = aix_policy; + + res = ra_attachrset(R_SUBRANGE, rsid, subrange.su_rsid.at_rset, 0); + if (res < 0 && errno == EPERM) { + /* EPERM may mean that one thread has ben bound with bindprocessor(). + * Unbind the entire process (we can't unbind individual threads) + * and try again. + * FIXME: actually check that this EPERM can happen + */ + bindprocessor(BINDPROCESS, getpid(), PROCESSOR_CLASS_ANY); + res = ra_attachrset(R_SUBRANGE, rsid, subrange.su_rsid.at_rset, 0); + } + + rs_free(subrange.su_rsid.at_rset); + return ret; +} +#endif + +static void * +hwloc_aix_alloc_membind(hwloc_topology_t topology, size_t len, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags) +{ + void *ret; + rsid_t rsid; + uint_t aix_policy; + + if (hwloc_aix_membind_policy_from_hwloc(&aix_policy, policy)) + return hwloc_alloc_or_fail(topology, len, flags); + + if (hwloc_aix_prepare_membind(topology, &rsid.at_rset, nodeset, flags)) + return hwloc_alloc_or_fail(topology, len, flags); + + ret = ra_mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0, R_RSET, rsid, aix_policy); + + rs_free(rsid.at_rset); + return ret; +} +#endif /* P_DEFAULT */ + +static void +look_rset(int sdl, hwloc_obj_type_t type, struct hwloc_topology *topology, int level) +{ + rsethandle_t rset, rad; + int i,maxcpus,j; + int nbnodes; + struct hwloc_obj *obj; + + if ((topology->flags & HWLOC_TOPOLOGY_FLAG_WHOLE_SYSTEM)) + rset = rs_alloc(RS_ALL); + else + rset = rs_alloc(RS_PARTITION); + rad = rs_alloc(RS_EMPTY); + nbnodes = rs_numrads(rset, sdl, 0); + if (nbnodes == -1) { + perror("rs_numrads"); + return; + } + + for (i = 0; i < nbnodes; i++) { + hwloc_bitmap_t cpuset; + unsigned os_index = (unsigned) -1; /* no os_index except for PU and NUMANODE below */ + + if (rs_getrad(rset, rad, sdl, i, 0)) { + fprintf(stderr,"rs_getrad(%d) failed: %s\n", i, strerror(errno)); + continue; + } + if (!rs_getinfo(rad, R_NUMPROCS, 0)) + continue; + + maxcpus = rs_getinfo(rad, R_MAXPROCS, 0); + cpuset = hwloc_bitmap_alloc(); + for (j = 0; j < maxcpus; j++) { + if (rs_op(RS_TESTRESOURCE, rad, NULL, R_PROCS, j)) + hwloc_bitmap_set(cpuset, j); + } + + if (type == HWLOC_OBJ_PU) { + os_index = hwloc_bitmap_first(cpuset); + hwloc_debug("Found PU #%u inside node %d for sdl %d\n", os_index, i, sdl); + assert(hwloc_bitmap_weight(cpuset) == 1); + } else if (type == HWLOC_OBJ_NUMANODE) { + /* NUMA node os_index isn't used for binding, just use the rad number to get unique values. + * Note that we'll use that fact in hwloc_aix_prepare_membind(). */ + os_index = i; + hwloc_debug("Using os_index #%u for NUMA node inside node %d for sdl %d\n", os_index, i, sdl); + } + + obj = hwloc_alloc_setup_object(type, os_index); + obj->cpuset = cpuset; + obj->os_level = sdl; + + switch(type) { + case HWLOC_OBJ_NUMANODE: + obj->nodeset = hwloc_bitmap_alloc(); + hwloc_bitmap_set(obj->nodeset, i); + obj->memory.local_memory = 0; /* TODO: odd, rs_getinfo(rad, R_MEMSIZE, 0) << 10 returns the total memory ... */ + obj->memory.page_types_len = 2; + obj->memory.page_types = malloc(2*sizeof(*obj->memory.page_types)); + memset(obj->memory.page_types, 0, 2*sizeof(*obj->memory.page_types)); + obj->memory.page_types[0].size = hwloc_getpagesize(); +#ifdef HAVE__SC_LARGE_PAGESIZE + obj->memory.page_types[1].size = sysconf(_SC_LARGE_PAGESIZE); +#endif + /* TODO: obj->memory.page_types[1].count = rs_getinfo(rset, R_LGPGFREE, 0) / hugepagesize */ + break; + case HWLOC_OBJ_CACHE: + obj->attr->cache.size = _system_configuration.L2_cache_size; + obj->attr->cache.associativity = _system_configuration.L2_cache_asc; + + obj->attr->cache.linesize = 0; /* unknown by default */ + if (__power_pc()) + if (__power_4() || __power_5() || __power_6() || __power_7()) + obj->attr->cache.linesize = 128; + + obj->attr->cache.depth = 2; + obj->attr->cache.type = HWLOC_OBJ_CACHE_UNIFIED; /* OK for power[4567], unknown for others */ + break; + case HWLOC_OBJ_GROUP: + obj->attr->group.depth = level; + break; + case HWLOC_OBJ_CORE: + { + hwloc_obj_t obj2, obj3; + obj2 = hwloc_alloc_setup_object(HWLOC_OBJ_CACHE, i); + obj2->cpuset = hwloc_bitmap_dup(obj->cpuset); + obj2->attr->cache.size = _system_configuration.dcache_size; + obj2->attr->cache.associativity = _system_configuration.dcache_asc; + obj2->attr->cache.linesize = _system_configuration.dcache_line; + obj2->attr->cache.depth = 1; + if (_system_configuration.cache_attrib & (1<<30)) { + /* Unified cache */ + obj2->attr->cache.type = HWLOC_OBJ_CACHE_UNIFIED; + hwloc_debug("Adding an L1u cache for core %d\n", i); + hwloc_insert_object_by_cpuset(topology, obj2); + } else { + /* Separate Instruction and Data caches */ + obj2->attr->cache.type = HWLOC_OBJ_CACHE_DATA; + hwloc_debug("Adding an L1d cache for core %d\n", i); + hwloc_insert_object_by_cpuset(topology, obj2); + + obj3 = hwloc_alloc_setup_object(HWLOC_OBJ_CACHE, i); + obj3->cpuset = hwloc_bitmap_dup(obj->cpuset); + obj3->attr->cache.size = _system_configuration.icache_size; + obj3->attr->cache.associativity = _system_configuration.icache_asc; + obj3->attr->cache.linesize = _system_configuration.icache_line; + obj3->attr->cache.depth = 1; + obj3->attr->cache.type = HWLOC_OBJ_CACHE_INSTRUCTION; + hwloc_debug("Adding an L1i cache for core %d\n", i); + hwloc_insert_object_by_cpuset(topology, obj3); + } + break; + } + default: + break; + } + hwloc_debug_2args_bitmap("%s %d has cpuset %s\n", + hwloc_obj_type_string(type), + i, obj->cpuset); + hwloc_insert_object_by_cpuset(topology, obj); + } + + rs_free(rset); + rs_free(rad); +} + +static int +hwloc_look_aix(struct hwloc_backend *backend) +{ + struct hwloc_topology *topology = backend->topology; + int i; + + if (topology->levels[0][0]->cpuset) + /* somebody discovered things */ + return 0; + + hwloc_alloc_obj_cpusets(topology->levels[0][0]); + + /* TODO: R_LGPGDEF/R_LGPGFREE for large pages */ + + hwloc_debug("Note: SMPSDL is at %d\n", rs_getinfo(NULL, R_SMPSDL, 0)); +#ifdef R_REF1SDL + hwloc_debug("Note: REF1SDL is at %d\n", rs_getinfo(NULL, R_REF1SDL, 0)); +#endif + + for (i=0; i<=rs_getinfo(NULL, R_MAXSDL, 0); i++) + { + int known = 0; +#if 0 + if (i == rs_getinfo(NULL, R_SMPSDL, 0)) + /* Not enabled for now because I'm not sure what it corresponds to. On + * decrypthon it contains all the cpus. Is it a "machine" or a "system" + * level ? + */ + { + hwloc_debug("looking AIX \"SMP\" sdl %d\n", i); + look_rset(i, HWLOC_OBJ_MACHINE, topology, i); + known = 1; + } +#endif + if (i == rs_getinfo(NULL, R_MCMSDL, 0)) + { + hwloc_debug("looking AIX node sdl %d\n", i); + look_rset(i, HWLOC_OBJ_NUMANODE, topology, i); + known = 1; + } +# ifdef R_L2CSDL + if (i == rs_getinfo(NULL, R_L2CSDL, 0)) + { + hwloc_debug("looking AIX L2 sdl %d\n", i); + look_rset(i, HWLOC_OBJ_CACHE, topology, i); + known = 1; + } +# endif +# ifdef R_PCORESDL + if (i == rs_getinfo(NULL, R_PCORESDL, 0)) + { + hwloc_debug("looking AIX core sdl %d\n", i); + look_rset(i, HWLOC_OBJ_CORE, topology, i); + known = 1; + } +# endif + if (i == rs_getinfo(NULL, R_MAXSDL, 0)) + { + hwloc_debug("looking AIX max sdl %d\n", i); + look_rset(i, HWLOC_OBJ_PU, topology, i); + known = 1; + topology->support.discovery->pu = 1; + } + + /* Don't know how it should be rendered, make a misc object for it. */ + if (!known) + { + hwloc_debug("looking AIX unknown sdl %d\n", i); + look_rset(i, HWLOC_OBJ_GROUP, topology, i); + } + } + + hwloc_obj_add_info(topology->levels[0][0], "Backend", "AIX"); + if (topology->is_thissystem) + hwloc_add_uname_info(topology, NULL); + return 1; +} + +void +hwloc_set_aix_hooks(struct hwloc_binding_hooks *hooks, + struct hwloc_topology_support *support __hwloc_attribute_unused) +{ + hooks->set_proc_cpubind = hwloc_aix_set_proc_cpubind; + hooks->get_proc_cpubind = hwloc_aix_get_proc_cpubind; +#ifdef R_THREAD +#ifdef HWLOC_HAVE_PTHREAD_GETTHRDS_NP + hooks->set_thread_cpubind = hwloc_aix_set_thread_cpubind; + hooks->get_thread_cpubind = hwloc_aix_get_thread_cpubind; +#endif /* HWLOC_HAVE_PTHREAD_GETTHRDS_NP */ +#endif /* R_THREAD */ + hooks->set_thisproc_cpubind = hwloc_aix_set_thisproc_cpubind; + hooks->get_thisproc_cpubind = hwloc_aix_get_thisproc_cpubind; +#ifdef R_THREAD + hooks->set_thisthread_cpubind = hwloc_aix_set_thisthread_cpubind; + hooks->get_thisthread_cpubind = hwloc_aix_get_thisthread_cpubind; +#endif /* R_THREAD */ + hooks->get_thisthread_last_cpu_location = hwloc_aix_get_thisthread_last_cpu_location; + /* TODO: get_last_cpu_location: mycpu() only works for the current thread? */ +#ifdef P_DEFAULT + hooks->set_proc_membind = hwloc_aix_set_proc_membind; + hooks->get_proc_membind = hwloc_aix_get_proc_membind; +#ifdef R_THREAD +#if 0 /* def HWLOC_HAVE_PTHREAD_GETTHRDS_NP */ + /* Does it really make sense to set the memory binding of another thread? */ + hooks->set_thread_membind = hwloc_aix_set_thread_membind; + hooks->get_thread_membind = hwloc_aix_get_thread_membind; +#endif /* HWLOC_HAVE_PTHREAD_GETTHRDS_NP */ +#endif /* R_THREAD */ + hooks->set_thisproc_membind = hwloc_aix_set_thisproc_membind; + hooks->get_thisproc_membind = hwloc_aix_get_thisproc_membind; +#ifdef R_THREAD + hooks->set_thisthread_membind = hwloc_aix_set_thisthread_membind; + hooks->get_thisthread_membind = hwloc_aix_get_thisthread_membind; +#endif /* R_THREAD */ + /* hooks->set_area_membind = hwloc_aix_set_area_membind; */ + /* get_area_membind is not available */ + hooks->alloc_membind = hwloc_aix_alloc_membind; + hooks->alloc = hwloc_alloc_mmap; + hooks->free_membind = hwloc_free_mmap; + support->membind->firsttouch_membind = 1; + support->membind->bind_membind = 1; + support->membind->interleave_membind = 1; +#endif /* P_DEFAULT */ +} + +static struct hwloc_backend * +hwloc_aix_component_instantiate(struct hwloc_disc_component *component, + const void *_data1 __hwloc_attribute_unused, + const void *_data2 __hwloc_attribute_unused, + const void *_data3 __hwloc_attribute_unused) +{ + struct hwloc_backend *backend; + backend = hwloc_backend_alloc(component); + if (!backend) + return NULL; + backend->discover = hwloc_look_aix; + return backend; +} + +static struct hwloc_disc_component hwloc_aix_disc_component = { + HWLOC_DISC_COMPONENT_TYPE_CPU, + "aix", + HWLOC_DISC_COMPONENT_TYPE_GLOBAL, + hwloc_aix_component_instantiate, + 50, + NULL +}; + +const struct hwloc_component hwloc_aix_component = { + HWLOC_COMPONENT_ABI, + NULL, NULL, + HWLOC_COMPONENT_TYPE_DISC, + 0, + &hwloc_aix_disc_component +}; diff --git a/opal/mca/hwloc/hwloc1110/hwloc/src/topology-bgq.c b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-bgq.c new file mode 100644 index 0000000000..1258b65420 --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-bgq.c @@ -0,0 +1,241 @@ +/* + * Copyright © 2013-2015 Inria. All rights reserved. + * See COPYING in top-level directory. + */ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +static int +hwloc_look_bgq(struct hwloc_backend *backend) +{ + struct hwloc_topology *topology = backend->topology; + unsigned i; + const char *env; + + if (!topology->levels[0][0]->cpuset) { + /* Nobody created objects yet, setup everything */ + hwloc_bitmap_t set; + hwloc_obj_t obj; + +#define HWLOC_BGQ_CORES 17 /* spare core ignored for now */ + + hwloc_alloc_obj_cpusets(topology->levels[0][0]); + /* mark the 17th core (OS-reserved) as disallowed */ + hwloc_bitmap_clr_range(topology->levels[0][0]->allowed_cpuset, (HWLOC_BGQ_CORES-1)*4, HWLOC_BGQ_CORES*4-1); + + env = getenv("BG_THREADMODEL"); + if (!env || atoi(env) != 2) { + /* process cannot use cores/threads outside of its Kernel_ThreadMask() */ + uint64_t bgmask = Kernel_ThreadMask(Kernel_MyTcoord()); + /* the mask is reversed, manually reverse it */ + for(i=0; i<64; i++) + if (((bgmask >> i) & 1) == 0) + hwloc_bitmap_clr(topology->levels[0][0]->allowed_cpuset, 63-i); + } + + /* a single memory bank */ + set = hwloc_bitmap_alloc(); + hwloc_bitmap_set(set, 0); + topology->levels[0][0]->nodeset = set; + topology->levels[0][0]->memory.local_memory = 16ULL*1024*1024*1024ULL; + + /* package */ + obj = hwloc_alloc_setup_object(HWLOC_OBJ_PACKAGE, 0); + set = hwloc_bitmap_alloc(); + hwloc_bitmap_set_range(set, 0, HWLOC_BGQ_CORES*4-1); + obj->cpuset = set; + hwloc_obj_add_info(obj, "CPUModel", "IBM PowerPC A2"); + hwloc_insert_object_by_cpuset(topology, obj); + + /* shared L2 */ + obj = hwloc_alloc_setup_object(HWLOC_OBJ_CACHE, -1); + obj->cpuset = hwloc_bitmap_dup(set); + obj->attr->cache.type = HWLOC_OBJ_CACHE_UNIFIED; + obj->attr->cache.depth = 2; + obj->attr->cache.size = 32*1024*1024; + obj->attr->cache.linesize = 128; + obj->attr->cache.associativity = 16; + hwloc_insert_object_by_cpuset(topology, obj); + + /* Cores */ + for(i=0; icpuset = set; + hwloc_insert_object_by_cpuset(topology, obj); + /* L1d */ + obj = hwloc_alloc_setup_object(HWLOC_OBJ_CACHE, -1); + obj->cpuset = hwloc_bitmap_dup(set); + obj->attr->cache.type = HWLOC_OBJ_CACHE_DATA; + obj->attr->cache.depth = 1; + obj->attr->cache.size = 16*1024; + obj->attr->cache.linesize = 64; + obj->attr->cache.associativity = 8; + hwloc_insert_object_by_cpuset(topology, obj); + /* L1i */ + obj = hwloc_alloc_setup_object(HWLOC_OBJ_CACHE, -1); + obj->cpuset = hwloc_bitmap_dup(set); + obj->attr->cache.type = HWLOC_OBJ_CACHE_INSTRUCTION; + obj->attr->cache.depth = 1; + obj->attr->cache.size = 16*1024; + obj->attr->cache.linesize = 64; + obj->attr->cache.associativity = 4; + hwloc_insert_object_by_cpuset(topology, obj); + /* there's also a L1p "prefetch cache" of 4kB with 128B lines */ + } + + /* PUs */ + hwloc_setup_pu_level(topology, HWLOC_BGQ_CORES*4); + } + + /* Add BGQ specific information */ + + hwloc_obj_add_info(topology->levels[0][0], "Backend", "BGQ"); + if (topology->is_thissystem) + hwloc_add_uname_info(topology, NULL); + return 1; +} + +static int +hwloc_bgq_get_thread_cpubind(hwloc_topology_t topology, pthread_t thread, hwloc_bitmap_t hwloc_set, int flags __hwloc_attribute_unused) +{ + unsigned pu; + cpu_set_t bg_set; + int err; + + if (topology->pid) { + errno = ENOSYS; + return -1; + } + err = pthread_getaffinity_np(thread, sizeof(bg_set), &bg_set); + if (err) { + errno = err; + return -1; + } + for(pu=0; pu<64; pu++) + if (CPU_ISSET(pu, &bg_set)) { + /* the binding cannot contain multiple PUs */ + hwloc_bitmap_only(hwloc_set, pu); + break; + } + return 0; +} + +static int +hwloc_bgq_get_thisthread_cpubind(hwloc_topology_t topology, hwloc_bitmap_t hwloc_set, int flags __hwloc_attribute_unused) +{ + if (topology->pid) { + errno = ENOSYS; + return -1; + } + hwloc_bitmap_only(hwloc_set, Kernel_ProcessorID()); + return 0; +} + +static int +hwloc_bgq_set_thread_cpubind(hwloc_topology_t topology, pthread_t thread, hwloc_const_bitmap_t hwloc_set, int flags) +{ + unsigned pu; + cpu_set_t bg_set; + int err; + + if (topology->pid) { + errno = ENOSYS; + return -1; + } + /* the binding cannot contain multiple PUs. + * keep the first PU only, and error out if STRICT. + */ + if (hwloc_bitmap_weight(hwloc_set) != 1) { + if ((flags & HWLOC_CPUBIND_STRICT)) { + errno = ENOSYS; + return -1; + } + } + pu = hwloc_bitmap_first(hwloc_set); + CPU_ZERO(&bg_set); + CPU_SET(pu, &bg_set); + err = pthread_setaffinity_np(thread, sizeof(bg_set), &bg_set); + if (err) { + errno = err; + return -1; + } + return 0; +} + +static int +hwloc_bgq_set_thisthread_cpubind(hwloc_topology_t topology, hwloc_const_bitmap_t hwloc_set, int flags) +{ + return hwloc_bgq_set_thread_cpubind(topology, pthread_self(), hwloc_set, flags); +} + +void +hwloc_set_bgq_hooks(struct hwloc_binding_hooks *hooks __hwloc_attribute_unused, + struct hwloc_topology_support *support __hwloc_attribute_unused) +{ + hooks->set_thisthread_cpubind = hwloc_bgq_set_thisthread_cpubind; + hooks->set_thread_cpubind = hwloc_bgq_set_thread_cpubind; + hooks->get_thisthread_cpubind = hwloc_bgq_get_thisthread_cpubind; + hooks->get_thread_cpubind = hwloc_bgq_get_thread_cpubind; + /* threads cannot be bound to more than one PU, so get_last_cpu_location == get_cpubind */ + hooks->get_thisthread_last_cpu_location = hwloc_bgq_get_thisthread_cpubind; + /* hooks->get_thread_last_cpu_location = hwloc_bgq_get_thread_cpubind; */ +} + +static struct hwloc_backend * +hwloc_bgq_component_instantiate(struct hwloc_disc_component *component, + const void *_data1 __hwloc_attribute_unused, + const void *_data2 __hwloc_attribute_unused, + const void *_data3 __hwloc_attribute_unused) +{ + struct utsname utsname; + struct hwloc_backend *backend; + const char *env; + int err; + + env = getenv("HWLOC_FORCE_BGQ"); + if (!env || !atoi(env)) { + err = uname(&utsname); + if (err || strcmp(utsname.sysname, "CNK") || strcmp(utsname.machine, "BGQ")) { + fprintf(stderr, "*** Found unexpected uname sysname `%s' machine `%s'\n", utsname.sysname, utsname.machine); + fprintf(stderr, "*** The BGQ backend is only enabled on compute nodes by default (sysname=CNK machine=BGQ)\n"); + fprintf(stderr, "*** Set HWLOC_FORCE_BGQ=1 in the environment to enforce the BGQ backend anyway.\n"); + return NULL; + } + } + + backend = hwloc_backend_alloc(component); + if (!backend) + return NULL; + backend->discover = hwloc_look_bgq; + return backend; +} + +static struct hwloc_disc_component hwloc_bgq_disc_component = { + HWLOC_DISC_COMPONENT_TYPE_GLOBAL, + "bgq", + ~0, + hwloc_bgq_component_instantiate, + 50, + NULL +}; + +const struct hwloc_component hwloc_bgq_component = { + HWLOC_COMPONENT_ABI, + NULL, NULL, + HWLOC_COMPONENT_TYPE_DISC, + 0, + &hwloc_bgq_disc_component +}; diff --git a/opal/mca/hwloc/hwloc1110/hwloc/src/topology-cuda.c b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-cuda.c new file mode 100644 index 0000000000..a1c6bffab4 --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-cuda.c @@ -0,0 +1,248 @@ +/* + * Copyright © 2011 Université Bordeaux + * Copyright © 2012-2014 Inria. All rights reserved. + * See COPYING in top-level directory. + */ + +#include +#include +#include +#include + +/* private headers allowed for convenience because this plugin is built within hwloc */ +#include +#include + +#include + +struct hwloc_cuda_backend_data_s { + unsigned nr_devices; /* -1 when unknown yet, first callback will setup */ + struct hwloc_cuda_device_info_s { + int idx; + unsigned pcidomain, pcibus, pcidev, pcifunc; + } * devices; +}; + +/* query all PCI bus ids for later */ +static void +hwloc_cuda_query_devices(struct hwloc_cuda_backend_data_s *data) +{ + cudaError_t cures; + int nb, i; + + /* mark the number of devices as 0 in case we fail below, + * so that we don't try again later. + */ + data->nr_devices = 0; + + cures = cudaGetDeviceCount(&nb); + if (cures) + return; + + /* allocate structs */ + data->devices = malloc(nb * sizeof(*data->devices)); + if (!data->devices) + return; + + for (i = 0; i < nb; i++) { + struct hwloc_cuda_device_info_s *info = &data->devices[data->nr_devices]; + int domain, bus, dev; + + if (hwloc_cudart_get_device_pci_ids(NULL /* topology unused */, i, &domain, &bus, &dev)) + continue; + + info->idx = i; + info->pcidomain = (unsigned) domain; + info->pcibus = (unsigned) bus; + info->pcidev = (unsigned) dev; + info->pcifunc = 0; + + /* validate this device */ + data->nr_devices++; + } + + return; +} + +static unsigned hwloc_cuda_cores_per_MP(int major, int minor) +{ + /* based on CUDA C Programming Guide, Annex G */ + switch (major) { + case 1: + switch (minor) { + case 0: + case 1: + case 2: + case 3: return 8; + } + break; + case 2: + switch (minor) { + case 0: return 32; + case 1: return 48; + } + break; + case 3: + return 192; + case 5: + return 128; + } + hwloc_debug("unknown compute capability %u.%u, disabling core display.\n", major, minor); + return 0; +} + +static int +hwloc_cuda_backend_notify_new_object(struct hwloc_backend *backend, struct hwloc_backend *caller __hwloc_attribute_unused, + struct hwloc_obj *pcidev) +{ + struct hwloc_topology *topology = backend->topology; + struct hwloc_cuda_backend_data_s *data = backend->private_data; + unsigned i; + + if (!(hwloc_topology_get_flags(topology) & (HWLOC_TOPOLOGY_FLAG_IO_DEVICES|HWLOC_TOPOLOGY_FLAG_WHOLE_IO))) + return 0; + + if (!hwloc_topology_is_thissystem(topology)) { + hwloc_debug("%s", "\nno CUDA detection (not thissystem)\n"); + return 0; + } + + if (HWLOC_OBJ_PCI_DEVICE != pcidev->type) + return 0; + + if (data->nr_devices == (unsigned) -1) { + /* first call, lookup all devices */ + hwloc_cuda_query_devices(data); + /* if it fails, data->nr_devices = 0 so we won't do anything below and in next callbacks */ + } + + if (!data->nr_devices) + /* found no devices */ + return 0; + + for(i=0; inr_devices; i++) { + struct hwloc_cuda_device_info_s *info = &data->devices[i]; + char cuda_name[32]; + char number[32]; + struct cudaDeviceProp prop; + hwloc_obj_t cuda_device; + cudaError_t cures; + unsigned cores; + + if (info->pcidomain != pcidev->attr->pcidev.domain) + continue; + if (info->pcibus != pcidev->attr->pcidev.bus) + continue; + if (info->pcidev != pcidev->attr->pcidev.dev) + continue; + if (info->pcifunc != pcidev->attr->pcidev.func) + continue; + + cuda_device = hwloc_alloc_setup_object(HWLOC_OBJ_OS_DEVICE, -1); + snprintf(cuda_name, sizeof(cuda_name), "cuda%d", info->idx); + cuda_device->name = strdup(cuda_name); + cuda_device->depth = (unsigned) HWLOC_TYPE_DEPTH_UNKNOWN; + cuda_device->attr->osdev.type = HWLOC_OBJ_OSDEV_COPROC; + + hwloc_obj_add_info(cuda_device, "CoProcType", "CUDA"); + hwloc_obj_add_info(cuda_device, "Backend", "CUDA"); + hwloc_obj_add_info(cuda_device, "GPUVendor", "NVIDIA Corporation"); + + cures = cudaGetDeviceProperties(&prop, info->idx); + if (!cures) + hwloc_obj_add_info(cuda_device, "GPUModel", prop.name); + + snprintf(number, sizeof(number), "%llu", ((unsigned long long) prop.totalGlobalMem) >> 10); + hwloc_obj_add_info(cuda_device, "CUDAGlobalMemorySize", number); + + snprintf(number, sizeof(number), "%llu", ((unsigned long long) prop.l2CacheSize) >> 10); + hwloc_obj_add_info(cuda_device, "CUDAL2CacheSize", number); + + snprintf(number, sizeof(number), "%d", prop.multiProcessorCount); + hwloc_obj_add_info(cuda_device, "CUDAMultiProcessors", number); + + cores = hwloc_cuda_cores_per_MP(prop.major, prop.minor); + if (cores) { + snprintf(number, sizeof(number), "%u", cores); + hwloc_obj_add_info(cuda_device, "CUDACoresPerMP", number); + } + + snprintf(number, sizeof(number), "%llu", ((unsigned long long) prop.sharedMemPerBlock) >> 10); + hwloc_obj_add_info(cuda_device, "CUDASharedMemorySizePerMP", number); + + hwloc_insert_object_by_parent(topology, pcidev, cuda_device); + return 1; + } + + return 0; +} + +static void +hwloc_cuda_backend_disable(struct hwloc_backend *backend) +{ + struct hwloc_cuda_backend_data_s *data = backend->private_data; + free(data->devices); + free(data); +} + +static struct hwloc_backend * +hwloc_cuda_component_instantiate(struct hwloc_disc_component *component, + const void *_data1 __hwloc_attribute_unused, + const void *_data2 __hwloc_attribute_unused, + const void *_data3 __hwloc_attribute_unused) +{ + struct hwloc_backend *backend; + struct hwloc_cuda_backend_data_s *data; + + /* thissystem may not be fully initialized yet, we'll check flags in discover() */ + + backend = hwloc_backend_alloc(component); + if (!backend) + return NULL; + + data = malloc(sizeof(*data)); + if (!data) { + free(backend); + return NULL; + } + /* the first callback will initialize those */ + data->nr_devices = (unsigned) -1; /* unknown yet */ + data->devices = NULL; + + backend->private_data = data; + backend->disable = hwloc_cuda_backend_disable; + + backend->notify_new_object = hwloc_cuda_backend_notify_new_object; + return backend; +} + +static struct hwloc_disc_component hwloc_cuda_disc_component = { + HWLOC_DISC_COMPONENT_TYPE_MISC, + "cuda", + HWLOC_DISC_COMPONENT_TYPE_GLOBAL, + hwloc_cuda_component_instantiate, + 10, /* after pci */ + NULL +}; + +static int +hwloc_cuda_component_init(unsigned long flags) +{ + if (flags) + return -1; + if (hwloc_plugin_check_namespace("cuda", "hwloc_backend_alloc") < 0) + return -1; + return 0; +} + +#ifdef HWLOC_INSIDE_PLUGIN +HWLOC_DECLSPEC extern const struct hwloc_component hwloc_cuda_component; +#endif + +const struct hwloc_component hwloc_cuda_component = { + HWLOC_COMPONENT_ABI, + hwloc_cuda_component_init, NULL, + HWLOC_COMPONENT_TYPE_DISC, + 0, + &hwloc_cuda_disc_component +}; diff --git a/opal/mca/hwloc/hwloc1110/hwloc/src/topology-custom.c b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-custom.c new file mode 100644 index 0000000000..c3ccfaadc9 --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-custom.c @@ -0,0 +1,100 @@ +/* + * Copyright © 2011-2014 Inria. All rights reserved. + * See COPYING in top-level directory. + */ + +#include +#include +#include + +hwloc_obj_t +hwloc_custom_insert_group_object_by_parent(struct hwloc_topology *topology, hwloc_obj_t parent, int groupdepth) +{ + hwloc_obj_t obj; + + /* must be called between set_custom() and load(), so there's a single backend, the custom one */ + if (topology->is_loaded || !topology->backends || !topology->backends->is_custom) { + errno = EINVAL; + return NULL; + } + + obj = hwloc_alloc_setup_object(HWLOC_OBJ_GROUP, -1); + obj->attr->group.depth = groupdepth; + hwloc_obj_add_info(obj, "Backend", "Custom"); + hwloc_insert_object_by_parent(topology, parent, obj); + /* insert_object_by_parent() doesn't merge during insert, so obj is still valid */ + + return obj; +} + +int +hwloc_custom_insert_topology(struct hwloc_topology *newtopology, + struct hwloc_obj *newparent, + struct hwloc_topology *oldtopology, + struct hwloc_obj *oldroot) +{ + /* must be called between set_custom() and load(), so there's a single backend, the custom one */ + if (newtopology->is_loaded || !newtopology->backends || !newtopology->backends->is_custom) { + errno = EINVAL; + return -1; + } + + if (!oldtopology->is_loaded) { + errno = EINVAL; + return -1; + } + + hwloc__duplicate_objects(newtopology, newparent, oldroot ? oldroot : oldtopology->levels[0][0]); + return 0; +} + +static int +hwloc_look_custom(struct hwloc_backend *backend) +{ + struct hwloc_topology *topology = backend->topology; + hwloc_obj_t root = topology->levels[0][0]; + + assert(!root->cpuset); + + if (!root->first_child) { + errno = EINVAL; + return -1; + } + + root->type = HWLOC_OBJ_SYSTEM; + hwloc_obj_add_info(root, "Backend", "Custom"); + return 1; +} + +static struct hwloc_backend * +hwloc_custom_component_instantiate(struct hwloc_disc_component *component, + const void *_data1 __hwloc_attribute_unused, + const void *_data2 __hwloc_attribute_unused, + const void *_data3 __hwloc_attribute_unused) +{ + struct hwloc_backend *backend; + backend = hwloc_backend_alloc(component); + if (!backend) + return NULL; + backend->discover = hwloc_look_custom; + backend->is_custom = 1; + backend->is_thissystem = 0; + return backend; +} + +static struct hwloc_disc_component hwloc_custom_disc_component = { + HWLOC_DISC_COMPONENT_TYPE_GLOBAL, + "custom", + ~0, + hwloc_custom_component_instantiate, + 30, + NULL +}; + +const struct hwloc_component hwloc_custom_component = { + HWLOC_COMPONENT_ABI, + NULL, NULL, + HWLOC_COMPONENT_TYPE_DISC, + 0, + &hwloc_custom_disc_component +}; diff --git a/opal/mca/hwloc/hwloc1110/hwloc/src/topology-darwin.c b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-darwin.c new file mode 100644 index 0000000000..1062a1d0c0 --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-darwin.c @@ -0,0 +1,307 @@ +/* + * Copyright © 2009 CNRS + * Copyright © 2009-2014 Inria. All rights reserved. + * Copyright © 2009-2013 Université Bordeaux + * Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved. + * See COPYING in top-level directory. + */ + +/* Detect topology change: registering for power management changes and check + * if for example hw.activecpu changed */ + +/* Apparently, Darwin people do not _want_ to provide binding functions. */ + +#include + +#include +#include +#include +#include + +#include +#include +#include + +static int +hwloc_look_darwin(struct hwloc_backend *backend) +{ + struct hwloc_topology *topology = backend->topology; + int64_t _nprocs; + unsigned nprocs; + int64_t _npackages; + unsigned i, j, cpu; + struct hwloc_obj *obj; + size_t size; + int64_t l1dcachesize, l1icachesize; + int64_t cacheways[2]; + int64_t l2cachesize; + int64_t cachelinesize; + int64_t memsize; + char cpumodel[64]; + + if (topology->levels[0][0]->cpuset) + /* somebody discovered things */ + return 0; + + hwloc_alloc_obj_cpusets(topology->levels[0][0]); + + if (hwloc_get_sysctlbyname("hw.ncpu", &_nprocs) || _nprocs <= 0) + return -1; + nprocs = _nprocs; + topology->support.discovery->pu = 1; + + hwloc_debug("%u procs\n", nprocs); + + size = sizeof(cpumodel); + if (sysctlbyname("machdep.cpu.brand_string", cpumodel, &size, NULL, 0)) + cpumodel[0] = '\0'; + + if (!hwloc_get_sysctlbyname("hw.packages", &_npackages) && _npackages > 0) { + unsigned npackages = _npackages; + int64_t _cores_per_package; + int64_t _logical_per_package; + unsigned logical_per_package; + + hwloc_debug("%u packages\n", npackages); + + if (!hwloc_get_sysctlbyname("machdep.cpu.logical_per_package", &_logical_per_package) && _logical_per_package > 0) + logical_per_package = _logical_per_package; + else + /* Assume the trivia. */ + logical_per_package = nprocs / npackages; + + hwloc_debug("%u threads per package\n", logical_per_package); + + + if (nprocs == npackages * logical_per_package) + for (i = 0; i < npackages; i++) { + obj = hwloc_alloc_setup_object(HWLOC_OBJ_PACKAGE, i); + obj->cpuset = hwloc_bitmap_alloc(); + for (cpu = i*logical_per_package; cpu < (i+1)*logical_per_package; cpu++) + hwloc_bitmap_set(obj->cpuset, cpu); + + hwloc_debug_1arg_bitmap("package %u has cpuset %s\n", + i, obj->cpuset); + + if (cpumodel[0] != '\0') + hwloc_obj_add_info(obj, "CPUModel", cpumodel); + hwloc_insert_object_by_cpuset(topology, obj); + } + else + if (cpumodel[0] != '\0') + hwloc_obj_add_info(topology->levels[0][0], "CPUModel", cpumodel); + + if (!hwloc_get_sysctlbyname("machdep.cpu.cores_per_package", &_cores_per_package) && _cores_per_package > 0) { + unsigned cores_per_package = _cores_per_package; + hwloc_debug("%u cores per package\n", cores_per_package); + + if (!(logical_per_package % cores_per_package)) + for (i = 0; i < npackages * cores_per_package; i++) { + obj = hwloc_alloc_setup_object(HWLOC_OBJ_CORE, i); + obj->cpuset = hwloc_bitmap_alloc(); + for (cpu = i*(logical_per_package/cores_per_package); + cpu < (i+1)*(logical_per_package/cores_per_package); + cpu++) + hwloc_bitmap_set(obj->cpuset, cpu); + + hwloc_debug_1arg_bitmap("core %u has cpuset %s\n", + i, obj->cpuset); + hwloc_insert_object_by_cpuset(topology, obj); + } + } + } else + if (cpumodel[0] != '\0') + hwloc_obj_add_info(topology->levels[0][0], "CPUModel", cpumodel); + + if (hwloc_get_sysctlbyname("hw.l1dcachesize", &l1dcachesize)) + l1dcachesize = 0; + + if (hwloc_get_sysctlbyname("hw.l1icachesize", &l1icachesize)) + l1icachesize = 0; + + if (hwloc_get_sysctlbyname("hw.l2cachesize", &l2cachesize)) + l2cachesize = 0; + + if (hwloc_get_sysctlbyname("machdep.cpu.cache.L1_associativity", &cacheways[0])) + cacheways[0] = 0; + else if (cacheways[0] == 0xff) + cacheways[0] = -1; + + if (hwloc_get_sysctlbyname("machdep.cpu.cache.L2_associativity", &cacheways[1])) + cacheways[1] = 0; + else if (cacheways[1] == 0xff) + cacheways[1] = -1; + + if (hwloc_get_sysctlbyname("hw.cachelinesize", &cachelinesize)) + cachelinesize = 0; + + if (hwloc_get_sysctlbyname("hw.memsize", &memsize)) + memsize = 0; + + if (!sysctlbyname("hw.cacheconfig", NULL, &size, NULL, 0)) { + unsigned n = size / sizeof(uint32_t); + uint64_t *cacheconfig = NULL; + uint64_t *cachesize = NULL; + uint32_t *cacheconfig32 = NULL; + + cacheconfig = malloc(sizeof(uint64_t) * n); + if (NULL == cacheconfig) { + goto out; + } + cachesize = malloc(sizeof(uint64_t) * n); + if (NULL == cachesize) { + goto out; + } + cacheconfig32 = malloc(sizeof(uint32_t) * n); + if (NULL == cacheconfig32) { + goto out; + } + + if ((!sysctlbyname("hw.cacheconfig", cacheconfig, &size, NULL, 0))) { + /* Yeech. Darwin seemingly has changed from 32bit to 64bit integers for + * cacheconfig, with apparently no way for detection. Assume the machine + * won't have more than 4 billion cpus */ + if (cacheconfig[0] > 0xFFFFFFFFUL) { + memcpy(cacheconfig32, cacheconfig, size); + for (i = 0 ; i < size / sizeof(uint32_t); i++) + cacheconfig[i] = cacheconfig32[i]; + } + + memset(cachesize, 0, sizeof(uint64_t) * n); + size = sizeof(uint64_t) * n; + if (sysctlbyname("hw.cachesize", cachesize, &size, NULL, 0)) { + if (n > 0) + cachesize[0] = memsize; + if (n > 1) + cachesize[1] = l1dcachesize; + if (n > 2) + cachesize[2] = l2cachesize; + } + + hwloc_debug("%s", "caches"); + for (i = 0; i < n && cacheconfig[i]; i++) + hwloc_debug(" %"PRIu64"(%"PRIu64"kB)", cacheconfig[i], cachesize[i] / 1024); + + /* Now we know how many caches there are */ + n = i; + hwloc_debug("\n%u cache levels\n", n - 1); + + /* For each cache level (0 is memory) */ + for (i = 0; i < n; i++) { + /* cacheconfig tells us how many cpus share it, let's iterate on each cache */ + for (j = 0; j < (nprocs / cacheconfig[i]); j++) { + obj = hwloc_alloc_setup_object(i?HWLOC_OBJ_CACHE:HWLOC_OBJ_NUMANODE, j); + if (!i) { + obj->nodeset = hwloc_bitmap_alloc(); + hwloc_bitmap_set(obj->nodeset, j); + } + obj->cpuset = hwloc_bitmap_alloc(); + for (cpu = j*cacheconfig[i]; + cpu < ((j+1)*cacheconfig[i]); + cpu++) + hwloc_bitmap_set(obj->cpuset, cpu); + + if (i == 1 && l1icachesize) { + /* FIXME assuming that L1i and L1d are shared the same way. Darwin + * does not yet provide a way to know. */ + hwloc_obj_t l1i = hwloc_alloc_setup_object(HWLOC_OBJ_CACHE, j); + l1i->cpuset = hwloc_bitmap_dup(obj->cpuset); + hwloc_debug_1arg_bitmap("L1icache %u has cpuset %s\n", + j, l1i->cpuset); + l1i->attr->cache.depth = i; + l1i->attr->cache.size = l1icachesize; + l1i->attr->cache.linesize = cachelinesize; + l1i->attr->cache.associativity = 0; + l1i->attr->cache.type = HWLOC_OBJ_CACHE_INSTRUCTION; + + hwloc_insert_object_by_cpuset(topology, l1i); + } + if (i) { + hwloc_debug_2args_bitmap("L%ucache %u has cpuset %s\n", + i, j, obj->cpuset); + obj->attr->cache.depth = i; + obj->attr->cache.size = cachesize[i]; + obj->attr->cache.linesize = cachelinesize; + if (i <= sizeof(cacheways) / sizeof(cacheways[0])) + obj->attr->cache.associativity = cacheways[i-1]; + else + obj->attr->cache.associativity = 0; + if (i == 1 && l1icachesize) + obj->attr->cache.type = HWLOC_OBJ_CACHE_DATA; + else + obj->attr->cache.type = HWLOC_OBJ_CACHE_UNIFIED; + } else { + hwloc_debug_1arg_bitmap("node %u has cpuset %s\n", + j, obj->cpuset); + obj->memory.local_memory = cachesize[i]; + obj->memory.page_types_len = 2; + obj->memory.page_types = malloc(2*sizeof(*obj->memory.page_types)); + memset(obj->memory.page_types, 0, 2*sizeof(*obj->memory.page_types)); + obj->memory.page_types[0].size = hwloc_getpagesize(); +#ifdef HAVE__SC_LARGE_PAGESIZE + obj->memory.page_types[1].size = sysconf(_SC_LARGE_PAGESIZE); +#endif + } + + hwloc_insert_object_by_cpuset(topology, obj); + } + } + } + out: + if (NULL != cacheconfig) { + free(cacheconfig); + } + if (NULL != cachesize) { + free(cachesize); + } + if (NULL != cacheconfig32) { + free(cacheconfig32); + } + } + + + /* add PU objects */ + hwloc_setup_pu_level(topology, nprocs); + + hwloc_obj_add_info(topology->levels[0][0], "Backend", "Darwin"); + if (topology->is_thissystem) + hwloc_add_uname_info(topology, NULL); + return 1; +} + +void +hwloc_set_darwin_hooks(struct hwloc_binding_hooks *hooks __hwloc_attribute_unused, + struct hwloc_topology_support *support __hwloc_attribute_unused) +{ +} + +static struct hwloc_backend * +hwloc_darwin_component_instantiate(struct hwloc_disc_component *component, + const void *_data1 __hwloc_attribute_unused, + const void *_data2 __hwloc_attribute_unused, + const void *_data3 __hwloc_attribute_unused) +{ + struct hwloc_backend *backend; + backend = hwloc_backend_alloc(component); + if (!backend) + return NULL; + backend->discover = hwloc_look_darwin; + return backend; +} + +static struct hwloc_disc_component hwloc_darwin_disc_component = { + HWLOC_DISC_COMPONENT_TYPE_CPU, + "darwin", + HWLOC_DISC_COMPONENT_TYPE_GLOBAL, + hwloc_darwin_component_instantiate, + 50, + NULL +}; + +const struct hwloc_component hwloc_darwin_component = { + HWLOC_COMPONENT_ABI, + NULL, NULL, + HWLOC_COMPONENT_TYPE_DISC, + 0, + &hwloc_darwin_disc_component +}; diff --git a/opal/mca/hwloc/hwloc1110/hwloc/src/topology-fake.c b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-fake.c new file mode 100644 index 0000000000..e3e22a0a13 --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-fake.c @@ -0,0 +1,61 @@ +/* + * Copyright © 2012-2014 Inria. All rights reserved. + * See COPYING in top-level directory. + */ + +#include +#include +#include + +#include + +static struct hwloc_backend * +hwloc_fake_component_instantiate(struct hwloc_disc_component *component __hwloc_attribute_unused, + const void *_data1 __hwloc_attribute_unused, + const void *_data2 __hwloc_attribute_unused, + const void *_data3 __hwloc_attribute_unused) +{ + if (getenv("HWLOC_DEBUG_FAKE_COMPONENT")) + printf("fake component instantiated\n"); + return NULL; +} + +static struct hwloc_disc_component hwloc_fake_disc_component = { + HWLOC_DISC_COMPONENT_TYPE_MISC, /* so that it's always enabled when using the OS discovery */ + "fake", + 0, /* nothing to exclude */ + hwloc_fake_component_instantiate, + 100, /* make sure it's loaded before anything conflicting excludes it */ + NULL +}; + +static int +hwloc_fake_component_init(unsigned long flags) +{ + if (flags) + return -1; + if (hwloc_plugin_check_namespace("fake", "hwloc_backend_alloc") < 0) + return -1; + if (getenv("HWLOC_DEBUG_FAKE_COMPONENT")) + printf("fake component initialized\n"); + return 0; +} + +static void +hwloc_fake_component_finalize(unsigned long flags) +{ + if (flags) + return; + if (getenv("HWLOC_DEBUG_FAKE_COMPONENT")) + printf("fake component finalized\n"); +} + +HWLOC_DECLSPEC extern const struct hwloc_component hwloc_fake_component; /* never linked statically in the core */ + +const struct hwloc_component hwloc_fake_component = { + HWLOC_COMPONENT_ABI, + hwloc_fake_component_init, hwloc_fake_component_finalize, + HWLOC_COMPONENT_TYPE_DISC, + 0, + &hwloc_fake_disc_component +}; diff --git a/opal/mca/hwloc/hwloc1110/hwloc/src/topology-freebsd.c b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-freebsd.c new file mode 100644 index 0000000000..4901209eee --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-freebsd.c @@ -0,0 +1,253 @@ +/* + * Copyright © 2009 CNRS + * Copyright © 2009-2014 Inria. All rights reserved. + * Copyright © 2009-2010, 2012 Université Bordeaux + * Copyright © 2011 Cisco Systems, Inc. All rights reserved. + * See COPYING in top-level directory. + */ + +#include + +#include +#include +#include +#include +#include +#ifdef HAVE_PTHREAD_NP_H +#include +#endif +#ifdef HAVE_SYS_CPUSET_H +#include +#endif +#ifdef HAVE_SYS_SYSCTL_H +#include +#endif + +#include +#include +#include + +#if defined(HAVE_SYS_CPUSET_H) && defined(HAVE_CPUSET_SETAFFINITY) +static void +hwloc_freebsd_bsd2hwloc(hwloc_bitmap_t hwloc_cpuset, const cpuset_t *cset) +{ + unsigned cpu; + hwloc_bitmap_zero(hwloc_cpuset); + for (cpu = 0; cpu < CPU_SETSIZE; cpu++) + if (CPU_ISSET(cpu, cset)) + hwloc_bitmap_set(hwloc_cpuset, cpu); +} + +static void +hwloc_freebsd_hwloc2bsd(hwloc_const_bitmap_t hwloc_cpuset, cpuset_t *cset) +{ + unsigned cpu; + CPU_ZERO(cset); + for (cpu = 0; cpu < CPU_SETSIZE; cpu++) + if (hwloc_bitmap_isset(hwloc_cpuset, cpu)) + CPU_SET(cpu, cset); +} + +static int +hwloc_freebsd_set_sth_affinity(hwloc_topology_t topology __hwloc_attribute_unused, cpulevel_t level, cpuwhich_t which, id_t id, hwloc_const_bitmap_t hwloc_cpuset, int flags __hwloc_attribute_unused) +{ + cpuset_t cset; + + hwloc_freebsd_hwloc2bsd(hwloc_cpuset, &cset); + + if (cpuset_setaffinity(level, which, id, sizeof(cset), &cset)) + return -1; + + return 0; +} + +static int +hwloc_freebsd_get_sth_affinity(hwloc_topology_t topology __hwloc_attribute_unused, cpulevel_t level, cpuwhich_t which, id_t id, hwloc_bitmap_t hwloc_cpuset, int flags __hwloc_attribute_unused) +{ + cpuset_t cset; + + if (cpuset_getaffinity(level, which, id, sizeof(cset), &cset)) + return -1; + + hwloc_freebsd_bsd2hwloc(hwloc_cpuset, &cset); + return 0; +} + +static int +hwloc_freebsd_set_thisproc_cpubind(hwloc_topology_t topology, hwloc_const_bitmap_t hwloc_cpuset, int flags) +{ + return hwloc_freebsd_set_sth_affinity(topology, CPU_LEVEL_WHICH, CPU_WHICH_PID, -1, hwloc_cpuset, flags); +} + +static int +hwloc_freebsd_get_thisproc_cpubind(hwloc_topology_t topology, hwloc_bitmap_t hwloc_cpuset, int flags) +{ + return hwloc_freebsd_get_sth_affinity(topology, CPU_LEVEL_WHICH, CPU_WHICH_PID, -1, hwloc_cpuset, flags); +} + +static int +hwloc_freebsd_set_thisthread_cpubind(hwloc_topology_t topology, hwloc_const_bitmap_t hwloc_cpuset, int flags) +{ + return hwloc_freebsd_set_sth_affinity(topology, CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, hwloc_cpuset, flags); +} + +static int +hwloc_freebsd_get_thisthread_cpubind(hwloc_topology_t topology, hwloc_bitmap_t hwloc_cpuset, int flags) +{ + return hwloc_freebsd_get_sth_affinity(topology, CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, hwloc_cpuset, flags); +} + +static int +hwloc_freebsd_set_proc_cpubind(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_const_bitmap_t hwloc_cpuset, int flags) +{ + return hwloc_freebsd_set_sth_affinity(topology, CPU_LEVEL_WHICH, CPU_WHICH_PID, pid, hwloc_cpuset, flags); +} + +static int +hwloc_freebsd_get_proc_cpubind(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_bitmap_t hwloc_cpuset, int flags) +{ + return hwloc_freebsd_get_sth_affinity(topology, CPU_LEVEL_WHICH, CPU_WHICH_PID, pid, hwloc_cpuset, flags); +} + +#ifdef hwloc_thread_t + +#if HAVE_DECL_PTHREAD_SETAFFINITY_NP +#pragma weak pthread_setaffinity_np +static int +hwloc_freebsd_set_thread_cpubind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_thread_t tid, hwloc_const_bitmap_t hwloc_cpuset, int flags __hwloc_attribute_unused) +{ + int err; + cpuset_t cset; + + if (!pthread_setaffinity_np) { + errno = ENOSYS; + return -1; + } + + hwloc_freebsd_hwloc2bsd(hwloc_cpuset, &cset); + + err = pthread_setaffinity_np(tid, sizeof(cset), &cset); + + if (err) { + errno = err; + return -1; + } + + return 0; +} +#endif + +#if HAVE_DECL_PTHREAD_GETAFFINITY_NP +#pragma weak pthread_getaffinity_np +static int +hwloc_freebsd_get_thread_cpubind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_thread_t tid, hwloc_bitmap_t hwloc_cpuset, int flags __hwloc_attribute_unused) +{ + int err; + cpuset_t cset; + + if (!pthread_getaffinity_np) { + errno = ENOSYS; + return -1; + } + + err = pthread_getaffinity_np(tid, sizeof(cset), &cset); + + if (err) { + errno = err; + return -1; + } + + hwloc_freebsd_bsd2hwloc(hwloc_cpuset, &cset); + return 0; +} +#endif +#endif +#endif + +#if (defined HAVE_SYSCTL) && (defined HAVE_SYS_SYSCTL_H) +static void +hwloc_freebsd_node_meminfo_info(struct hwloc_topology *topology) +{ + int mib[2] = { CTL_HW, HW_PHYSMEM }; + unsigned long physmem; + size_t len = sizeof(physmem); + sysctl(mib, 2, &physmem, &len, NULL, 0); + topology->levels[0][0]->memory.local_memory = physmem; +} +#endif + +static int +hwloc_look_freebsd(struct hwloc_backend *backend) +{ + struct hwloc_topology *topology = backend->topology; + unsigned nbprocs = hwloc_fallback_nbprocessors(topology); + + if (!topology->levels[0][0]->cpuset) { + /* Nobody (even the x86 backend) created objects yet, setup basic objects */ + hwloc_alloc_obj_cpusets(topology->levels[0][0]); + hwloc_setup_pu_level(topology, nbprocs); + } + + /* Add FreeBSD specific information */ +#if (defined HAVE_SYSCTL) && (defined HAVE_SYS_SYSCTL_H) + hwloc_freebsd_node_meminfo_info(topology); +#endif + hwloc_obj_add_info(topology->levels[0][0], "Backend", "FreeBSD"); + if (topology->is_thissystem) + hwloc_add_uname_info(topology, NULL); + return 1; +} + +void +hwloc_set_freebsd_hooks(struct hwloc_binding_hooks *hooks __hwloc_attribute_unused, + struct hwloc_topology_support *support __hwloc_attribute_unused) +{ +#if defined(HAVE_SYS_CPUSET_H) && defined(HAVE_CPUSET_SETAFFINITY) + hooks->set_thisproc_cpubind = hwloc_freebsd_set_thisproc_cpubind; + hooks->get_thisproc_cpubind = hwloc_freebsd_get_thisproc_cpubind; + hooks->set_thisthread_cpubind = hwloc_freebsd_set_thisthread_cpubind; + hooks->get_thisthread_cpubind = hwloc_freebsd_get_thisthread_cpubind; + hooks->set_proc_cpubind = hwloc_freebsd_set_proc_cpubind; + hooks->get_proc_cpubind = hwloc_freebsd_get_proc_cpubind; +#ifdef hwloc_thread_t +#if HAVE_DECL_PTHREAD_SETAFFINITY_NP + hooks->set_thread_cpubind = hwloc_freebsd_set_thread_cpubind; +#endif +#if HAVE_DECL_PTHREAD_GETAFFINITY_NP + hooks->get_thread_cpubind = hwloc_freebsd_get_thread_cpubind; +#endif +#endif +#endif + /* TODO: get_last_cpu_location: find out ki_lastcpu */ +} + +static struct hwloc_backend * +hwloc_freebsd_component_instantiate(struct hwloc_disc_component *component, + const void *_data1 __hwloc_attribute_unused, + const void *_data2 __hwloc_attribute_unused, + const void *_data3 __hwloc_attribute_unused) +{ + struct hwloc_backend *backend; + backend = hwloc_backend_alloc(component); + if (!backend) + return NULL; + backend->discover = hwloc_look_freebsd; + return backend; +} + +static struct hwloc_disc_component hwloc_freebsd_disc_component = { + HWLOC_DISC_COMPONENT_TYPE_CPU, + "freebsd", + HWLOC_DISC_COMPONENT_TYPE_GLOBAL, + hwloc_freebsd_component_instantiate, + 50, + NULL +}; + +const struct hwloc_component hwloc_freebsd_component = { + HWLOC_COMPONENT_ABI, + NULL, NULL, + HWLOC_COMPONENT_TYPE_DISC, + 0, + &hwloc_freebsd_disc_component +}; diff --git a/opal/mca/hwloc/hwloc1110/hwloc/src/topology-gl.c b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-gl.c new file mode 100644 index 0000000000..45e9e2dff6 --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-gl.c @@ -0,0 +1,271 @@ +/* + * Copyright © 2012-2013 Blue Brain Project, BBP/EPFL. All rights reserved. + * Copyright © 2012-2014 Inria. All rights reserved. + * See COPYING in top-level directory. + */ + +#include +#include +#include + +/* private headers allowed for convenience because this plugin is built within hwloc */ +#include +#include + +#include +#include +#include +#include +#include + +#define HWLOC_GL_SERVER_MAX 10 +#define HWLOC_GL_SCREEN_MAX 10 +struct hwloc_gl_backend_data_s { + unsigned nr_display; + struct hwloc_gl_display_info_s { + char name[10]; + unsigned port, device; + unsigned pcidomain, pcibus, pcidevice, pcifunc; + char *productname; + } display[HWLOC_GL_SERVER_MAX*HWLOC_GL_SCREEN_MAX]; +}; + +static void +hwloc_gl_query_devices(struct hwloc_gl_backend_data_s *data) +{ + int err; + unsigned i,j; + + /* mark the number of display as 0 in case we fail below, + * so that we don't try again later. + */ + data->nr_display = 0; + + for (i = 0; i < HWLOC_GL_SERVER_MAX; ++i) { + Display* display; + char displayName[10]; + int opcode, event, error; + + /* open X server */ + snprintf(displayName, sizeof(displayName), ":%u", i); + display = XOpenDisplay(displayName); + if (!display) + continue; + + /* Check for NV-CONTROL extension (it's per server) */ + if(!XQueryExtension(display, "NV-CONTROL", &opcode, &event, &error)) { + XCloseDisplay(display); + continue; + } + + for (j = 0; j < (unsigned) ScreenCount(display) && j < HWLOC_GL_SCREEN_MAX; j++) { + struct hwloc_gl_display_info_s *info = &data->display[data->nr_display]; + const int screen = j; + unsigned int *ptr_binary_data; + int data_length; + int gpu_number; + int nv_ctrl_pci_bus; + int nv_ctrl_pci_device; + int nv_ctrl_pci_domain; + int nv_ctrl_pci_func; + char *productname; + + /* the server supports NV-CONTROL but it may contain non-NVIDIA screen that don't support it */ + if (!XNVCTRLIsNvScreen(display, screen)) + continue; + + /* Gets the GPU number attached to the default screen. */ + /* For further details, see the */ + err = XNVCTRLQueryTargetBinaryData (display, NV_CTRL_TARGET_TYPE_X_SCREEN, screen, 0, + NV_CTRL_BINARY_DATA_GPUS_USED_BY_XSCREEN, + (unsigned char **) &ptr_binary_data, &data_length); + if (!err) + continue; + + gpu_number = ptr_binary_data[1]; + free(ptr_binary_data); + +#ifdef NV_CTRL_PCI_DOMAIN + /* Gets the ID's of the GPU defined by gpu_number + * For further details, see the */ + err = XNVCTRLQueryTargetAttribute(display, NV_CTRL_TARGET_TYPE_GPU, gpu_number, 0, + NV_CTRL_PCI_DOMAIN, &nv_ctrl_pci_domain); + if (!err) + continue; +#else + nv_ctrl_pci_domain = 0; +#endif + + err = XNVCTRLQueryTargetAttribute(display, NV_CTRL_TARGET_TYPE_GPU, gpu_number, 0, + NV_CTRL_PCI_BUS, &nv_ctrl_pci_bus); + if (!err) + continue; + + err = XNVCTRLQueryTargetAttribute(display, NV_CTRL_TARGET_TYPE_GPU, gpu_number, 0, + NV_CTRL_PCI_DEVICE, &nv_ctrl_pci_device); + if (!err) + continue; + + err = XNVCTRLQueryTargetAttribute(display, NV_CTRL_TARGET_TYPE_GPU, gpu_number, 0, + NV_CTRL_PCI_FUNCTION, &nv_ctrl_pci_func); + if (!err) + continue; + + productname = NULL; + err = XNVCTRLQueryTargetStringAttribute(display, NV_CTRL_TARGET_TYPE_GPU, gpu_number, 0, + NV_CTRL_STRING_PRODUCT_NAME, &productname); + + snprintf(info->name, sizeof(info->name), ":%u.%u", i, j); + info->port = i; + info->device = j; + info->pcidomain = nv_ctrl_pci_domain; + info->pcibus = nv_ctrl_pci_bus; + info->pcidevice = nv_ctrl_pci_device; + info->pcifunc = nv_ctrl_pci_func; + info->productname = productname; + + hwloc_debug("GL device %s (product %s) on PCI 0000:%02x:%02x.%u\n", info->name, productname, + nv_ctrl_pci_domain, nv_ctrl_pci_bus, nv_ctrl_pci_device, nv_ctrl_pci_func); + + /* validate this device */ + data->nr_display++; + } + XCloseDisplay(display); + } +} + +static int +hwloc_gl_backend_notify_new_object(struct hwloc_backend *backend, struct hwloc_backend *caller __hwloc_attribute_unused, + struct hwloc_obj *pcidev) +{ + struct hwloc_topology *topology = backend->topology; + struct hwloc_gl_backend_data_s *data = backend->private_data; + unsigned i, res; + + if (!(hwloc_topology_get_flags(topology) & (HWLOC_TOPOLOGY_FLAG_IO_DEVICES|HWLOC_TOPOLOGY_FLAG_WHOLE_IO))) + return 0; + + if (!hwloc_topology_is_thissystem(topology)) { + hwloc_debug("%s", "\nno GL detection (not thissystem)\n"); + return 0; + } + + if (HWLOC_OBJ_PCI_DEVICE != pcidev->type) + return 0; + + if (data->nr_display == (unsigned) -1) { + /* first call, lookup all display */ + hwloc_gl_query_devices(data); + /* if it fails, data->nr_display = 0 so we won't do anything below and in next callbacks */ + } + + if (!data->nr_display) + /* found no display */ + return 0; + + /* now the display array is ready to use */ + res = 0; + for(i=0; inr_display; i++) { + struct hwloc_gl_display_info_s *info = &data->display[i]; + hwloc_obj_t osdev; + + if (info->pcidomain != pcidev->attr->pcidev.domain) + continue; + if (info->pcibus != pcidev->attr->pcidev.bus) + continue; + if (info->pcidevice != pcidev->attr->pcidev.dev) + continue; + if (info->pcifunc != pcidev->attr->pcidev.func) + continue; + + osdev = hwloc_alloc_setup_object(HWLOC_OBJ_OS_DEVICE, -1); + osdev->name = strdup(info->name); + osdev->logical_index = -1; + osdev->attr->osdev.type = HWLOC_OBJ_OSDEV_GPU; + hwloc_obj_add_info(osdev, "Backend", "GL"); + hwloc_obj_add_info(osdev, "GPUVendor", "NVIDIA Corporation"); + if (info->productname) + hwloc_obj_add_info(osdev, "GPUModel", info->productname); + hwloc_insert_object_by_parent(topology, pcidev, osdev); + + res++; + /* there may be others */ + } + + return res; +} + +static void +hwloc_gl_backend_disable(struct hwloc_backend *backend) +{ + struct hwloc_gl_backend_data_s *data = backend->private_data; + unsigned i; + if (data->nr_display != (unsigned) -1) { /* could be -1 if --no-io */ + for(i=0; inr_display; i++) { + struct hwloc_gl_display_info_s *info = &data->display[i]; + free(info->productname); + } + } + free(backend->private_data); +} + +static struct hwloc_backend * +hwloc_gl_component_instantiate(struct hwloc_disc_component *component, + const void *_data1 __hwloc_attribute_unused, + const void *_data2 __hwloc_attribute_unused, + const void *_data3 __hwloc_attribute_unused) +{ + struct hwloc_backend *backend; + struct hwloc_gl_backend_data_s *data; + + /* thissystem may not be fully initialized yet, we'll check flags in discover() */ + + backend = hwloc_backend_alloc(component); + if (!backend) + return NULL; + + data = malloc(sizeof(*data)); + if (!data) { + free(backend); + return NULL; + } + /* the first callback will initialize those */ + data->nr_display = (unsigned) -1; /* unknown yet */ + + backend->private_data = data; + backend->disable = hwloc_gl_backend_disable; + + backend->notify_new_object = hwloc_gl_backend_notify_new_object; + return backend; +} + +static struct hwloc_disc_component hwloc_gl_disc_component = { + HWLOC_DISC_COMPONENT_TYPE_MISC, + "gl", + HWLOC_DISC_COMPONENT_TYPE_GLOBAL, + hwloc_gl_component_instantiate, + 10, /* after pci */ + NULL +}; + +static int +hwloc_gl_component_init(unsigned long flags) +{ + if (flags) + return -1; + if (hwloc_plugin_check_namespace("gl", "hwloc_backend_alloc") < 0) + return -1; + return 0; +} + +#ifdef HWLOC_INSIDE_PLUGIN +HWLOC_DECLSPEC extern const struct hwloc_component hwloc_gl_component; +#endif + +const struct hwloc_component hwloc_gl_component = { + HWLOC_COMPONENT_ABI, + hwloc_gl_component_init, NULL, + HWLOC_COMPONENT_TYPE_DISC, + 0, + &hwloc_gl_disc_component +}; diff --git a/opal/mca/hwloc/hwloc1110/hwloc/src/topology-hpux.c b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-hpux.c new file mode 100644 index 0000000000..44a4a4c41a --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-hpux.c @@ -0,0 +1,311 @@ +/* + * Copyright © 2009 CNRS + * Copyright © 2009-2014 Inria. All rights reserved. + * Copyright © 2009-2010, 2013 Université Bordeaux + * Copyright © 2011 Cisco Systems, Inc. All rights reserved. + * See COPYING in top-level directory. + */ + +/* TODO: psets? (Only for root) + * since 11i 1.6: + _SC_PSET_SUPPORT + pset_create/destroy/assign/setattr + pset_ctl/getattr + pset_bind() + pthread_pset_bind_np() + */ + +#include + +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +static ldom_t +hwloc_hpux_find_ldom(hwloc_topology_t topology, hwloc_const_bitmap_t hwloc_set) +{ + int has_numa = sysconf(_SC_CCNUMA_SUPPORT) == 1; + hwloc_obj_t obj; + + if (!has_numa) + return -1; + + obj = hwloc_get_first_largest_obj_inside_cpuset(topology, hwloc_set); + if (!hwloc_bitmap_isequal(obj->cpuset, hwloc_set)) + /* Does not correspond to exactly one node */ + return -1; + /* obj is the highest possibly matching object, but some (single) child (with same cpuset) could match too */ + while (obj->type != HWLOC_OBJ_NUMANODE) { + /* try the first child, in case it has the same cpuset */ + if (!obj->first_child + || !obj->first_child->cpuset + || !hwloc_bitmap_isequal(obj->cpuset, obj->first_child->cpuset)) + return -1; + obj = obj->first_child; + } + + return obj->os_index; +} + +static spu_t +hwloc_hpux_find_spu(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_const_bitmap_t hwloc_set) +{ + spu_t cpu; + + cpu = hwloc_bitmap_first(hwloc_set); + if (cpu != -1 && hwloc_bitmap_weight(hwloc_set) == 1) + return cpu; + return -1; +} + +/* Note: get_cpubind not available on HP-UX */ +static int +hwloc_hpux_set_proc_cpubind(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_const_bitmap_t hwloc_set, int flags) +{ + ldom_t ldom; + spu_t cpu; + + /* Drop previous binding */ + mpctl(MPC_SETLDOM, MPC_LDOMFLOAT, pid); + mpctl(MPC_SETPROCESS, MPC_SPUFLOAT, pid); + + if (hwloc_bitmap_isequal(hwloc_set, hwloc_topology_get_complete_cpuset(topology))) + return 0; + + ldom = hwloc_hpux_find_ldom(topology, hwloc_set); + if (ldom != -1) + return mpctl(MPC_SETLDOM, ldom, pid); + + cpu = hwloc_hpux_find_spu(topology, hwloc_set); + if (cpu != -1) + return mpctl(flags & HWLOC_CPUBIND_STRICT ? MPC_SETPROCESS_FORCE : MPC_SETPROCESS, cpu, pid); + + errno = EXDEV; + return -1; +} + +static int +hwloc_hpux_set_thisproc_cpubind(hwloc_topology_t topology, hwloc_const_bitmap_t hwloc_set, int flags) +{ + return hwloc_hpux_set_proc_cpubind(topology, MPC_SELFPID, hwloc_set, flags); +} + +#ifdef hwloc_thread_t +static int +hwloc_hpux_set_thread_cpubind(hwloc_topology_t topology, hwloc_thread_t pthread, hwloc_const_bitmap_t hwloc_set, int flags) +{ + ldom_t ldom, ldom2; + spu_t cpu, cpu2; + + /* Drop previous binding */ + pthread_ldom_bind_np(&ldom2, PTHREAD_LDOMFLOAT_NP, pthread); + pthread_processor_bind_np(PTHREAD_BIND_ADVISORY_NP, &cpu2, PTHREAD_SPUFLOAT_NP, pthread); + + if (hwloc_bitmap_isequal(hwloc_set, hwloc_topology_get_complete_cpuset(topology))) + return 0; + + ldom = hwloc_hpux_find_ldom(topology, hwloc_set); + if (ldom != -1) + return pthread_ldom_bind_np(&ldom2, ldom, pthread); + + cpu = hwloc_hpux_find_spu(topology, hwloc_set); + if (cpu != -1) + return pthread_processor_bind_np(flags & HWLOC_CPUBIND_STRICT ? PTHREAD_BIND_FORCED_NP : PTHREAD_BIND_ADVISORY_NP, &cpu2, cpu, pthread); + + errno = EXDEV; + return -1; +} + +static int +hwloc_hpux_set_thisthread_cpubind(hwloc_topology_t topology, hwloc_const_bitmap_t hwloc_set, int flags) +{ + return hwloc_hpux_set_thread_cpubind(topology, PTHREAD_SELFTID_NP, hwloc_set, flags); +} +#endif + +/* According to HP docs, HP-UX up to 11iv2 don't support migration */ + +#ifdef MAP_MEM_FIRST_TOUCH +static void* +hwloc_hpux_alloc_membind(hwloc_topology_t topology, size_t len, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags) +{ + int mmap_flags; + + /* Can not give a set of nodes. */ + if (!hwloc_bitmap_isequal(nodeset, hwloc_topology_get_complete_nodeset(topology))) { + errno = EXDEV; + return hwloc_alloc_or_fail(topology, len, flags); + } + + switch (policy) { + case HWLOC_MEMBIND_DEFAULT: + case HWLOC_MEMBIND_BIND: + mmap_flags = 0; + break; + case HWLOC_MEMBIND_FIRSTTOUCH: + mmap_flags = MAP_MEM_FIRST_TOUCH; + break; + case HWLOC_MEMBIND_INTERLEAVE: + mmap_flags = MAP_MEM_INTERLEAVED; + break; + default: + errno = ENOSYS; + return NULL; + } + + return mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | mmap_flags, -1, 0); +} +#endif /* MAP_MEM_FIRST_TOUCH */ + +static int +hwloc_look_hpux(struct hwloc_backend *backend) +{ + struct hwloc_topology *topology = backend->topology; + int has_numa = sysconf(_SC_CCNUMA_SUPPORT) == 1; + hwloc_obj_t *nodes = NULL, obj; + spu_t currentcpu; + ldom_t currentnode; + int i, nbnodes = 0; + + if (topology->levels[0][0]->cpuset) + /* somebody discovered things */ + return 0; + + hwloc_alloc_obj_cpusets(topology->levels[0][0]); + + if (has_numa) { + nbnodes = mpctl(topology->flags & HWLOC_TOPOLOGY_FLAG_WHOLE_SYSTEM ? + MPC_GETNUMLDOMS_SYS : MPC_GETNUMLDOMS, 0, 0); + + hwloc_debug("%d nodes\n", nbnodes); + + nodes = malloc(nbnodes * sizeof(*nodes)); + + i = 0; + currentnode = mpctl(topology->flags & HWLOC_TOPOLOGY_FLAG_WHOLE_SYSTEM ? + MPC_GETFIRSTLDOM_SYS : MPC_GETFIRSTLDOM, 0, 0); + while (currentnode != -1 && i < nbnodes) { + hwloc_debug("node %d is %d\n", i, currentnode); + nodes[i] = obj = hwloc_alloc_setup_object(HWLOC_OBJ_NUMANODE, currentnode); + obj->cpuset = hwloc_bitmap_alloc(); + obj->nodeset = hwloc_bitmap_alloc(); + hwloc_bitmap_set(obj->nodeset, currentnode); + /* TODO: obj->attr->node.memory_kB */ + /* TODO: obj->attr->node.huge_page_free */ + + currentnode = mpctl(topology->flags & HWLOC_TOPOLOGY_FLAG_WHOLE_SYSTEM ? + MPC_GETNEXTLDOM_SYS : MPC_GETNEXTLDOM, currentnode, 0); + i++; + } + } + + i = 0; + currentcpu = mpctl(topology->flags & HWLOC_TOPOLOGY_FLAG_WHOLE_SYSTEM ? + MPC_GETFIRSTSPU_SYS : MPC_GETFIRSTSPU, 0,0); + while (currentcpu != -1) { + obj = hwloc_alloc_setup_object(HWLOC_OBJ_PU, currentcpu); + obj->cpuset = hwloc_bitmap_alloc(); + hwloc_bitmap_set(obj->cpuset, currentcpu); + + hwloc_debug("cpu %d\n", currentcpu); + + if (nodes) { + /* Add this cpu to its node */ + currentnode = mpctl(MPC_SPUTOLDOM, currentcpu, 0); + /* Hopefully it's just the same as previous cpu */ + if (i >= nbnodes || (ldom_t) nodes[i]->os_index != currentnode) + for (i = 0; i < nbnodes; i++) + if ((ldom_t) nodes[i]->os_index == currentnode) + break; + if (i < nbnodes) { + hwloc_bitmap_set(nodes[i]->cpuset, currentcpu); + hwloc_debug("is in node %d\n", i); + } else { + hwloc_debug("%s", "is in no node?!\n"); + } + } + + /* Add cpu */ + hwloc_insert_object_by_cpuset(topology, obj); + + currentcpu = mpctl(topology->flags & HWLOC_TOPOLOGY_FLAG_WHOLE_SYSTEM ? + MPC_GETNEXTSPU_SYS : MPC_GETNEXTSPU, currentcpu, 0); + } + + if (nodes) { + /* Add nodes */ + for (i = 0 ; i < nbnodes ; i++) + hwloc_insert_object_by_cpuset(topology, nodes[i]); + free(nodes); + } + + topology->support.discovery->pu = 1; + + hwloc_obj_add_info(topology->levels[0][0], "Backend", "HP-UX"); + if (topology->is_thissystem) + hwloc_add_uname_info(topology, NULL); + return 1; +} + +void +hwloc_set_hpux_hooks(struct hwloc_binding_hooks *hooks, + struct hwloc_topology_support *support __hwloc_attribute_unused) +{ + hooks->set_proc_cpubind = hwloc_hpux_set_proc_cpubind; + hooks->set_thisproc_cpubind = hwloc_hpux_set_thisproc_cpubind; +#ifdef hwloc_thread_t + hooks->set_thread_cpubind = hwloc_hpux_set_thread_cpubind; + hooks->set_thisthread_cpubind = hwloc_hpux_set_thisthread_cpubind; +#endif +#ifdef MAP_MEM_FIRST_TOUCH + hooks->alloc_membind = hwloc_hpux_alloc_membind; + hooks->alloc = hwloc_alloc_mmap; + hooks->free_membind = hwloc_free_mmap; + support->membind->firsttouch_membind = 1; + support->membind->bind_membind = 1; + support->membind->interleave_membind = 1; +#endif /* MAP_MEM_FIRST_TOUCH */ +} + +static struct hwloc_backend * +hwloc_hpux_component_instantiate(struct hwloc_disc_component *component, + const void *_data1 __hwloc_attribute_unused, + const void *_data2 __hwloc_attribute_unused, + const void *_data3 __hwloc_attribute_unused) +{ + struct hwloc_backend *backend; + backend = hwloc_backend_alloc(component); + if (!backend) + return NULL; + backend->discover = hwloc_look_hpux; + return backend; +} + +static struct hwloc_disc_component hwloc_hpux_disc_component = { + HWLOC_DISC_COMPONENT_TYPE_CPU, + "hpux", + HWLOC_DISC_COMPONENT_TYPE_GLOBAL, + hwloc_hpux_component_instantiate, + 50, + NULL +}; + +const struct hwloc_component hwloc_hpux_component = { + HWLOC_COMPONENT_ABI, + NULL, NULL, + HWLOC_COMPONENT_TYPE_DISC, + 0, + &hwloc_hpux_disc_component +}; diff --git a/opal/mca/hwloc/hwloc1110/hwloc/src/topology-linux.c b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-linux.c new file mode 100644 index 0000000000..2d9d4da9cd --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-linux.c @@ -0,0 +1,5229 @@ +/* + * Copyright © 2009 CNRS + * Copyright © 2009-2015 Inria. All rights reserved. + * Copyright © 2009-2013 Université Bordeaux + * Copyright © 2009-2014 Cisco Systems, Inc. All rights reserved. + * Copyright © 2015 Intel, Inc. All rights reserved. + * Copyright © 2010 IBM + * See COPYING in top-level directory. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#ifdef HAVE_DIRENT_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_LIBUDEV_H +#include +#endif +#include +#include +#include +#include +#include +#include +#if defined HWLOC_HAVE_SET_MEMPOLICY || defined HWLOC_HAVE_MBIND +#define migratepages migrate_pages /* workaround broken migratepages prototype in numaif.h before libnuma 2.0.2 */ +#include +#endif + +struct hwloc_linux_backend_data_s { + int root_fd; /* The file descriptor for the file system root, used when browsing, e.g., Linux' sysfs and procfs. */ + int is_real_fsroot; /* Boolean saying whether root_fd points to the real filesystem root of the system */ +#ifdef HAVE_LIBUDEV_H + struct udev *udev; /* Global udev context */ +#endif + + struct utsname utsname; /* fields contain \0 when unknown */ + + int deprecated_classlinks_model; /* -2 if never tried, -1 if unknown, 0 if new (device contains class/name), 1 if old (device contains class:name) */ + int mic_need_directlookup; /* if not tried yet, 0 if not needed, 1 if needed */ + unsigned mic_directlookup_id_max; /* -1 if not tried yet, 0 if none to lookup, maxid+1 otherwise */ +}; + + + +/*************************** + * Misc Abstraction layers * + ***************************/ + +#if !(defined HWLOC_HAVE_SCHED_SETAFFINITY) && (defined HWLOC_HAVE__SYSCALL3) +/* libc doesn't have support for sched_setaffinity, build system call + * ourselves: */ +# include +# ifndef __NR_sched_setaffinity +# ifdef __i386__ +# define __NR_sched_setaffinity 241 +# elif defined(__x86_64__) +# define __NR_sched_setaffinity 203 +# elif defined(__ia64__) +# define __NR_sched_setaffinity 1231 +# elif defined(__hppa__) +# define __NR_sched_setaffinity 211 +# elif defined(__alpha__) +# define __NR_sched_setaffinity 395 +# elif defined(__s390__) +# define __NR_sched_setaffinity 239 +# elif defined(__sparc__) +# define __NR_sched_setaffinity 261 +# elif defined(__m68k__) +# define __NR_sched_setaffinity 311 +# elif defined(__powerpc__) || defined(__ppc__) || defined(__PPC__) || defined(__powerpc64__) || defined(__ppc64__) +# define __NR_sched_setaffinity 222 +# elif defined(__arm__) +# define __NR_sched_setaffinity 241 +# elif defined(__cris__) +# define __NR_sched_setaffinity 241 +/*# elif defined(__mips__) + # define __NR_sched_setaffinity TODO (32/64/nabi) */ +# else +# warning "don't know the syscall number for sched_setaffinity on this architecture, will not support binding" +# define sched_setaffinity(pid, lg, mask) (errno = ENOSYS, -1) +# endif +# endif +# ifndef sched_setaffinity + _syscall3(int, sched_setaffinity, pid_t, pid, unsigned int, lg, const void *, mask) +# endif +# ifndef __NR_sched_getaffinity +# ifdef __i386__ +# define __NR_sched_getaffinity 242 +# elif defined(__x86_64__) +# define __NR_sched_getaffinity 204 +# elif defined(__ia64__) +# define __NR_sched_getaffinity 1232 +# elif defined(__hppa__) +# define __NR_sched_getaffinity 212 +# elif defined(__alpha__) +# define __NR_sched_getaffinity 396 +# elif defined(__s390__) +# define __NR_sched_getaffinity 240 +# elif defined(__sparc__) +# define __NR_sched_getaffinity 260 +# elif defined(__m68k__) +# define __NR_sched_getaffinity 312 +# elif defined(__powerpc__) || defined(__ppc__) || defined(__PPC__) || defined(__powerpc64__) || defined(__ppc64__) +# define __NR_sched_getaffinity 223 +# elif defined(__arm__) +# define __NR_sched_getaffinity 242 +# elif defined(__cris__) +# define __NR_sched_getaffinity 242 +/*# elif defined(__mips__) + # define __NR_sched_getaffinity TODO (32/64/nabi) */ +# else +# warning "don't know the syscall number for sched_getaffinity on this architecture, will not support getting binding" +# define sched_getaffinity(pid, lg, mask) (errno = ENOSYS, -1) +# endif +# endif +# ifndef sched_getaffinity + _syscall3(int, sched_getaffinity, pid_t, pid, unsigned int, lg, void *, mask) +# endif +#endif + +/* Added for ntohl() */ +#include + +#ifdef HAVE_OPENAT +/* Use our own filesystem functions if we have openat */ + +static const char * +hwloc_checkat(const char *path, int fsroot_fd) +{ + const char *relative_path; + if (fsroot_fd < 0) { + errno = EBADF; + return NULL; + } + + /* Skip leading slashes. */ + for (relative_path = path; *relative_path == '/'; relative_path++); + + return relative_path; +} + +static int +hwloc_openat(const char *path, int fsroot_fd) +{ + const char *relative_path; + + relative_path = hwloc_checkat(path, fsroot_fd); + if (!relative_path) + return -1; + + return openat (fsroot_fd, relative_path, O_RDONLY); +} + +static FILE * +hwloc_fopenat(const char *path, const char *mode, int fsroot_fd) +{ + int fd; + + if (strcmp(mode, "r")) { + errno = ENOTSUP; + return NULL; + } + + fd = hwloc_openat (path, fsroot_fd); + if (fd == -1) + return NULL; + + return fdopen(fd, mode); +} + +static int +hwloc_accessat(const char *path, int mode, int fsroot_fd) +{ + const char *relative_path; + + relative_path = hwloc_checkat(path, fsroot_fd); + if (!relative_path) + return -1; + + return faccessat(fsroot_fd, relative_path, mode, 0); +} + +static int +hwloc_fstatat(const char *path, struct stat *st, int flags, int fsroot_fd) +{ + const char *relative_path; + + relative_path = hwloc_checkat(path, fsroot_fd); + if (!relative_path) + return -1; + + return fstatat(fsroot_fd, relative_path, st, flags); +} + +static DIR* +hwloc_opendirat(const char *path, int fsroot_fd) +{ + int dir_fd; + const char *relative_path; + + relative_path = hwloc_checkat(path, fsroot_fd); + if (!relative_path) + return NULL; + + dir_fd = openat(fsroot_fd, relative_path, O_RDONLY | O_DIRECTORY); + if (dir_fd < 0) + return NULL; + + return fdopendir(dir_fd); +} + +#endif /* HAVE_OPENAT */ + +/* Static inline version of fopen so that we can use openat if we have + it, but still preserve compiler parameter checking */ +static __hwloc_inline int +hwloc_open(const char *p, int d __hwloc_attribute_unused) +{ +#ifdef HAVE_OPENAT + return hwloc_openat(p, d); +#else + return open(p, O_RDONLY); +#endif +} + +static __hwloc_inline FILE * +hwloc_fopen(const char *p, const char *m, int d __hwloc_attribute_unused) +{ +#ifdef HAVE_OPENAT + return hwloc_fopenat(p, m, d); +#else + return fopen(p, m); +#endif +} + +/* Static inline version of access so that we can use openat if we have + it, but still preserve compiler parameter checking */ +static __hwloc_inline int +hwloc_access(const char *p, int m, int d __hwloc_attribute_unused) +{ +#ifdef HAVE_OPENAT + return hwloc_accessat(p, m, d); +#else + return access(p, m); +#endif +} + +static __hwloc_inline int +hwloc_stat(const char *p, struct stat *st, int d __hwloc_attribute_unused) +{ +#ifdef HAVE_OPENAT + return hwloc_fstatat(p, st, 0, d); +#else + return stat(p, st); +#endif +} + +static __hwloc_inline int +hwloc_lstat(const char *p, struct stat *st, int d __hwloc_attribute_unused) +{ +#ifdef HAVE_OPENAT + return hwloc_fstatat(p, st, AT_SYMLINK_NOFOLLOW, d); +#else + return lstat(p, st); +#endif +} + +/* Static inline version of opendir so that we can use openat if we have + it, but still preserve compiler parameter checking */ +static __hwloc_inline DIR * +hwloc_opendir(const char *p, int d __hwloc_attribute_unused) +{ +#ifdef HAVE_OPENAT + return hwloc_opendirat(p, d); +#else + return opendir(p); +#endif +} + + +/***************************** + ******* CpuBind Hooks ******* + *****************************/ + +int +hwloc_linux_set_tid_cpubind(hwloc_topology_t topology __hwloc_attribute_unused, pid_t tid __hwloc_attribute_unused, hwloc_const_bitmap_t hwloc_set __hwloc_attribute_unused) +{ + /* TODO Kerrighed: Use + * int migrate (pid_t pid, int destination_node); + * int migrate_self (int destination_node); + * int thread_migrate (int thread_id, int destination_node); + */ + + /* The resulting binding is always strict */ + +#if defined(HWLOC_HAVE_CPU_SET_S) && !defined(HWLOC_HAVE_OLD_SCHED_SETAFFINITY) + cpu_set_t *plinux_set; + unsigned cpu; + int last; + size_t setsize; + int err; + + last = hwloc_bitmap_last(hwloc_set); + if (last == -1) { + errno = EINVAL; + return -1; + } + + setsize = CPU_ALLOC_SIZE(last+1); + plinux_set = CPU_ALLOC(last+1); + + CPU_ZERO_S(setsize, plinux_set); + hwloc_bitmap_foreach_begin(cpu, hwloc_set) + CPU_SET_S(cpu, setsize, plinux_set); + hwloc_bitmap_foreach_end(); + + err = sched_setaffinity(tid, setsize, plinux_set); + + CPU_FREE(plinux_set); + return err; +#elif defined(HWLOC_HAVE_CPU_SET) + cpu_set_t linux_set; + unsigned cpu; + + CPU_ZERO(&linux_set); + hwloc_bitmap_foreach_begin(cpu, hwloc_set) + CPU_SET(cpu, &linux_set); + hwloc_bitmap_foreach_end(); + +#ifdef HWLOC_HAVE_OLD_SCHED_SETAFFINITY + return sched_setaffinity(tid, &linux_set); +#else /* HWLOC_HAVE_OLD_SCHED_SETAFFINITY */ + return sched_setaffinity(tid, sizeof(linux_set), &linux_set); +#endif /* HWLOC_HAVE_OLD_SCHED_SETAFFINITY */ +#elif defined(HWLOC_HAVE__SYSCALL3) + unsigned long mask = hwloc_bitmap_to_ulong(hwloc_set); + +#ifdef HWLOC_HAVE_OLD_SCHED_SETAFFINITY + return sched_setaffinity(tid, (void*) &mask); +#else /* HWLOC_HAVE_OLD_SCHED_SETAFFINITY */ + return sched_setaffinity(tid, sizeof(mask), (void*) &mask); +#endif /* HWLOC_HAVE_OLD_SCHED_SETAFFINITY */ +#else /* !_SYSCALL3 */ + errno = ENOSYS; + return -1; +#endif /* !_SYSCALL3 */ +} + +#if defined(HWLOC_HAVE_CPU_SET_S) && !defined(HWLOC_HAVE_OLD_SCHED_SETAFFINITY) +static int +hwloc_linux_parse_cpuset_file(FILE *file, hwloc_bitmap_t set) +{ + unsigned long start, stop; + + /* reset to zero first */ + hwloc_bitmap_zero(set); + + while (fscanf(file, "%lu", &start) == 1) + { + int c = fgetc(file); + + stop = start; + + if (c == '-') { + /* Range */ + if (fscanf(file, "%lu", &stop) != 1) { + /* Expected a number here */ + errno = EINVAL; + return -1; + } + c = fgetc(file); + } + + if (c == EOF || c == '\n') { + hwloc_bitmap_set_range(set, start, stop); + break; + } + + if (c != ',') { + /* Expected EOF, EOL, or a comma */ + errno = EINVAL; + return -1; + } + + hwloc_bitmap_set_range(set, start, stop); + } + + return 0; +} + +/* + * On some kernels, sched_getaffinity requires the output size to be larger + * than the kernel cpu_set size (defined by CONFIG_NR_CPUS). + * Try sched_affinity on ourself until we find a nr_cpus value that makes + * the kernel happy. + */ +static int +hwloc_linux_find_kernel_nr_cpus(hwloc_topology_t topology) +{ + static int _nr_cpus = -1; + int nr_cpus = _nr_cpus; + FILE *possible; + + if (nr_cpus != -1) + /* already computed */ + return nr_cpus; + + if (topology->levels[0][0]->complete_cpuset) + /* start with a nr_cpus that may contain the whole topology */ + nr_cpus = hwloc_bitmap_last(topology->levels[0][0]->complete_cpuset) + 1; + if (nr_cpus <= 0) + /* start from scratch, the topology isn't ready yet (complete_cpuset is missing (-1) or empty (0))*/ + nr_cpus = 1; + + possible = fopen("/sys/devices/system/cpu/possible", "r"); + if (possible) { + hwloc_bitmap_t possible_bitmap = hwloc_bitmap_alloc(); + if (hwloc_linux_parse_cpuset_file(possible, possible_bitmap) == 0) { + int max_possible = hwloc_bitmap_last(possible_bitmap); + + hwloc_debug_bitmap("possible CPUs are %s\n", possible_bitmap); + + if (nr_cpus < max_possible + 1) + nr_cpus = max_possible + 1; + } + fclose(possible); + hwloc_bitmap_free(possible_bitmap); + } + + while (1) { + cpu_set_t *set = CPU_ALLOC(nr_cpus); + size_t setsize = CPU_ALLOC_SIZE(nr_cpus); + int err = sched_getaffinity(0, setsize, set); /* always works, unless setsize is too small */ + CPU_FREE(set); + nr_cpus = setsize * 8; /* that's the value that was actually tested */ + if (!err) + /* found it */ + return _nr_cpus = nr_cpus; + nr_cpus *= 2; + } +} +#endif + +int +hwloc_linux_get_tid_cpubind(hwloc_topology_t topology __hwloc_attribute_unused, pid_t tid __hwloc_attribute_unused, hwloc_bitmap_t hwloc_set __hwloc_attribute_unused) +{ + int err __hwloc_attribute_unused; + /* TODO Kerrighed */ + +#if defined(HWLOC_HAVE_CPU_SET_S) && !defined(HWLOC_HAVE_OLD_SCHED_SETAFFINITY) + cpu_set_t *plinux_set; + unsigned cpu; + int last; + size_t setsize; + int kernel_nr_cpus; + + /* find the kernel nr_cpus so as to use a large enough cpu_set size */ + kernel_nr_cpus = hwloc_linux_find_kernel_nr_cpus(topology); + setsize = CPU_ALLOC_SIZE(kernel_nr_cpus); + plinux_set = CPU_ALLOC(kernel_nr_cpus); + + err = sched_getaffinity(tid, setsize, plinux_set); + + if (err < 0) { + CPU_FREE(plinux_set); + return -1; + } + + last = -1; + if (topology->levels[0][0]->complete_cpuset) + last = hwloc_bitmap_last(topology->levels[0][0]->complete_cpuset); + if (last == -1) + /* round the maximal support number, the topology isn't ready yet (complete_cpuset is missing or empty)*/ + last = kernel_nr_cpus-1; + + hwloc_bitmap_zero(hwloc_set); + for(cpu=0; cpu<=(unsigned) last; cpu++) + if (CPU_ISSET_S(cpu, setsize, plinux_set)) + hwloc_bitmap_set(hwloc_set, cpu); + + CPU_FREE(plinux_set); +#elif defined(HWLOC_HAVE_CPU_SET) + cpu_set_t linux_set; + unsigned cpu; + +#ifdef HWLOC_HAVE_OLD_SCHED_SETAFFINITY + err = sched_getaffinity(tid, &linux_set); +#else /* HWLOC_HAVE_OLD_SCHED_SETAFFINITY */ + err = sched_getaffinity(tid, sizeof(linux_set), &linux_set); +#endif /* HWLOC_HAVE_OLD_SCHED_SETAFFINITY */ + if (err < 0) + return -1; + + hwloc_bitmap_zero(hwloc_set); + for(cpu=0; cpud_name, ".") || !strcmp(dirent->d_name, "..")) + continue; + tids[nr_tids++] = atoi(dirent->d_name); + } + + *nr_tidsp = nr_tids; + *tidsp = tids; + return 0; +} + +/* Per-tid callbacks */ +typedef int (*hwloc_linux_foreach_proc_tid_cb_t)(hwloc_topology_t topology, pid_t tid, void *data, int idx); + +static int +hwloc_linux_foreach_proc_tid(hwloc_topology_t topology, + pid_t pid, hwloc_linux_foreach_proc_tid_cb_t cb, + void *data) +{ + char taskdir_path[128]; + DIR *taskdir; + pid_t *tids, *newtids; + unsigned i, nr, newnr, failed = 0, failed_errno = 0; + unsigned retrynr = 0; + int err; + + if (pid) + snprintf(taskdir_path, sizeof(taskdir_path), "/proc/%u/task", (unsigned) pid); + else + snprintf(taskdir_path, sizeof(taskdir_path), "/proc/self/task"); + + taskdir = opendir(taskdir_path); + if (!taskdir) { + if (errno == ENOENT) + errno = EINVAL; + err = -1; + goto out; + } + + /* read the current list of threads */ + err = hwloc_linux_get_proc_tids(taskdir, &nr, &tids); + if (err < 0) + goto out_with_dir; + + retry: + /* apply the callback to all threads */ + failed=0; + for(i=0; i 10) { + /* we tried 10 times, it didn't work, the application is probably creating/destroying many threads, stop trying */ + errno = EAGAIN; + err = -1; + goto out_with_tids; + } + goto retry; + } else { + free(newtids); + } + + /* if all threads failed, return the last errno. */ + if (failed) { + err = -1; + errno = failed_errno; + goto out_with_tids; + } + + err = 0; + out_with_tids: + free(tids); + out_with_dir: + closedir(taskdir); + out: + return err; +} + +/* Per-tid proc_set_cpubind callback and caller. + * Callback data is a hwloc_bitmap_t. */ +static int +hwloc_linux_foreach_proc_tid_set_cpubind_cb(hwloc_topology_t topology, pid_t tid, void *data, int idx __hwloc_attribute_unused) +{ + return hwloc_linux_set_tid_cpubind(topology, tid, (hwloc_bitmap_t) data); +} + +static int +hwloc_linux_set_pid_cpubind(hwloc_topology_t topology, pid_t pid, hwloc_const_bitmap_t hwloc_set, int flags __hwloc_attribute_unused) +{ + return hwloc_linux_foreach_proc_tid(topology, pid, + hwloc_linux_foreach_proc_tid_set_cpubind_cb, + (void*) hwloc_set); +} + +/* Per-tid proc_get_cpubind callback data, callback function and caller */ +struct hwloc_linux_foreach_proc_tid_get_cpubind_cb_data_s { + hwloc_bitmap_t cpuset; + hwloc_bitmap_t tidset; + int flags; +}; + +static int +hwloc_linux_foreach_proc_tid_get_cpubind_cb(hwloc_topology_t topology, pid_t tid, void *_data, int idx) +{ + struct hwloc_linux_foreach_proc_tid_get_cpubind_cb_data_s *data = _data; + hwloc_bitmap_t cpuset = data->cpuset; + hwloc_bitmap_t tidset = data->tidset; + int flags = data->flags; + + if (hwloc_linux_get_tid_cpubind(topology, tid, tidset)) + return -1; + + /* reset the cpuset on first iteration */ + if (!idx) + hwloc_bitmap_zero(cpuset); + + if (flags & HWLOC_CPUBIND_STRICT) { + /* if STRICT, we want all threads to have the same binding */ + if (!idx) { + /* this is the first thread, copy its binding */ + hwloc_bitmap_copy(cpuset, tidset); + } else if (!hwloc_bitmap_isequal(cpuset, tidset)) { + /* this is not the first thread, and it's binding is different */ + errno = EXDEV; + return -1; + } + } else { + /* if not STRICT, just OR all thread bindings */ + hwloc_bitmap_or(cpuset, cpuset, tidset); + } + return 0; +} + +static int +hwloc_linux_get_pid_cpubind(hwloc_topology_t topology, pid_t pid, hwloc_bitmap_t hwloc_set, int flags) +{ + struct hwloc_linux_foreach_proc_tid_get_cpubind_cb_data_s data; + hwloc_bitmap_t tidset = hwloc_bitmap_alloc(); + int ret; + + data.cpuset = hwloc_set; + data.tidset = tidset; + data.flags = flags; + ret = hwloc_linux_foreach_proc_tid(topology, pid, + hwloc_linux_foreach_proc_tid_get_cpubind_cb, + (void*) &data); + hwloc_bitmap_free(tidset); + return ret; +} + +static int +hwloc_linux_set_proc_cpubind(hwloc_topology_t topology, pid_t pid, hwloc_const_bitmap_t hwloc_set, int flags) +{ + if (pid == 0) + pid = topology->pid; + if (flags & HWLOC_CPUBIND_THREAD) + return hwloc_linux_set_tid_cpubind(topology, pid, hwloc_set); + else + return hwloc_linux_set_pid_cpubind(topology, pid, hwloc_set, flags); +} + +static int +hwloc_linux_get_proc_cpubind(hwloc_topology_t topology, pid_t pid, hwloc_bitmap_t hwloc_set, int flags) +{ + if (pid == 0) + pid = topology->pid; + if (flags & HWLOC_CPUBIND_THREAD) + return hwloc_linux_get_tid_cpubind(topology, pid, hwloc_set); + else + return hwloc_linux_get_pid_cpubind(topology, pid, hwloc_set, flags); +} + +static int +hwloc_linux_set_thisproc_cpubind(hwloc_topology_t topology, hwloc_const_bitmap_t hwloc_set, int flags) +{ + return hwloc_linux_set_pid_cpubind(topology, topology->pid, hwloc_set, flags); +} + +static int +hwloc_linux_get_thisproc_cpubind(hwloc_topology_t topology, hwloc_bitmap_t hwloc_set, int flags) +{ + return hwloc_linux_get_pid_cpubind(topology, topology->pid, hwloc_set, flags); +} + +static int +hwloc_linux_set_thisthread_cpubind(hwloc_topology_t topology, hwloc_const_bitmap_t hwloc_set, int flags __hwloc_attribute_unused) +{ + if (topology->pid) { + errno = ENOSYS; + return -1; + } + return hwloc_linux_set_tid_cpubind(topology, 0, hwloc_set); +} + +static int +hwloc_linux_get_thisthread_cpubind(hwloc_topology_t topology, hwloc_bitmap_t hwloc_set, int flags __hwloc_attribute_unused) +{ + if (topology->pid) { + errno = ENOSYS; + return -1; + } + return hwloc_linux_get_tid_cpubind(topology, 0, hwloc_set); +} + +#if HAVE_DECL_PTHREAD_SETAFFINITY_NP +#pragma weak pthread_setaffinity_np +#pragma weak pthread_self + +static int +hwloc_linux_set_thread_cpubind(hwloc_topology_t topology, pthread_t tid, hwloc_const_bitmap_t hwloc_set, int flags __hwloc_attribute_unused) +{ + int err; + + if (topology->pid) { + errno = ENOSYS; + return -1; + } + + if (!pthread_self) { + /* ?! Application uses set_thread_cpubind, but doesn't link against libpthread ?! */ + errno = ENOSYS; + return -1; + } + if (tid == pthread_self()) + return hwloc_linux_set_tid_cpubind(topology, 0, hwloc_set); + + if (!pthread_setaffinity_np) { + errno = ENOSYS; + return -1; + } + /* TODO Kerrighed: Use + * int migrate (pid_t pid, int destination_node); + * int migrate_self (int destination_node); + * int thread_migrate (int thread_id, int destination_node); + */ + +#if defined(HWLOC_HAVE_CPU_SET_S) && !defined(HWLOC_HAVE_OLD_SCHED_SETAFFINITY) + /* Use a separate block so that we can define specific variable + types here */ + { + cpu_set_t *plinux_set; + unsigned cpu; + int last; + size_t setsize; + + last = hwloc_bitmap_last(hwloc_set); + if (last == -1) { + errno = EINVAL; + return -1; + } + + setsize = CPU_ALLOC_SIZE(last+1); + plinux_set = CPU_ALLOC(last+1); + + CPU_ZERO_S(setsize, plinux_set); + hwloc_bitmap_foreach_begin(cpu, hwloc_set) + CPU_SET_S(cpu, setsize, plinux_set); + hwloc_bitmap_foreach_end(); + + err = pthread_setaffinity_np(tid, setsize, plinux_set); + + CPU_FREE(plinux_set); + } +#elif defined(HWLOC_HAVE_CPU_SET) + /* Use a separate block so that we can define specific variable + types here */ + { + cpu_set_t linux_set; + unsigned cpu; + + CPU_ZERO(&linux_set); + hwloc_bitmap_foreach_begin(cpu, hwloc_set) + CPU_SET(cpu, &linux_set); + hwloc_bitmap_foreach_end(); + +#ifdef HWLOC_HAVE_OLD_SCHED_SETAFFINITY + err = pthread_setaffinity_np(tid, &linux_set); +#else /* HWLOC_HAVE_OLD_SCHED_SETAFFINITY */ + err = pthread_setaffinity_np(tid, sizeof(linux_set), &linux_set); +#endif /* HWLOC_HAVE_OLD_SCHED_SETAFFINITY */ + } +#else /* CPU_SET */ + /* Use a separate block so that we can define specific variable + types here */ + { + unsigned long mask = hwloc_bitmap_to_ulong(hwloc_set); + +#ifdef HWLOC_HAVE_OLD_SCHED_SETAFFINITY + err = pthread_setaffinity_np(tid, (void*) &mask); +#else /* HWLOC_HAVE_OLD_SCHED_SETAFFINITY */ + err = pthread_setaffinity_np(tid, sizeof(mask), (void*) &mask); +#endif /* HWLOC_HAVE_OLD_SCHED_SETAFFINITY */ + } +#endif /* CPU_SET */ + + if (err) { + errno = err; + return -1; + } + return 0; +} +#endif /* HAVE_DECL_PTHREAD_SETAFFINITY_NP */ + +#if HAVE_DECL_PTHREAD_GETAFFINITY_NP +#pragma weak pthread_getaffinity_np +#pragma weak pthread_self + +static int +hwloc_linux_get_thread_cpubind(hwloc_topology_t topology, pthread_t tid, hwloc_bitmap_t hwloc_set, int flags __hwloc_attribute_unused) +{ + int err; + + if (topology->pid) { + errno = ENOSYS; + return -1; + } + + if (!pthread_self) { + /* ?! Application uses set_thread_cpubind, but doesn't link against libpthread ?! */ + errno = ENOSYS; + return -1; + } + if (tid == pthread_self()) + return hwloc_linux_get_tid_cpubind(topology, 0, hwloc_set); + + if (!pthread_getaffinity_np) { + errno = ENOSYS; + return -1; + } + /* TODO Kerrighed */ + +#if defined(HWLOC_HAVE_CPU_SET_S) && !defined(HWLOC_HAVE_OLD_SCHED_SETAFFINITY) + /* Use a separate block so that we can define specific variable + types here */ + { + cpu_set_t *plinux_set; + unsigned cpu; + int last; + size_t setsize; + + last = hwloc_bitmap_last(topology->levels[0][0]->complete_cpuset); + assert (last != -1); + + setsize = CPU_ALLOC_SIZE(last+1); + plinux_set = CPU_ALLOC(last+1); + + err = pthread_getaffinity_np(tid, setsize, plinux_set); + if (err) { + CPU_FREE(plinux_set); + errno = err; + return -1; + } + + hwloc_bitmap_zero(hwloc_set); + for(cpu=0; cpu<=(unsigned) last; cpu++) + if (CPU_ISSET_S(cpu, setsize, plinux_set)) + hwloc_bitmap_set(hwloc_set, cpu); + + CPU_FREE(plinux_set); + } +#elif defined(HWLOC_HAVE_CPU_SET) + /* Use a separate block so that we can define specific variable + types here */ + { + cpu_set_t linux_set; + unsigned cpu; + +#ifdef HWLOC_HAVE_OLD_SCHED_SETAFFINITY + err = pthread_getaffinity_np(tid, &linux_set); +#else /* HWLOC_HAVE_OLD_SCHED_SETAFFINITY */ + err = pthread_getaffinity_np(tid, sizeof(linux_set), &linux_set); +#endif /* HWLOC_HAVE_OLD_SCHED_SETAFFINITY */ + if (err) { + errno = err; + return -1; + } + + hwloc_bitmap_zero(hwloc_set); + for(cpu=0; cpucpuset; + hwloc_bitmap_t tidset = data->tidset; + + if (hwloc_linux_get_tid_last_cpu_location(topology, tid, tidset)) + return -1; + + /* reset the cpuset on first iteration */ + if (!idx) + hwloc_bitmap_zero(cpuset); + + hwloc_bitmap_or(cpuset, cpuset, tidset); + return 0; +} + +static int +hwloc_linux_get_pid_last_cpu_location(hwloc_topology_t topology, pid_t pid, hwloc_bitmap_t hwloc_set, int flags __hwloc_attribute_unused) +{ + struct hwloc_linux_foreach_proc_tid_get_last_cpu_location_cb_data_s data; + hwloc_bitmap_t tidset = hwloc_bitmap_alloc(); + int ret; + + data.cpuset = hwloc_set; + data.tidset = tidset; + ret = hwloc_linux_foreach_proc_tid(topology, pid, + hwloc_linux_foreach_proc_tid_get_last_cpu_location_cb, + &data); + hwloc_bitmap_free(tidset); + return ret; +} + +static int +hwloc_linux_get_proc_last_cpu_location(hwloc_topology_t topology, pid_t pid, hwloc_bitmap_t hwloc_set, int flags) +{ + if (pid == 0) + pid = topology->pid; + if (flags & HWLOC_CPUBIND_THREAD) + return hwloc_linux_get_tid_last_cpu_location(topology, pid, hwloc_set); + else + return hwloc_linux_get_pid_last_cpu_location(topology, pid, hwloc_set, flags); +} + +static int +hwloc_linux_get_thisproc_last_cpu_location(hwloc_topology_t topology, hwloc_bitmap_t hwloc_set, int flags) +{ + return hwloc_linux_get_pid_last_cpu_location(topology, topology->pid, hwloc_set, flags); +} + +static int +hwloc_linux_get_thisthread_last_cpu_location(hwloc_topology_t topology, hwloc_bitmap_t hwloc_set, int flags __hwloc_attribute_unused) +{ + if (topology->pid) { + errno = ENOSYS; + return -1; + } + return hwloc_linux_get_tid_last_cpu_location(topology, 0, hwloc_set); +} + + + +/*************************** + ****** Membind hooks ****** + ***************************/ + +#if defined HWLOC_HAVE_SET_MEMPOLICY || defined HWLOC_HAVE_MBIND +static int +hwloc_linux_membind_policy_from_hwloc(int *linuxpolicy, hwloc_membind_policy_t policy, int flags) +{ + switch (policy) { + case HWLOC_MEMBIND_DEFAULT: + case HWLOC_MEMBIND_FIRSTTOUCH: + *linuxpolicy = MPOL_DEFAULT; + break; + case HWLOC_MEMBIND_BIND: + if (flags & HWLOC_MEMBIND_STRICT) + *linuxpolicy = MPOL_BIND; + else + *linuxpolicy = MPOL_PREFERRED; + break; + case HWLOC_MEMBIND_INTERLEAVE: + *linuxpolicy = MPOL_INTERLEAVE; + break; + /* TODO: next-touch when (if?) patch applied upstream */ + default: + errno = ENOSYS; + return -1; + } + return 0; +} + +static int +hwloc_linux_membind_mask_from_nodeset(hwloc_topology_t topology __hwloc_attribute_unused, + hwloc_const_nodeset_t nodeset, + unsigned *max_os_index_p, unsigned long **linuxmaskp) +{ + unsigned max_os_index = 0; /* highest os_index + 1 */ + unsigned long *linuxmask; + unsigned i; + hwloc_nodeset_t linux_nodeset = NULL; + + if (hwloc_bitmap_isfull(nodeset)) { + linux_nodeset = hwloc_bitmap_alloc(); + hwloc_bitmap_only(linux_nodeset, 0); + nodeset = linux_nodeset; + } + + max_os_index = hwloc_bitmap_last(nodeset); + if (max_os_index == (unsigned) -1) + max_os_index = 0; + /* add 1 to convert the last os_index into a max_os_index, + * and round up to the nearest multiple of BITS_PER_LONG */ + max_os_index = (max_os_index + 1 + HWLOC_BITS_PER_LONG - 1) & ~(HWLOC_BITS_PER_LONG - 1); + + linuxmask = calloc(max_os_index/HWLOC_BITS_PER_LONG, sizeof(long)); + if (!linuxmask) { + hwloc_bitmap_free(linux_nodeset); + errno = ENOMEM; + return -1; + } + + for(i=0; iset_thisthread_cpubind = hwloc_linux_set_thisthread_cpubind; + hooks->get_thisthread_cpubind = hwloc_linux_get_thisthread_cpubind; + hooks->set_thisproc_cpubind = hwloc_linux_set_thisproc_cpubind; + hooks->get_thisproc_cpubind = hwloc_linux_get_thisproc_cpubind; + hooks->set_proc_cpubind = hwloc_linux_set_proc_cpubind; + hooks->get_proc_cpubind = hwloc_linux_get_proc_cpubind; +#if HAVE_DECL_PTHREAD_SETAFFINITY_NP + hooks->set_thread_cpubind = hwloc_linux_set_thread_cpubind; +#endif /* HAVE_DECL_PTHREAD_SETAFFINITY_NP */ +#if HAVE_DECL_PTHREAD_GETAFFINITY_NP + hooks->get_thread_cpubind = hwloc_linux_get_thread_cpubind; +#endif /* HAVE_DECL_PTHREAD_GETAFFINITY_NP */ + hooks->get_thisthread_last_cpu_location = hwloc_linux_get_thisthread_last_cpu_location; + hooks->get_thisproc_last_cpu_location = hwloc_linux_get_thisproc_last_cpu_location; + hooks->get_proc_last_cpu_location = hwloc_linux_get_proc_last_cpu_location; +#ifdef HWLOC_HAVE_SET_MEMPOLICY + hooks->set_thisthread_membind = hwloc_linux_set_thisthread_membind; + hooks->get_thisthread_membind = hwloc_linux_get_thisthread_membind; + hooks->get_area_membind = hwloc_linux_get_area_membind; +#endif /* HWLOC_HAVE_SET_MEMPOLICY */ +#ifdef HWLOC_HAVE_MBIND + hooks->set_area_membind = hwloc_linux_set_area_membind; + hooks->alloc_membind = hwloc_linux_alloc_membind; + hooks->alloc = hwloc_alloc_mmap; + hooks->free_membind = hwloc_free_mmap; + support->membind->firsttouch_membind = 1; + support->membind->bind_membind = 1; + support->membind->interleave_membind = 1; +#endif /* HWLOC_HAVE_MBIND */ +#if (defined HWLOC_HAVE_MIGRATE_PAGES) || ((defined HWLOC_HAVE_MBIND) && (defined MPOL_MF_MOVE)) + support->membind->migrate_membind = 1; +#endif +} + + + +/******************************************* + *** Misc Helpers for Topology Discovery *** + *******************************************/ + +/* cpuinfo array */ +struct hwloc_linux_cpuinfo_proc { + /* set during hwloc_linux_parse_cpuinfo */ + unsigned long Pproc; + /* set during hwloc_linux_parse_cpuinfo or -1 if unknown*/ + long Pcore, Ppkg; + /* set later, or -1 if unknown */ + long Lcore, Lpkg; + + /* custom info, set during hwloc_linux_parse_cpuinfo */ + struct hwloc_obj_info_s *infos; + unsigned infos_count; +}; + +static int +hwloc_parse_sysfs_unsigned(const char *mappath, unsigned *value, int fsroot_fd) +{ + char string[11]; + FILE * fd; + + fd = hwloc_fopen(mappath, "r", fsroot_fd); + if (!fd) { + *value = -1; + return -1; + } + + if (!fgets(string, 11, fd)) { + *value = -1; + fclose(fd); + return -1; + } + *value = strtoul(string, NULL, 10); + + fclose(fd); + + return 0; +} + + +/* kernel cpumaps are composed of an array of 32bits cpumasks */ +#define KERNEL_CPU_MASK_BITS 32 +#define KERNEL_CPU_MAP_LEN (KERNEL_CPU_MASK_BITS/4+2) + +int +hwloc_linux_parse_cpumap_file(FILE *file, hwloc_bitmap_t set) +{ + unsigned long *maps; + unsigned long map; + int nr_maps = 0; + static int nr_maps_allocated = 8; /* only compute the power-of-two above the kernel cpumask size once */ + int i; + + maps = malloc(nr_maps_allocated * sizeof(*maps)); + + /* reset to zero first */ + hwloc_bitmap_zero(set); + + /* parse the whole mask */ + while (fscanf(file, "%lx,", &map) == 1) /* read one kernel cpu mask and the ending comma */ + { + if (nr_maps == nr_maps_allocated) { + nr_maps_allocated *= 2; + maps = realloc(maps, nr_maps_allocated * sizeof(*maps)); + } + + if (!map && !nr_maps) + /* ignore the first map if it's empty */ + continue; + + memmove(&maps[1], &maps[0], nr_maps*sizeof(*maps)); + maps[0] = map; + nr_maps++; + } + + /* convert into a set */ +#if KERNEL_CPU_MASK_BITS == HWLOC_BITS_PER_LONG + for(i=0; i. If cpuset are used they get /proc/pid/cpuset + * containing . + */ +static char * +hwloc_read_linux_cpuset_name(int fsroot_fd, hwloc_pid_t pid) +{ +#define CPUSET_NAME_LEN 128 + char cpuset_name[CPUSET_NAME_LEN]; + FILE *fd; + char *tmp; + + /* check whether a cgroup-cpuset is enabled */ + if (!pid) + fd = hwloc_fopen("/proc/self/cgroup", "r", fsroot_fd); + else { + char path[] = "/proc/XXXXXXXXXX/cgroup"; + snprintf(path, sizeof(path), "/proc/%d/cgroup", pid); + fd = hwloc_fopen(path, "r", fsroot_fd); + } + if (fd) { + /* find a cpuset line */ +#define CGROUP_LINE_LEN 256 + char line[CGROUP_LINE_LEN]; + while (fgets(line, sizeof(line), fd)) { + char *end, *colon = strchr(line, ':'); + if (!colon) + continue; + if (strncmp(colon, ":cpuset:", 8)) + continue; + + /* found a cgroup-cpuset line, return the name */ + fclose(fd); + end = strchr(colon, '\n'); + if (end) + *end = '\0'; + hwloc_debug("Found cgroup-cpuset %s\n", colon+8); + return strdup(colon+8); + } + fclose(fd); + } + + /* check whether a cpuset is enabled */ + if (!pid) + fd = hwloc_fopen("/proc/self/cpuset", "r", fsroot_fd); + else { + char path[] = "/proc/XXXXXXXXXX/cpuset"; + snprintf(path, sizeof(path), "/proc/%d/cpuset", pid); + fd = hwloc_fopen(path, "r", fsroot_fd); + } + if (!fd) { + /* found nothing */ + hwloc_debug("%s", "No cgroup or cpuset found\n"); + return NULL; + } + + /* found a cpuset, return the name */ + tmp = fgets(cpuset_name, sizeof(cpuset_name), fd); + fclose(fd); + if (!tmp) + return NULL; + tmp = strchr(cpuset_name, '\n'); + if (tmp) + *tmp = '\0'; + hwloc_debug("Found cpuset %s\n", cpuset_name); + return strdup(cpuset_name); +} + +/* + * Then, the cpuset description is available from either the cgroup or + * the cpuset filesystem (usually mounted in / or /dev) where there + * are cgroup/cpuset.{cpus,mems} or cpuset/{cpus,mems} files. + */ +static char * +hwloc_read_linux_cpuset_mask(const char *cgroup_mntpnt, const char *cpuset_mntpnt, const char *cpuset_name, const char *attr_name, int fsroot_fd) +{ +#define CPUSET_FILENAME_LEN 256 + char cpuset_filename[CPUSET_FILENAME_LEN]; + FILE *fd; + char *info = NULL, *tmp; + ssize_t ssize; + size_t size; + + if (cgroup_mntpnt) { + /* try to read the cpuset from cgroup */ + snprintf(cpuset_filename, CPUSET_FILENAME_LEN, "%s%s/cpuset.%s", cgroup_mntpnt, cpuset_name, attr_name); + hwloc_debug("Trying to read cgroup file <%s>\n", cpuset_filename); + fd = hwloc_fopen(cpuset_filename, "r", fsroot_fd); + if (fd) + goto gotfile; + } else if (cpuset_mntpnt) { + /* try to read the cpuset directly */ + snprintf(cpuset_filename, CPUSET_FILENAME_LEN, "%s%s/%s", cpuset_mntpnt, cpuset_name, attr_name); + hwloc_debug("Trying to read cpuset file <%s>\n", cpuset_filename); + fd = hwloc_fopen(cpuset_filename, "r", fsroot_fd); + if (fd) + goto gotfile; + } + + /* found no cpuset description, ignore it */ + hwloc_debug("Couldn't find cpuset <%s> description, ignoring\n", cpuset_name); + goto out; + +gotfile: + ssize = getline(&info, &size, fd); + fclose(fd); + if (ssize < 0) + goto out; + if (!info) + goto out; + + tmp = strchr(info, '\n'); + if (tmp) + *tmp = '\0'; + +out: + return info; +} + +static void +hwloc_admin_disable_set_from_cpuset(struct hwloc_linux_backend_data_s *data, + const char *cgroup_mntpnt, const char *cpuset_mntpnt, const char *cpuset_name, + const char *attr_name, + hwloc_bitmap_t admin_enabled_cpus_set) +{ + char *cpuset_mask; + char *current, *comma, *tmp; + int prevlast, nextfirst, nextlast; /* beginning/end of enabled-segments */ + hwloc_bitmap_t tmpset; + + cpuset_mask = hwloc_read_linux_cpuset_mask(cgroup_mntpnt, cpuset_mntpnt, cpuset_name, + attr_name, data->root_fd); + if (!cpuset_mask) + return; + + hwloc_debug("found cpuset %s: %s\n", attr_name, cpuset_mask); + + current = cpuset_mask; + prevlast = -1; + + while (1) { + /* save a pointer to the next comma and erase it to simplify things */ + comma = strchr(current, ','); + if (comma) + *comma = '\0'; + + /* find current enabled-segment bounds */ + nextfirst = strtoul(current, &tmp, 0); + if (*tmp == '-') + nextlast = strtoul(tmp+1, NULL, 0); + else + nextlast = nextfirst; + if (prevlast+1 <= nextfirst-1) { + hwloc_debug("%s [%d:%d] excluded by cpuset\n", attr_name, prevlast+1, nextfirst-1); + hwloc_bitmap_clr_range(admin_enabled_cpus_set, prevlast+1, nextfirst-1); + } + + /* switch to next enabled-segment */ + prevlast = nextlast; + if (!comma) + break; + current = comma+1; + } + + hwloc_debug("%s [%d:%d] excluded by cpuset\n", attr_name, prevlast+1, nextfirst-1); + /* no easy way to clear until the infinity */ + tmpset = hwloc_bitmap_alloc(); + hwloc_bitmap_set_range(tmpset, 0, prevlast); + hwloc_bitmap_and(admin_enabled_cpus_set, admin_enabled_cpus_set, tmpset); + hwloc_bitmap_free(tmpset); + + free(cpuset_mask); +} + +static void +hwloc_parse_meminfo_info(struct hwloc_linux_backend_data_s *data, + const char *path, + int prefixlength, + uint64_t *local_memory, + uint64_t *meminfo_hugepages_count, + uint64_t *meminfo_hugepages_size, + int onlytotal) +{ + char string[64]; + FILE *fd; + + fd = hwloc_fopen(path, "r", data->root_fd); + if (!fd) + return; + + while (fgets(string, sizeof(string), fd) && *string != '\0') + { + unsigned long long number; + if (strlen(string) < (size_t) prefixlength) + continue; + if (sscanf(string+prefixlength, "MemTotal: %llu kB", (unsigned long long *) &number) == 1) { + *local_memory = number << 10; + if (onlytotal) + break; + } + else if (!onlytotal) { + if (sscanf(string+prefixlength, "Hugepagesize: %llu", (unsigned long long *) &number) == 1) + *meminfo_hugepages_size = number << 10; + else if (sscanf(string+prefixlength, "HugePages_Free: %llu", (unsigned long long *) &number) == 1) + /* these are free hugepages, not the total amount of huge pages */ + *meminfo_hugepages_count = number; + } + } + + fclose(fd); +} + +#define SYSFS_NUMA_NODE_PATH_LEN 128 + +static void +hwloc_parse_hugepages_info(struct hwloc_linux_backend_data_s *data, + const char *dirpath, + struct hwloc_obj_memory_s *memory, + uint64_t *remaining_local_memory) +{ + DIR *dir; + struct dirent *dirent; + unsigned long index_ = 1; + FILE *hpfd; + char line[64]; + char path[SYSFS_NUMA_NODE_PATH_LEN]; + + dir = hwloc_opendir(dirpath, data->root_fd); + if (dir) { + while ((dirent = readdir(dir)) != NULL) { + if (strncmp(dirent->d_name, "hugepages-", 10)) + continue; + memory->page_types[index_].size = strtoul(dirent->d_name+10, NULL, 0) * 1024ULL; + sprintf(path, "%s/%s/nr_hugepages", dirpath, dirent->d_name); + hpfd = hwloc_fopen(path, "r", data->root_fd); + if (hpfd) { + if (fgets(line, sizeof(line), hpfd)) { + /* these are the actual total amount of huge pages */ + memory->page_types[index_].count = strtoull(line, NULL, 0); + *remaining_local_memory -= memory->page_types[index_].count * memory->page_types[index_].size; + index_++; + } + fclose(hpfd); + } + } + closedir(dir); + memory->page_types_len = index_; + } +} + +static void +hwloc_get_kerrighed_node_meminfo_info(struct hwloc_topology *topology, + struct hwloc_linux_backend_data_s *data, + unsigned long node, struct hwloc_obj_memory_s *memory) +{ + char path[128]; + uint64_t meminfo_hugepages_count, meminfo_hugepages_size = 0; + + if (topology->is_thissystem) { + memory->page_types_len = 2; + memory->page_types = malloc(2*sizeof(*memory->page_types)); + memset(memory->page_types, 0, 2*sizeof(*memory->page_types)); + /* Try to get the hugepage size from sysconf in case we fail to get it from /proc/meminfo later */ +#ifdef HAVE__SC_LARGE_PAGESIZE + memory->page_types[1].size = sysconf(_SC_LARGE_PAGESIZE); +#endif + memory->page_types[0].size = hwloc_getpagesize(); + } + + snprintf(path, sizeof(path), "/proc/nodes/node%lu/meminfo", node); + hwloc_parse_meminfo_info(data, path, 0 /* no prefix */, + &memory->local_memory, + &meminfo_hugepages_count, &meminfo_hugepages_size, + memory->page_types == NULL); + + if (memory->page_types) { + uint64_t remaining_local_memory = memory->local_memory; + if (meminfo_hugepages_size) { + memory->page_types[1].size = meminfo_hugepages_size; + memory->page_types[1].count = meminfo_hugepages_count; + remaining_local_memory -= meminfo_hugepages_count * meminfo_hugepages_size; + } else { + memory->page_types_len = 1; + } + memory->page_types[0].count = remaining_local_memory / memory->page_types[0].size; + } +} + +static void +hwloc_get_procfs_meminfo_info(struct hwloc_topology *topology, + struct hwloc_linux_backend_data_s *data, + struct hwloc_obj_memory_s *memory) +{ + uint64_t meminfo_hugepages_count, meminfo_hugepages_size = 0; + struct stat st; + int has_sysfs_hugepages = 0; + const char *pagesize_env = getenv("HWLOC_DEBUG_PAGESIZE"); + int types = 2; + int err; + + err = hwloc_stat("/sys/kernel/mm/hugepages", &st, data->root_fd); + if (!err) { + types = 1 + st.st_nlink-2; + has_sysfs_hugepages = 1; + } + + if (topology->is_thissystem || pagesize_env) { + /* we cannot report any page_type info unless we have the page size. + * we'll take it either from the system if local, or from the debug env variable + */ + memory->page_types_len = types; + memory->page_types = calloc(types, sizeof(*memory->page_types)); + } + + if (topology->is_thissystem) { + /* Get the page and hugepage sizes from sysconf */ +#ifdef HAVE__SC_LARGE_PAGESIZE + memory->page_types[1].size = sysconf(_SC_LARGE_PAGESIZE); +#endif + memory->page_types[0].size = hwloc_getpagesize(); /* might be overwritten later by /proc/meminfo or sysfs */ + } + + hwloc_parse_meminfo_info(data, "/proc/meminfo", 0 /* no prefix */, + &memory->local_memory, + &meminfo_hugepages_count, &meminfo_hugepages_size, + memory->page_types == NULL); + + if (memory->page_types) { + uint64_t remaining_local_memory = memory->local_memory; + if (has_sysfs_hugepages) { + /* read from node%d/hugepages/hugepages-%skB/nr_hugepages */ + hwloc_parse_hugepages_info(data, "/sys/kernel/mm/hugepages", memory, &remaining_local_memory); + } else { + /* use what we found in meminfo */ + if (meminfo_hugepages_size) { + memory->page_types[1].size = meminfo_hugepages_size; + memory->page_types[1].count = meminfo_hugepages_count; + remaining_local_memory -= meminfo_hugepages_count * meminfo_hugepages_size; + } else { + memory->page_types_len = 1; + } + } + + if (pagesize_env) { + /* We cannot get the pagesize if not thissystem, use the env-given one to experience the code during make check */ + memory->page_types[0].size = strtoull(pagesize_env, NULL, 10); + /* If failed, use 4kB */ + if (!memory->page_types[0].size) + memory->page_types[0].size = 4096; + } + assert(memory->page_types[0].size); /* from sysconf if local or from the env */ + /* memory->page_types[1].size from sysconf if local, or from /proc/meminfo, or from sysfs, + * may be 0 if no hugepage support in the kernel */ + + memory->page_types[0].count = remaining_local_memory / memory->page_types[0].size; + } +} + +static void +hwloc_sysfs_node_meminfo_info(struct hwloc_topology *topology, + struct hwloc_linux_backend_data_s *data, + const char *syspath, int node, + struct hwloc_obj_memory_s *memory) +{ + char path[SYSFS_NUMA_NODE_PATH_LEN]; + char meminfopath[SYSFS_NUMA_NODE_PATH_LEN]; + uint64_t meminfo_hugepages_count = 0; + uint64_t meminfo_hugepages_size = 0; + struct stat st; + int has_sysfs_hugepages = 0; + int types = 2; + int err; + + sprintf(path, "%s/node%d/hugepages", syspath, node); + err = hwloc_stat(path, &st, data->root_fd); + if (!err) { + types = 1 + st.st_nlink-2; + has_sysfs_hugepages = 1; + } + + if (topology->is_thissystem) { + memory->page_types_len = types; + memory->page_types = malloc(types*sizeof(*memory->page_types)); + memset(memory->page_types, 0, types*sizeof(*memory->page_types)); + } + + sprintf(meminfopath, "%s/node%d/meminfo", syspath, node); + hwloc_parse_meminfo_info(data, meminfopath, + snprintf(NULL, 0, "Node %d ", node), + &memory->local_memory, + &meminfo_hugepages_count, NULL /* no hugepage size in node-specific meminfo */, + memory->page_types == NULL); + + if (memory->page_types) { + uint64_t remaining_local_memory = memory->local_memory; + if (has_sysfs_hugepages) { + /* read from node%d/hugepages/hugepages-%skB/nr_hugepages */ + hwloc_parse_hugepages_info(data, path, memory, &remaining_local_memory); + } else { + /* get hugepage size from machine-specific meminfo since there is no size in node-specific meminfo, + * hwloc_get_procfs_meminfo_info must have been called earlier */ + meminfo_hugepages_size = topology->levels[0][0]->memory.page_types[1].size; + /* use what we found in meminfo */ + if (meminfo_hugepages_size) { + memory->page_types[1].count = meminfo_hugepages_count; + memory->page_types[1].size = meminfo_hugepages_size; + remaining_local_memory -= meminfo_hugepages_count * meminfo_hugepages_size; + } else { + memory->page_types_len = 1; + } + } + /* update what's remaining as normal pages */ + memory->page_types[0].size = hwloc_getpagesize(); + memory->page_types[0].count = remaining_local_memory / memory->page_types[0].size; + } +} + +static void +hwloc_parse_node_distance(const char *distancepath, unsigned nbnodes, float *distances, int fsroot_fd) +{ + char string[4096]; /* enough for hundreds of nodes */ + char *tmp, *next; + FILE * fd; + + fd = hwloc_fopen(distancepath, "r", fsroot_fd); + if (!fd) + return; + + if (!fgets(string, sizeof(string), fd)) { + fclose(fd); + return; + } + + tmp = string; + while (tmp) { + unsigned distance = strtoul(tmp, &next, 0); + if (next == tmp) + break; + *distances = (float) distance; + distances++; + nbnodes--; + if (!nbnodes) + break; + tmp = next+1; + } + + fclose(fd); +} + +static void +hwloc__get_dmi_id_one_info(struct hwloc_linux_backend_data_s *data, + hwloc_obj_t obj, + char *path, unsigned pathlen, + const char *dmi_name, const char *hwloc_name) +{ + char dmi_line[64]; + char *tmp; + FILE *fd; + + strcpy(path+pathlen, dmi_name); + fd = hwloc_fopen(path, "r", data->root_fd); + if (!fd) + return; + + dmi_line[0] = '\0'; + tmp = fgets(dmi_line, sizeof(dmi_line), fd); + fclose (fd); + + if (tmp && dmi_line[0] != '\0') { + tmp = strchr(dmi_line, '\n'); + if (tmp) + *tmp = '\0'; + hwloc_debug("found %s '%s'\n", hwloc_name, dmi_line); + hwloc_obj_add_info(obj, hwloc_name, dmi_line); + } +} + +static void +hwloc__get_dmi_id_info(struct hwloc_linux_backend_data_s *data, hwloc_obj_t obj) +{ + char path[128]; + unsigned pathlen; + DIR *dir; + + strcpy(path, "/sys/devices/virtual/dmi/id"); + dir = hwloc_opendir(path, data->root_fd); + if (dir) { + pathlen = 27; + } else { + strcpy(path, "/sys/class/dmi/id"); + dir = hwloc_opendir(path, data->root_fd); + if (dir) + pathlen = 17; + else + return; + } + closedir(dir); + + path[pathlen++] = '/'; + + hwloc__get_dmi_id_one_info(data, obj, path, pathlen, "product_name", "DMIProductName"); + hwloc__get_dmi_id_one_info(data, obj, path, pathlen, "product_version", "DMIProductVersion"); + hwloc__get_dmi_id_one_info(data, obj, path, pathlen, "product_serial", "DMIProductSerial"); + hwloc__get_dmi_id_one_info(data, obj, path, pathlen, "product_uuid", "DMIProductUUID"); + hwloc__get_dmi_id_one_info(data, obj, path, pathlen, "board_vendor", "DMIBoardVendor"); + hwloc__get_dmi_id_one_info(data, obj, path, pathlen, "board_name", "DMIBoardName"); + hwloc__get_dmi_id_one_info(data, obj, path, pathlen, "board_version", "DMIBoardVersion"); + hwloc__get_dmi_id_one_info(data, obj, path, pathlen, "board_serial", "DMIBoardSerial"); + hwloc__get_dmi_id_one_info(data, obj, path, pathlen, "board_asset_tag", "DMIBoardAssetTag"); + hwloc__get_dmi_id_one_info(data, obj, path, pathlen, "chassis_vendor", "DMIChassisVendor"); + hwloc__get_dmi_id_one_info(data, obj, path, pathlen, "chassis_type", "DMIChassisType"); + hwloc__get_dmi_id_one_info(data, obj, path, pathlen, "chassis_version", "DMIChassisVersion"); + hwloc__get_dmi_id_one_info(data, obj, path, pathlen, "chassis_serial", "DMIChassisSerial"); + hwloc__get_dmi_id_one_info(data, obj, path, pathlen, "chassis_asset_tag", "DMIChassisAssetTag"); + hwloc__get_dmi_id_one_info(data, obj, path, pathlen, "bios_vendor", "DMIBIOSVendor"); + hwloc__get_dmi_id_one_info(data, obj, path, pathlen, "bios_version", "DMIBIOSVersion"); + hwloc__get_dmi_id_one_info(data, obj, path, pathlen, "bios_date", "DMIBIOSDate"); + hwloc__get_dmi_id_one_info(data, obj, path, pathlen, "sys_vendor", "DMISysVendor"); +} + +struct hwloc_firmware_dmi_mem_device_header { + unsigned char type; + unsigned char length; + unsigned char handle[2]; + unsigned char phy_mem_handle[2]; + unsigned char mem_err_handle[2]; + unsigned char tot_width[2]; + unsigned char dat_width[2]; + unsigned char size[2]; + unsigned char ff; + unsigned char dev_set; + unsigned char dev_loc_str_num; + unsigned char bank_loc_str_num; + unsigned char mem_type; + unsigned char type_detail[2]; + unsigned char speed[2]; + unsigned char manuf_str_num; + unsigned char serial_str_num; + unsigned char asset_tag_str_num; + unsigned char part_num_str_num; + /* don't include the following fields since we don't need them, + * some old implementations may miss them. + */ +}; + +static int check_dmi_entry(const char *buffer) +{ + /* reject empty strings */ + if (!*buffer) + return 0; + /* reject strings of spaces (at least Dell use this for empty memory slots) */ + if (strspn(buffer, " ") == strlen(buffer)) + return 0; + return 1; +} + +static void +hwloc__get_firmware_dmi_memory_info_one(struct hwloc_topology *topology, + unsigned idx, const char *path, FILE *fd, + struct hwloc_firmware_dmi_mem_device_header *header) +{ + unsigned slen; + char buffer[256]; /* enough for memory device strings, or at least for each of them */ + unsigned foff; /* offset in raw file */ + unsigned boff; /* offset in buffer read from raw file */ + unsigned i; + struct hwloc_obj_info_s *infos = NULL; + unsigned infos_count = 0; + hwloc_obj_t misc; + int foundinfo = 0; + + hwloc__add_info(&infos, &infos_count, "Type", "MemoryModule"); + + /* start after the header */ + foff = header->length; + i = 1; + while (1) { + /* read one buffer */ + if (fseek(fd, foff, SEEK_SET) < 0) + break; + if (!fgets(buffer, sizeof(buffer), fd)) + break; + /* read string at the beginning of the buffer */ + boff = 0; + while (1) { + /* stop on empty string */ + if (!buffer[boff]) + goto done; + /* stop if this string goes to the end of the buffer */ + slen = strlen(buffer+boff); + if (boff + slen+1 == sizeof(buffer)) + break; + /* string didn't get truncated, should be OK */ + if (i == header->manuf_str_num) { + if (check_dmi_entry(buffer+boff)) { + hwloc__add_info(&infos, &infos_count, "Vendor", buffer+boff); + foundinfo = 1; + } + } else if (i == header->serial_str_num) { + if (check_dmi_entry(buffer+boff)) { + hwloc__add_info(&infos, &infos_count, "SerialNumber", buffer+boff); + foundinfo = 1; + } + } else if (i == header->asset_tag_str_num) { + if (check_dmi_entry(buffer+boff)) { + hwloc__add_info(&infos, &infos_count, "AssetTag", buffer+boff); + foundinfo = 1; + } + } else if (i == header->part_num_str_num) { + if (check_dmi_entry(buffer+boff)) { + hwloc__add_info(&infos, &infos_count, "PartNumber", buffer+boff); + foundinfo = 1; + } + } else if (i == header->dev_loc_str_num) { + if (check_dmi_entry(buffer+boff)) { + hwloc__add_info(&infos, &infos_count, "DeviceLocation", buffer+boff); + /* only a location, not an actual info about the device */ + } + } else if (i == header->bank_loc_str_num) { + if (check_dmi_entry(buffer+boff)) { + hwloc__add_info(&infos, &infos_count, "BankLocation", buffer+boff); + /* only a location, not an actual info about the device */ + } + } else { + goto done; + } + /* next string in buffer */ + boff += slen+1; + i++; + } + /* couldn't read a single full string from that buffer, we're screwed */ + if (!boff) { + fprintf(stderr, "hwloc could read a DMI firmware entry #%u in %s\n", + i, path); + break; + } + /* reread buffer after previous string */ + foff += boff; + } + +done: + if (!foundinfo) { + /* found no actual info about the device. if there's only location info, the slot may be empty */ + goto out_with_infos; + } + + misc = hwloc_alloc_setup_object(HWLOC_OBJ_MISC, idx); + if (!misc) + goto out_with_infos; + + hwloc__move_infos(&misc->infos, &misc->infos_count, &infos, &infos_count); + /* FIXME: find a way to identify the corresponding NUMA node and attach these objects there. + * but it means we need to parse DeviceLocation=DIMM_B4 but these vary significantly + * with the vendor, and it's hard to be 100% sure 'B' is second socket. + * Examples at http://sourceforge.net/p/edac-utils/code/HEAD/tree/trunk/src/etc/labels.db + * or https://github.com/grondo/edac-utils/blob/master/src/etc/labels.db + */ + hwloc_insert_object_by_parent(topology, hwloc_get_root_obj(topology), misc); + return; + + out_with_infos: + hwloc__free_infos(infos, infos_count); +} + +static void +hwloc__get_firmware_dmi_memory_info(struct hwloc_topology *topology, + struct hwloc_linux_backend_data_s *data) +{ + char path[128]; + unsigned i; + + for(i=0; ; i++) { + FILE *fd; + struct hwloc_firmware_dmi_mem_device_header header; + int err; + + snprintf(path, sizeof(path), "/sys/firmware/dmi/entries/17-%u/raw", i); + fd = hwloc_fopen(path, "r", data->root_fd); + if (!fd) + break; + + err = fread(&header, sizeof(header), 1, fd); + if (err != 1) + break; + if (header.length < sizeof(header)) { + /* invalid, or too old entry/spec that doesn't contain what we need */ + fclose(fd); + break; + } + + hwloc__get_firmware_dmi_memory_info_one(topology, i, path, fd, &header); + + fclose(fd); + } +} + + +/*********************************** + ****** Device tree Discovery ****** + ***********************************/ + +/* Reads the entire file and returns bytes read if bytes_read != NULL + * Returned pointer can be freed by using free(). */ +static void * +hwloc_read_raw(const char *p, const char *p1, size_t *bytes_read, int root_fd) +{ + char fname[256]; + char *ret = NULL; + struct stat fs; + int file = -1; + + snprintf(fname, sizeof(fname), "%s/%s", p, p1); + + file = hwloc_open(fname, root_fd); + if (-1 == file) { + goto out_no_close; + } + if (fstat(file, &fs)) { + goto out; + } + + ret = (char *) malloc(fs.st_size); + if (NULL != ret) { + ssize_t cb = read(file, ret, fs.st_size); + if (cb == -1) { + free(ret); + ret = NULL; + } else { + if (NULL != bytes_read) + *bytes_read = cb; + } + } + + out: + close(file); + out_no_close: + return ret; +} + +/* Reads the entire file and returns it as a 0-terminated string + * Returned pointer can be freed by using free(). */ +static char * +hwloc_read_str(const char *p, const char *p1, int root_fd) +{ + size_t cb = 0; + char *ret = hwloc_read_raw(p, p1, &cb, root_fd); + if ((NULL != ret) && (0 < cb) && (0 != ret[cb-1])) { + ret = realloc(ret, cb + 1); + ret[cb] = 0; + } + return ret; +} + +/* Reads first 32bit bigendian value */ +static ssize_t +hwloc_read_unit32be(const char *p, const char *p1, uint32_t *buf, int root_fd) +{ + size_t cb = 0; + uint32_t *tmp = hwloc_read_raw(p, p1, &cb, root_fd); + if (sizeof(*buf) != cb) { + errno = EINVAL; + free(tmp); /* tmp is either NULL or contains useless things */ + return -1; + } + *buf = htonl(*tmp); + free(tmp); + return sizeof(*buf); +} + +typedef struct { + unsigned int n, allocated; + struct { + hwloc_bitmap_t cpuset; + uint32_t phandle; + uint32_t l2_cache; + char *name; + } *p; +} device_tree_cpus_t; + +static void +add_device_tree_cpus_node(device_tree_cpus_t *cpus, hwloc_bitmap_t cpuset, + uint32_t l2_cache, uint32_t phandle, const char *name) +{ + if (cpus->n == cpus->allocated) { + if (!cpus->allocated) + cpus->allocated = 64; + else + cpus->allocated *= 2; + cpus->p = realloc(cpus->p, cpus->allocated * sizeof(cpus->p[0])); + } + cpus->p[cpus->n].phandle = phandle; + cpus->p[cpus->n].cpuset = (NULL == cpuset)?NULL:hwloc_bitmap_dup(cpuset); + cpus->p[cpus->n].l2_cache = l2_cache; + cpus->p[cpus->n].name = strdup(name); + ++cpus->n; +} + +/* Walks over the cache list in order to detect nested caches and CPU mask for each */ +static int +look_powerpc_device_tree_discover_cache(device_tree_cpus_t *cpus, + uint32_t phandle, unsigned int *level, hwloc_bitmap_t cpuset) +{ + unsigned int i; + int ret = -1; + if ((NULL == level) || (NULL == cpuset) || phandle == (uint32_t) -1) + return ret; + for (i = 0; i < cpus->n; ++i) { + if (phandle != cpus->p[i].l2_cache) + continue; + if (NULL != cpus->p[i].cpuset) { + hwloc_bitmap_or(cpuset, cpuset, cpus->p[i].cpuset); + ret = 0; + } else { + ++(*level); + if (0 == look_powerpc_device_tree_discover_cache(cpus, + cpus->p[i].phandle, level, cpuset)) + ret = 0; + } + } + return ret; +} + +static void +try__add_cache_from_device_tree_cpu(struct hwloc_topology *topology, + unsigned int level, hwloc_obj_cache_type_t type, + uint32_t cache_line_size, uint32_t cache_size, uint32_t cache_sets, + hwloc_bitmap_t cpuset) +{ + struct hwloc_obj *c = NULL; + + if (0 == cache_size) + return; + + c = hwloc_alloc_setup_object(HWLOC_OBJ_CACHE, -1); + c->attr->cache.depth = level; + c->attr->cache.linesize = cache_line_size; + c->attr->cache.size = cache_size; + c->attr->cache.type = type; + if (cache_sets == 1) + /* likely wrong, make it unknown */ + cache_sets = 0; + if (cache_sets && cache_line_size) + c->attr->cache.associativity = cache_size / (cache_sets * cache_line_size); + else + c->attr->cache.associativity = 0; + c->cpuset = hwloc_bitmap_dup(cpuset); + hwloc_debug_2args_bitmap("cache (%s) depth %d has cpuset %s\n", + type == HWLOC_OBJ_CACHE_UNIFIED ? "unified" : (type == HWLOC_OBJ_CACHE_DATA ? "data" : "instruction"), + level, c->cpuset); + hwloc_insert_object_by_cpuset(topology, c); +} + +static void +try_add_cache_from_device_tree_cpu(struct hwloc_topology *topology, + struct hwloc_linux_backend_data_s *data, + const char *cpu, unsigned int level, hwloc_bitmap_t cpuset) +{ + /* d-cache-block-size - ignore */ + /* d-cache-line-size - to read, in bytes */ + /* d-cache-sets - ignore */ + /* d-cache-size - to read, in bytes */ + /* i-cache, same for instruction */ + /* cache-unified only exist if data and instruction caches are unified */ + /* d-tlb-sets - ignore */ + /* d-tlb-size - ignore, always 0 on power6 */ + /* i-tlb-*, same */ + uint32_t d_cache_line_size = 0, d_cache_size = 0, d_cache_sets = 0; + uint32_t i_cache_line_size = 0, i_cache_size = 0, i_cache_sets = 0; + char unified_path[1024]; + struct stat statbuf; + int unified; + + snprintf(unified_path, sizeof(unified_path), "%s/cache-unified", cpu); + unified = (hwloc_stat(unified_path, &statbuf, data->root_fd) == 0); + + hwloc_read_unit32be(cpu, "d-cache-line-size", &d_cache_line_size, + data->root_fd); + hwloc_read_unit32be(cpu, "d-cache-size", &d_cache_size, + data->root_fd); + hwloc_read_unit32be(cpu, "d-cache-sets", &d_cache_sets, + data->root_fd); + hwloc_read_unit32be(cpu, "i-cache-line-size", &i_cache_line_size, + data->root_fd); + hwloc_read_unit32be(cpu, "i-cache-size", &i_cache_size, + data->root_fd); + hwloc_read_unit32be(cpu, "i-cache-sets", &i_cache_sets, + data->root_fd); + + if (!unified) + try__add_cache_from_device_tree_cpu(topology, level, HWLOC_OBJ_CACHE_INSTRUCTION, + i_cache_line_size, i_cache_size, i_cache_sets, cpuset); + try__add_cache_from_device_tree_cpu(topology, level, unified ? HWLOC_OBJ_CACHE_UNIFIED : HWLOC_OBJ_CACHE_DATA, + d_cache_line_size, d_cache_size, d_cache_sets, cpuset); +} + +/* + * Discovers L1/L2/L3 cache information on IBM PowerPC systems for old kernels (RHEL5.*) + * which provide NUMA nodes information without any details + */ +static void +look_powerpc_device_tree(struct hwloc_topology *topology, + struct hwloc_linux_backend_data_s *data) +{ + device_tree_cpus_t cpus; + const char ofroot[] = "/proc/device-tree/cpus"; + unsigned int i; + int root_fd = data->root_fd; + DIR *dt = hwloc_opendir(ofroot, root_fd); + struct dirent *dirent; + + if (NULL == dt) + return; + + /* only works for Power so far, and not useful on ARM */ + if (strncmp(data->utsname.machine, "ppc", 3)) + return; + + cpus.n = 0; + cpus.p = NULL; + cpus.allocated = 0; + + while (NULL != (dirent = readdir(dt))) { + char cpu[256]; + char *device_type; + uint32_t reg = -1, l2_cache = -1, phandle = -1; + + if ('.' == dirent->d_name[0]) + continue; + + snprintf(cpu, sizeof(cpu), "%s/%s", ofroot, dirent->d_name); + + device_type = hwloc_read_str(cpu, "device_type", root_fd); + if (NULL == device_type) + continue; + + hwloc_read_unit32be(cpu, "reg", ®, root_fd); + if (hwloc_read_unit32be(cpu, "next-level-cache", &l2_cache, root_fd) == -1) + hwloc_read_unit32be(cpu, "l2-cache", &l2_cache, root_fd); + if (hwloc_read_unit32be(cpu, "phandle", &phandle, root_fd) == -1) + if (hwloc_read_unit32be(cpu, "ibm,phandle", &phandle, root_fd) == -1) + hwloc_read_unit32be(cpu, "linux,phandle", &phandle, root_fd); + + if (0 == strcmp(device_type, "cache")) { + add_device_tree_cpus_node(&cpus, NULL, l2_cache, phandle, dirent->d_name); + } + else if (0 == strcmp(device_type, "cpu")) { + /* Found CPU */ + hwloc_bitmap_t cpuset = NULL; + size_t cb = 0; + uint32_t *threads = hwloc_read_raw(cpu, "ibm,ppc-interrupt-server#s", &cb, root_fd); + uint32_t nthreads = cb / sizeof(threads[0]); + + if (NULL != threads) { + cpuset = hwloc_bitmap_alloc(); + for (i = 0; i < nthreads; ++i) { + if (hwloc_bitmap_isset(topology->levels[0][0]->complete_cpuset, ntohl(threads[i]))) + hwloc_bitmap_set(cpuset, ntohl(threads[i])); + } + free(threads); + } else if ((unsigned int)-1 != reg) { + /* Doesn't work on ARM because cpu "reg" do not start at 0. + * We know the first cpu "reg" is the lowest. The others are likely + * in order assuming the device-tree shows objects in order. + */ + cpuset = hwloc_bitmap_alloc(); + hwloc_bitmap_set(cpuset, reg); + } + + if (NULL == cpuset) { + hwloc_debug("%s has no \"reg\" property, skipping\n", cpu); + } else { + struct hwloc_obj *core = NULL; + add_device_tree_cpus_node(&cpus, cpuset, l2_cache, phandle, dirent->d_name); + + /* Add core */ + core = hwloc_alloc_setup_object(HWLOC_OBJ_CORE, reg); + core->cpuset = hwloc_bitmap_dup(cpuset); + hwloc_insert_object_by_cpuset(topology, core); + + /* Add L1 cache */ + try_add_cache_from_device_tree_cpu(topology, data, cpu, 1, cpuset); + + hwloc_bitmap_free(cpuset); + } + } + free(device_type); + } + closedir(dt); + + /* No cores and L2 cache were found, exiting */ + if (0 == cpus.n) { + hwloc_debug("No cores and L2 cache were found in %s, exiting\n", ofroot); + return; + } + +#ifdef HWLOC_DEBUG + for (i = 0; i < cpus.n; ++i) { + hwloc_debug("%i: %s ibm,phandle=%08X l2_cache=%08X ", + i, cpus.p[i].name, cpus.p[i].phandle, cpus.p[i].l2_cache); + if (NULL == cpus.p[i].cpuset) { + hwloc_debug("%s\n", "no cpuset"); + } else { + hwloc_debug_bitmap("cpuset %s\n", cpus.p[i].cpuset); + } + } +#endif + + /* Scan L2/L3/... caches */ + for (i = 0; i < cpus.n; ++i) { + unsigned int level = 2; + hwloc_bitmap_t cpuset; + /* Skip real CPUs */ + if (NULL != cpus.p[i].cpuset) + continue; + + /* Calculate cache level and CPU mask */ + cpuset = hwloc_bitmap_alloc(); + if (0 == look_powerpc_device_tree_discover_cache(&cpus, + cpus.p[i].phandle, &level, cpuset)) { + char cpu[256]; + snprintf(cpu, sizeof(cpu), "%s/%s", ofroot, cpus.p[i].name); + try_add_cache_from_device_tree_cpu(topology, data, cpu, level, cpuset); + } + hwloc_bitmap_free(cpuset); + } + + /* Do cleanup */ + for (i = 0; i < cpus.n; ++i) { + hwloc_bitmap_free(cpus.p[i].cpuset); + free(cpus.p[i].name); + } + free(cpus.p); +} + + + +/************************************** + ****** Sysfs Topology Discovery ****** + **************************************/ + +static int +look_sysfsnode(struct hwloc_topology *topology, + struct hwloc_linux_backend_data_s *data, + const char *path, unsigned *found) +{ + unsigned osnode; + unsigned nbnodes = 0; + DIR *dir; + struct dirent *dirent; + hwloc_bitmap_t nodeset; + + *found = 0; + + /* Get the list of nodes first */ + dir = hwloc_opendir(path, data->root_fd); + if (dir) + { + nodeset = hwloc_bitmap_alloc(); + while ((dirent = readdir(dir)) != NULL) + { + if (strncmp(dirent->d_name, "node", 4)) + continue; + osnode = strtoul(dirent->d_name+4, NULL, 0); + hwloc_bitmap_set(nodeset, osnode); + nbnodes++; + } + closedir(dir); + } + else + return -1; + + if (nbnodes <= 1) + { + hwloc_bitmap_free(nodeset); + return 0; + } + + /* For convenience, put these declarations inside a block. */ + + { + hwloc_obj_t * nodes = calloc(nbnodes, sizeof(hwloc_obj_t)); + unsigned *indexes = calloc(nbnodes, sizeof(unsigned)); + float * distances; + int failednodes = 0; + unsigned index_; + + if (NULL == nodes || NULL == indexes) { + free(nodes); + free(indexes); + hwloc_bitmap_free(nodeset); + nbnodes = 0; + goto out; + } + + /* Unsparsify node indexes. + * We'll need them later because Linux groups sparse distances + * and keeps them in order in the sysfs distance files. + * It'll simplify things in the meantime. + */ + index_ = 0; + hwloc_bitmap_foreach_begin (osnode, nodeset) { + indexes[index_] = osnode; + index_++; + } hwloc_bitmap_foreach_end(); + hwloc_bitmap_free(nodeset); + +#ifdef HWLOC_DEBUG + hwloc_debug("%s", "NUMA indexes: "); + for (index_ = 0; index_ < nbnodes; index_++) { + hwloc_debug(" %u", indexes[index_]); + } + hwloc_debug("%s", "\n"); +#endif + + /* Create NUMA objects */ + for (index_ = 0; index_ < nbnodes; index_++) { + char nodepath[SYSFS_NUMA_NODE_PATH_LEN]; + hwloc_bitmap_t cpuset; + hwloc_obj_t node, res_obj; + + osnode = indexes[index_]; + + sprintf(nodepath, "%s/node%u/cpumap", path, osnode); + cpuset = hwloc_parse_cpumap(nodepath, data->root_fd); + if (!cpuset) { + /* This NUMA object won't be inserted, we'll ignore distances */ + failednodes++; + continue; + } + + node = hwloc_alloc_setup_object(HWLOC_OBJ_NUMANODE, osnode); + node->cpuset = cpuset; + node->nodeset = hwloc_bitmap_alloc(); + hwloc_bitmap_set(node->nodeset, osnode); + + hwloc_sysfs_node_meminfo_info(topology, data, path, osnode, &node->memory); + + hwloc_debug_1arg_bitmap("os node %u has cpuset %s\n", + osnode, node->cpuset); + res_obj = hwloc_insert_object_by_cpuset(topology, node); + if (node == res_obj) { + nodes[index_] = node; + } else { + /* We got merged somehow, could be a buggy BIOS reporting wrong NUMA node cpuset. + * This object disappeared, we'll ignore distances */ + failednodes++; + } + } + + if (failednodes) { + /* failed to read/create some nodes, don't bother reading/fixing + * a distance matrix that would likely be wrong anyway. + */ + nbnodes -= failednodes; + distances = NULL; + } else { + distances = calloc(nbnodes*nbnodes, sizeof(float)); + } + + if (NULL == distances) { + free(nodes); + free(indexes); + goto out; + } + + /* Get actual distances now */ + for (index_ = 0; index_ < nbnodes; index_++) { + char nodepath[SYSFS_NUMA_NODE_PATH_LEN]; + + osnode = indexes[index_]; + + /* Linux nodeX/distance file contains distance from X to other localities (from ACPI SLIT table or so), + * store them in slots X*N...X*N+N-1 */ + sprintf(nodepath, "%s/node%u/distance", path, osnode); + hwloc_parse_node_distance(nodepath, nbnodes, distances+index_*nbnodes, data->root_fd); + } + + hwloc_distances_set(topology, HWLOC_OBJ_NUMANODE, nbnodes, indexes, nodes, distances, 0 /* OS cannot force */); + } + + out: + *found = nbnodes; + return 0; +} + +/* Look at Linux' /sys/devices/system/cpu/cpu%d/topology/ */ +static int +look_sysfscpu(struct hwloc_topology *topology, + struct hwloc_linux_backend_data_s *data, + const char *path, + struct hwloc_linux_cpuinfo_proc * cpuinfo_Lprocs, unsigned cpuinfo_numprocs) +{ + hwloc_bitmap_t cpuset; /* Set of cpus for which we have topology information */ +#define CPU_TOPOLOGY_STR_LEN 128 + char str[CPU_TOPOLOGY_STR_LEN]; + DIR *dir; + int i,j; + FILE *fd; + unsigned caches_added, merge_buggy_core_siblings; + hwloc_obj_t packages = NULL; /* temporary list of packages before actual insert in the tree */ + + /* fill the cpuset of interesting cpus */ + dir = hwloc_opendir(path, data->root_fd); + if (!dir) + return -1; + else { + struct dirent *dirent; + cpuset = hwloc_bitmap_alloc(); + + while ((dirent = readdir(dir)) != NULL) { + unsigned long cpu; + char online[2]; + + if (strncmp(dirent->d_name, "cpu", 3)) + continue; + cpu = strtoul(dirent->d_name+3, NULL, 0); + + /* Maybe we don't have topology information but at least it exists */ + hwloc_bitmap_set(topology->levels[0][0]->complete_cpuset, cpu); + + /* check whether this processor is online */ + sprintf(str, "%s/cpu%lu/online", path, cpu); + fd = hwloc_fopen(str, "r", data->root_fd); + if (fd) { + if (fgets(online, sizeof(online), fd)) { + fclose(fd); + if (atoi(online)) { + hwloc_debug("os proc %lu is online\n", cpu); + } else { + hwloc_debug("os proc %lu is offline\n", cpu); + hwloc_bitmap_clr(topology->levels[0][0]->online_cpuset, cpu); + } + } else { + fclose(fd); + } + } + + /* check whether the kernel exports topology information for this cpu */ + sprintf(str, "%s/cpu%lu/topology", path, cpu); + if (hwloc_access(str, X_OK, data->root_fd) < 0 && errno == ENOENT) { + hwloc_debug("os proc %lu has no accessible %s/cpu%lu/topology\n", + cpu, path, cpu); + continue; + } + + hwloc_bitmap_set(cpuset, cpu); + } + closedir(dir); + } + + topology->support.discovery->pu = 1; + hwloc_debug_1arg_bitmap("found %d cpu topologies, cpuset %s\n", + hwloc_bitmap_weight(cpuset), cpuset); + + merge_buggy_core_siblings = (!strcmp(data->utsname.machine, "x86_64")) + || (data->utsname.machine[0] == 'i' && !strcmp(data->utsname.machine+2, "86")); + caches_added = 0; + hwloc_bitmap_foreach_begin(i, cpuset) + { + hwloc_bitmap_t packageset, coreset, bookset, threadset, savedcoreset; + unsigned mypackageid, mycoreid, mybookid; + int threadwithcoreid = 0; + + /* look at the package */ + mypackageid = 0; /* shut-up the compiler */ + sprintf(str, "%s/cpu%d/topology/physical_package_id", path, i); + hwloc_parse_sysfs_unsigned(str, &mypackageid, data->root_fd); + + sprintf(str, "%s/cpu%d/topology/core_siblings", path, i); + packageset = hwloc_parse_cpumap(str, data->root_fd); + if (packageset && hwloc_bitmap_first(packageset) == i) { + /* first cpu in this package, add the package */ + struct hwloc_obj *package; + + if (merge_buggy_core_siblings) { + /* check for another package with same physical_package_id */ + hwloc_obj_t curpackage = packages; + while (curpackage) { + if (curpackage->os_index == mypackageid) { + /* found another package with same physical_package_id but different core_siblings. + * looks like a buggy kernel on Intel Xeon E5 v3 processor with two rings. + * merge these core_siblings to extend the existing first package object. + */ + static int reported = 0; + if (!reported && !hwloc_hide_errors()) { + char *a, *b; + hwloc_bitmap_asprintf(&a, curpackage->cpuset); + hwloc_bitmap_asprintf(&b, packageset); + fprintf(stderr, "****************************************************************************\n"); + fprintf(stderr, "* hwloc %s has detected buggy sysfs package information: Two packages have\n", HWLOC_VERSION); + fprintf(stderr, "* the same physical package id %u but different core_siblings %s and %s\n", + mypackageid, a, b); + fprintf(stderr, "* hwloc is merging these packages into a single one assuming your Linux kernel\n"); + fprintf(stderr, "* does not support this processor correctly.\n"); + fprintf(stderr, "* You may hide this warning by setting HWLOC_HIDE_ERRORS=1 in the environment.\n"); + fprintf(stderr, "*\n"); + fprintf(stderr, "* If hwloc does not report the right number of packages,\n"); + fprintf(stderr, "* please report this error message to the hwloc user's mailing list,\n"); + fprintf(stderr, "* along with the output+tarball generated by the hwloc-gather-topology script.\n"); + fprintf(stderr, "****************************************************************************\n"); + reported = 1; + free(a); + free(b); + } + hwloc_bitmap_or(curpackage->cpuset, curpackage->cpuset, packageset); + goto package_done; + } + curpackage = curpackage->next_cousin; + } + } + + /* no package with same physical_package_id, create a new one */ + package = hwloc_alloc_setup_object(HWLOC_OBJ_PACKAGE, mypackageid); + package->cpuset = packageset; + hwloc_debug_1arg_bitmap("os package %u has cpuset %s\n", + mypackageid, packageset); + /* add cpuinfo */ + if (cpuinfo_Lprocs) { + for(j=0; j<(int) cpuinfo_numprocs; j++) + if ((int) cpuinfo_Lprocs[j].Pproc == i) { + hwloc__move_infos(&package->infos, &package->infos_count, + &cpuinfo_Lprocs[j].infos, &cpuinfo_Lprocs[j].infos_count); + } + } + /* insert in a temporary list in case we have to modify the cpuset by merging other core_siblings later. + * we'll actually insert the tree at the end of the entire sysfs cpu loop. + */ + package->next_cousin = packages; + packages = package; + + packageset = NULL; /* don't free it */ + } +package_done: + hwloc_bitmap_free(packageset); + + /* look at the core */ + mycoreid = 0; /* shut-up the compiler */ + sprintf(str, "%s/cpu%d/topology/core_id", path, i); + hwloc_parse_sysfs_unsigned(str, &mycoreid, data->root_fd); + + sprintf(str, "%s/cpu%d/topology/thread_siblings", path, i); + coreset = hwloc_parse_cpumap(str, data->root_fd); + savedcoreset = coreset; /* store it for later work-arounds */ + + if (coreset && hwloc_bitmap_weight(coreset) > 1) { + /* check if this is hyper-threading or different coreids */ + unsigned siblingid, siblingcoreid; + hwloc_bitmap_t set = hwloc_bitmap_dup(coreset); + hwloc_bitmap_clr(set, i); + siblingid = hwloc_bitmap_first(set); + siblingcoreid = mycoreid; + sprintf(str, "%s/cpu%d/topology/core_id", path, siblingid); + hwloc_parse_sysfs_unsigned(str, &siblingcoreid, data->root_fd); + threadwithcoreid = (siblingcoreid != mycoreid); + hwloc_bitmap_free(set); + } + + + if (coreset && (hwloc_bitmap_first(coreset) == i || threadwithcoreid)) { + /* regular core */ + struct hwloc_obj *core = hwloc_alloc_setup_object(HWLOC_OBJ_CORE, mycoreid); + if (threadwithcoreid) { + /* amd multicore compute-unit, create one core per thread */ + core->cpuset = hwloc_bitmap_alloc(); + hwloc_bitmap_set(core->cpuset, i); + } else { + core->cpuset = coreset; + } + hwloc_debug_1arg_bitmap("os core %u has cpuset %s\n", + mycoreid, coreset); + hwloc_insert_object_by_cpuset(topology, core); + coreset = NULL; /* don't free it */ + } + + /* look at the books */ + mybookid = 0; /* shut-up the compiler */ + sprintf(str, "%s/cpu%d/topology/book_id", path, i); + if (hwloc_parse_sysfs_unsigned(str, &mybookid, data->root_fd) == 0) { + + sprintf(str, "%s/cpu%d/topology/book_siblings", path, i); + bookset = hwloc_parse_cpumap(str, data->root_fd); + if (bookset && hwloc_bitmap_first(bookset) == i) { + struct hwloc_obj *book = hwloc_alloc_setup_object(HWLOC_OBJ_GROUP, mybookid); + book->cpuset = bookset; + hwloc_debug_1arg_bitmap("os book %u has cpuset %s\n", + mybookid, bookset); + hwloc_obj_add_info(book, "Type", "Book"); + hwloc_insert_object_by_cpuset(topology, book); + bookset = NULL; /* don't free it */ + } + } + + { + /* look at the thread */ + struct hwloc_obj *thread = hwloc_alloc_setup_object(HWLOC_OBJ_PU, i); + threadset = hwloc_bitmap_alloc(); + hwloc_bitmap_only(threadset, i); + thread->cpuset = threadset; + hwloc_debug_1arg_bitmap("thread %d has cpuset %s\n", + i, threadset); + hwloc_insert_object_by_cpuset(topology, thread); + } + + /* look at the caches */ + for(j=0; j<10; j++) { +#define SHARED_CPU_MAP_STRLEN 128 + char mappath[SHARED_CPU_MAP_STRLEN]; + char str2[20]; /* enough for a level number (one digit) or a type (Data/Instruction/Unified) */ + hwloc_bitmap_t cacheset; + unsigned long kB = 0; + unsigned linesize = 0; + unsigned sets = 0, lines_per_tag = 1; + int depth; /* 0 for L1, .... */ + hwloc_obj_cache_type_t type = HWLOC_OBJ_CACHE_UNIFIED; /* default */ + + /* get the cache level depth */ + sprintf(mappath, "%s/cpu%d/cache/index%d/level", path, i, j); + fd = hwloc_fopen(mappath, "r", data->root_fd); + if (fd) { + char *res = fgets(str2,sizeof(str2), fd); + fclose(fd); + if (res) + depth = strtoul(str2, NULL, 10)-1; + else + continue; + } else + continue; + + /* cache type */ + sprintf(mappath, "%s/cpu%d/cache/index%d/type", path, i, j); + fd = hwloc_fopen(mappath, "r", data->root_fd); + if (fd) { + if (fgets(str2, sizeof(str2), fd)) { + fclose(fd); + if (!strncmp(str2, "Data", 4)) + type = HWLOC_OBJ_CACHE_DATA; + else if (!strncmp(str2, "Unified", 7)) + type = HWLOC_OBJ_CACHE_UNIFIED; + else if (!strncmp(str2, "Instruction", 11)) + type = HWLOC_OBJ_CACHE_INSTRUCTION; + else + continue; + } else { + fclose(fd); + continue; + } + } else + continue; + + /* get the cache size */ + sprintf(mappath, "%s/cpu%d/cache/index%d/size", path, i, j); + fd = hwloc_fopen(mappath, "r", data->root_fd); + if (fd) { + if (fgets(str2,sizeof(str2), fd)) + kB = atol(str2); /* in kB */ + fclose(fd); + } + + /* get the line size */ + sprintf(mappath, "%s/cpu%d/cache/index%d/coherency_line_size", path, i, j); + fd = hwloc_fopen(mappath, "r", data->root_fd); + if (fd) { + if (fgets(str2,sizeof(str2), fd)) + linesize = atol(str2); /* in bytes */ + fclose(fd); + } + + /* get the number of sets and lines per tag. + * don't take the associativity directly in "ways_of_associativity" because + * some archs (ia64, ppc) put 0 there when fully-associative, while others (x86) put something like -1 there. + */ + sprintf(mappath, "%s/cpu%d/cache/index%d/number_of_sets", path, i, j); + fd = hwloc_fopen(mappath, "r", data->root_fd); + if (fd) { + if (fgets(str2,sizeof(str2), fd)) + sets = atol(str2); + fclose(fd); + } + sprintf(mappath, "%s/cpu%d/cache/index%d/physical_line_partition", path, i, j); + fd = hwloc_fopen(mappath, "r", data->root_fd); + if (fd) { + if (fgets(str2,sizeof(str2), fd)) + lines_per_tag = atol(str2); + fclose(fd); + } + + sprintf(mappath, "%s/cpu%d/cache/index%d/shared_cpu_map", path, i, j); + cacheset = hwloc_parse_cpumap(mappath, data->root_fd); + if (cacheset) { + if (hwloc_bitmap_weight(cacheset) < 1) { + /* mask is wrong (useful for many itaniums) */ + if (savedcoreset) + /* assume it's a core-specific cache */ + hwloc_bitmap_copy(cacheset, savedcoreset); + else + /* assumes it's not shared */ + hwloc_bitmap_only(cacheset, i); + } + + if (hwloc_bitmap_first(cacheset) == i) { + /* first cpu in this cache, add the cache */ + struct hwloc_obj *cache = hwloc_alloc_setup_object(HWLOC_OBJ_CACHE, -1); + cache->attr->cache.size = kB << 10; + cache->attr->cache.depth = depth+1; + cache->attr->cache.linesize = linesize; + cache->attr->cache.type = type; + if (!linesize || !lines_per_tag || !sets) + cache->attr->cache.associativity = 0; /* unknown */ + else if (sets == 1) + cache->attr->cache.associativity = 0; /* likely wrong, make it unknown */ + else + cache->attr->cache.associativity = (kB << 10) / linesize / lines_per_tag / sets; + cache->cpuset = cacheset; + hwloc_debug_1arg_bitmap("cache depth %d has cpuset %s\n", + depth, cacheset); + hwloc_insert_object_by_cpuset(topology, cache); + cacheset = NULL; /* don't free it */ + ++caches_added; + } + } + hwloc_bitmap_free(cacheset); + } + hwloc_bitmap_free(coreset); + } + hwloc_bitmap_foreach_end(); + + /* actually insert in the tree now that package cpusets have been fixed-up */ + while (packages) { + hwloc_obj_t next = packages->next_cousin; + packages->next_cousin = NULL; + hwloc_insert_object_by_cpuset(topology, packages); + packages = next; + } + + if (0 == caches_added) + look_powerpc_device_tree(topology, data); + + hwloc_bitmap_free(cpuset); + + return 0; +} + + + +/**************************************** + ****** cpuinfo Topology Discovery ****** + ****************************************/ + +static int +hwloc_linux_parse_cpuinfo_x86(const char *prefix, const char *value, + struct hwloc_obj_info_s **infos, unsigned *infos_count, + int is_global __hwloc_attribute_unused) +{ + if (!strcmp("vendor_id", prefix)) { + hwloc__add_info(infos, infos_count, "CPUVendor", value); + } else if (!strcmp("model name", prefix)) { + hwloc__add_info(infos, infos_count, "CPUModel", value); + } else if (!strcmp("model", prefix)) { + hwloc__add_info(infos, infos_count, "CPUModelNumber", value); + } else if (!strcmp("cpu family", prefix)) { + hwloc__add_info(infos, infos_count, "CPUFamilyNumber", value); + } else if (!strcmp("stepping", prefix)) { + hwloc__add_info(infos, infos_count, "CPUStepping", value); + } + return 0; +} + +static int +hwloc_linux_parse_cpuinfo_ia64(const char *prefix, const char *value, + struct hwloc_obj_info_s **infos, unsigned *infos_count, + int is_global __hwloc_attribute_unused) +{ + if (!strcmp("vendor", prefix)) { + hwloc__add_info(infos, infos_count, "CPUVendor", value); + } else if (!strcmp("model name", prefix)) { + hwloc__add_info(infos, infos_count, "CPUModel", value); + } else if (!strcmp("model", prefix)) { + hwloc__add_info(infos, infos_count, "CPUModelNumber", value); + } else if (!strcmp("family", prefix)) { + hwloc__add_info(infos, infos_count, "CPUFamilyNumber", value); + } + return 0; +} + +static int +hwloc_linux_parse_cpuinfo_arm(const char *prefix, const char *value, + struct hwloc_obj_info_s **infos, unsigned *infos_count, + int is_global __hwloc_attribute_unused) +{ + if (!strcmp("Processor", prefix) /* old kernels with one Processor header */ + || !strcmp("model name", prefix) /* new kernels with one model name per core */) { + hwloc__add_info(infos, infos_count, "CPUModel", value); + } else if (!strcmp("CPU implementer", prefix)) { + hwloc__add_info(infos, infos_count, "CPUImplementer", value); + } else if (!strcmp("CPU architecture", prefix)) { + hwloc__add_info(infos, infos_count, "CPUArchitecture", value); + } else if (!strcmp("CPU variant", prefix)) { + hwloc__add_info(infos, infos_count, "CPUVariant", value); + } else if (!strcmp("CPU part", prefix)) { + hwloc__add_info(infos, infos_count, "CPUPart", value); + } else if (!strcmp("CPU revision", prefix)) { + hwloc__add_info(infos, infos_count, "CPURevision", value); + } else if (!strcmp("Hardware", prefix)) { + hwloc__add_info(infos, infos_count, "HardwareName", value); + } else if (!strcmp("Revision", prefix)) { + hwloc__add_info(infos, infos_count, "HardwareRevision", value); + } else if (!strcmp("Serial", prefix)) { + hwloc__add_info(infos, infos_count, "HardwareSerial", value); + } + return 0; +} + +static int +hwloc_linux_parse_cpuinfo_ppc(const char *prefix, const char *value, + struct hwloc_obj_info_s **infos, unsigned *infos_count, + int is_global) +{ + /* common fields */ + if (!strcmp("cpu", prefix)) { + hwloc__add_info(infos, infos_count, "CPUModel", value); + } else if (!strcmp("platform", prefix)) { + hwloc__add_info(infos, infos_count, "PlatformName", value); + } else if (!strcmp("model", prefix)) { + hwloc__add_info(infos, infos_count, "PlatformModel", value); + } + /* platform-specific fields */ + else if (!strcasecmp("vendor", prefix)) { + hwloc__add_info(infos, infos_count, "PlatformVendor", value); + } else if (!strcmp("Board ID", prefix)) { + hwloc__add_info(infos, infos_count, "PlatformBoardID", value); + } else if (!strcmp("Board", prefix) + || !strcasecmp("Machine", prefix)) { + /* machine and board are similar (and often more precise) than model above */ + char **valuep = hwloc__find_info_slot(infos, infos_count, "PlatformModel"); + if (*valuep) + free(*valuep); + *valuep = strdup(value); + } else if (!strcasecmp("Revision", prefix) + || !strcmp("Hardware rev", prefix)) { + hwloc__add_info(infos, infos_count, is_global ? "PlatformRevision" : "CPURevision", value); + } else if (!strcmp("SVR", prefix)) { + hwloc__add_info(infos, infos_count, "SystemVersionRegister", value); + } else if (!strcmp("PVR", prefix)) { + hwloc__add_info(infos, infos_count, "ProcessorVersionRegister", value); + } + /* don't match 'board*' because there's also "board l2" on some platforms */ + return 0; +} + +/* + * avr32: "chip type\t:" => OK + * blackfin: "model name\t:" => OK + * h8300: "CPU:" => OK + * m68k: "CPU:" => OK + * mips: "cpu model\t\t:" => OK + * openrisc: "CPU:" => OK + * sparc: "cpu\t\t:" => OK + * tile: "model name\t:" => OK + * unicore32: "Processor\t:" => OK + * alpha: "cpu\t\t\t: Alpha" + "cpu model\t\t:" => "cpu" overwritten by "cpu model", no processor indexes + * cris: "cpu\t\t:" + "cpu model\t:" => only "cpu" + * frv: "CPU-Core:" + "CPU:" => only "CPU" + * mn10300: "cpu core :" + "model name :" => only "model name" + * parisc: "cpu family\t:" + "cpu\t\t:" => only "cpu" + * + * not supported because of conflicts with other arch minor lines: + * m32r: "cpu family\t:" => KO (adding "cpu family" would break "blackfin") + * microblaze: "CPU-Family:" => KO + * sh: "cpu family\t:" + "cpu type\t:" => KO + * xtensa: "model\t\t:" => KO + */ +static int +hwloc_linux_parse_cpuinfo_generic(const char *prefix, const char *value, + struct hwloc_obj_info_s **infos, unsigned *infos_count, + int is_global __hwloc_attribute_unused) +{ + if (!strcmp("model name", prefix) + || !strcmp("Processor", prefix) + || !strcmp("chip type", prefix) + || !strcmp("cpu model", prefix) + || !strcasecmp("cpu", prefix)) { + /* keep the last one, assume it's more precise than the first one. + * we should have the Architecture keypair for basic information anyway. + */ + char **valuep = hwloc__find_info_slot(infos, infos_count, "CPUModel"); + if (*valuep) + free(*valuep); + *valuep = strdup(value); + } + return 0; +} + +static int +hwloc_linux_parse_cpuinfo(struct hwloc_linux_backend_data_s *data, + const char *path, + struct hwloc_linux_cpuinfo_proc ** Lprocs_p, + struct hwloc_obj_info_s **global_infos, unsigned *global_infos_count) +{ + FILE *fd; + char *str = NULL; + char *endptr; + unsigned len; + unsigned allocated_Lprocs = 0; + struct hwloc_linux_cpuinfo_proc * Lprocs = NULL; + unsigned numprocs = 0; + int curproc = -1; + int (*parse_cpuinfo_func)(const char *, const char *, struct hwloc_obj_info_s **, unsigned *, int) = NULL; + + if (!(fd=hwloc_fopen(path,"r", data->root_fd))) + { + hwloc_debug("could not open %s\n", path); + return -1; + } + +# define PROCESSOR "processor" +# define PACKAGEID "physical id" /* the longest one */ +# define COREID "core id" + len = 128; /* vendor/model can be very long */ + str = malloc(len); + hwloc_debug("\n\n * Topology extraction from %s *\n\n", path); + while (fgets(str,len,fd)!=NULL) { + unsigned long Ppkg, Pcore, Pproc; + char *end, *dot, *prefix, *value; + int noend = 0; + + /* remove the ending \n */ + end = strchr(str, '\n'); + if (end) + *end = 0; + else + noend = 1; + /* if empty line, skip and reset curproc */ + if (!*str) { + curproc = -1; + continue; + } + /* skip lines with no dot */ + dot = strchr(str, ':'); + if (!dot) + continue; + /* skip lines not starting with a letter */ + if ((*str > 'z' || *str < 'a') + && (*str > 'Z' || *str < 'A')) + continue; + + /* mark the end of the prefix */ + prefix = str; + end = dot; + while (end[-1] == ' ' || end[-1] == ' ') end--; /* need a strrspn() */ + *end = 0; + /* find beginning of value, its end is already marked */ + value = dot+1 + strspn(dot+1, " "); + + /* defines for parsing numbers */ +# define getprocnb_begin(field, var) \ + if (!strcmp(field,prefix)) { \ + var = strtoul(value,&endptr,0); \ + if (endptr==value) { \ + hwloc_debug("no number in "field" field of %s\n", path); \ + goto err; \ + } else if (var==ULONG_MAX) { \ + hwloc_debug("too big "field" number in %s\n", path); \ + goto err; \ + } \ + hwloc_debug(field " %lu\n", var) +# define getprocnb_end() \ + } + /* actually parse numbers */ + getprocnb_begin(PROCESSOR, Pproc); + curproc = numprocs++; + if (numprocs > allocated_Lprocs) { + if (!allocated_Lprocs) + allocated_Lprocs = 8; + else + allocated_Lprocs *= 2; + Lprocs = realloc(Lprocs, allocated_Lprocs * sizeof(*Lprocs)); + } + Lprocs[curproc].Pproc = Pproc; + Lprocs[curproc].Pcore = -1; + Lprocs[curproc].Ppkg = -1; + Lprocs[curproc].Lcore = -1; + Lprocs[curproc].Lpkg = -1; + Lprocs[curproc].infos = NULL; + Lprocs[curproc].infos_count = 0; + getprocnb_end() else + getprocnb_begin(PACKAGEID, Ppkg); + Lprocs[curproc].Ppkg = Ppkg; + getprocnb_end() else + getprocnb_begin(COREID, Pcore); + Lprocs[curproc].Pcore = Pcore; + getprocnb_end() else { + + /* architecture specific or default routine for parsing cpumodel */ + if (!parse_cpuinfo_func) { + parse_cpuinfo_func = hwloc_linux_parse_cpuinfo_generic; + if (*data->utsname.machine) { + /* x86_32 x86_64 k1om => x86 */ + if (!strcmp(data->utsname.machine, "x86_64") + || (data->utsname.machine[0] == 'i' && !strcmp(data->utsname.machine+2, "86")) + || !strcmp(data->utsname.machine, "k1om")) + parse_cpuinfo_func = hwloc_linux_parse_cpuinfo_x86; + /* ia64 */ + else if (!strcmp(data->utsname.machine, "ia64")) + parse_cpuinfo_func = hwloc_linux_parse_cpuinfo_ia64; + /* arm */ + else if (!strncmp(data->utsname.machine, "arm", 3)) + parse_cpuinfo_func = hwloc_linux_parse_cpuinfo_arm; + else if (!strncmp(data->utsname.machine, "ppc", 3) + || !strncmp(data->utsname.machine, "power", 5)) + parse_cpuinfo_func = hwloc_linux_parse_cpuinfo_ppc; + } + } + /* we can't assume that we already got a processor index line: + * alpha/frv/h8300/m68k/microblaze/sparc have no processor lines at all, only a global entry. + * tile has a global section with model name before the list of processor lines. + */ + parse_cpuinfo_func(prefix, value, + curproc >= 0 ? &Lprocs[curproc].infos : global_infos, + curproc >= 0 ? &Lprocs[curproc].infos_count : global_infos_count, + curproc < 0); + } + + if (noend) { + /* ignore end of line */ + if (fscanf(fd,"%*[^\n]") == EOF) + break; + getc(fd); + } + } + fclose(fd); + free(str); + + *Lprocs_p = Lprocs; + return numprocs; + + err: + fclose(fd); + free(str); + free(Lprocs); + return -1; +} + +static void +hwloc_linux_free_cpuinfo(struct hwloc_linux_cpuinfo_proc * Lprocs, unsigned numprocs, + struct hwloc_obj_info_s *global_infos, unsigned global_infos_count) +{ + if (Lprocs) { + unsigned i; + for(i=0; iinfos, &hwloc_get_root_obj(topology)->infos_count, + &global_infos, &global_infos_count); + + + if (_numprocs <= 0) + /* found no processor */ + return -1; + numprocs = _numprocs; + + /* initialize misc arrays, there can be at most numprocs entries */ + Lcore_to_Pcore = malloc(numprocs * sizeof(*Lcore_to_Pcore)); + Lcore_to_Ppkg = malloc(numprocs * sizeof(*Lcore_to_Ppkg)); + Lpkg_to_Ppkg = malloc(numprocs * sizeof(*Lpkg_to_Ppkg)); + for (i = 0; i < numprocs; i++) { + Lcore_to_Pcore[i] = -1; + Lcore_to_Ppkg[i] = -1; + Lpkg_to_Ppkg[i] = -1; + } + + cpuset = hwloc_bitmap_alloc(); + + /* create PU objects */ + for(Lproc=0; Lproccpuset = hwloc_bitmap_alloc(); + hwloc_bitmap_only(obj->cpuset, Pproc); + hwloc_debug_2args_bitmap("cpu %lu (os %lu) has cpuset %s\n", + Lproc, Pproc, obj->cpuset); + hwloc_insert_object_by_cpuset(topology, obj); + } + + topology->support.discovery->pu = 1; + hwloc_bitmap_copy(online_cpuset, cpuset); + hwloc_bitmap_free(cpuset); + + hwloc_debug("%u online processors found\n", numprocs); + hwloc_debug_bitmap("online processor cpuset: %s\n", online_cpuset); + + hwloc_debug("%s", "\n * Topology summary *\n"); + hwloc_debug("%u processors)\n", numprocs); + + /* fill Lprocs[].Lpkg and Lpkg_to_Ppkg */ + for(Lproc=0; Lproc0) { + for (i = 0; i < numpkgs; i++) { + struct hwloc_obj *obj = hwloc_alloc_setup_object(HWLOC_OBJ_PACKAGE, Lpkg_to_Ppkg[i]); + int doneinfos = 0; + obj->cpuset = hwloc_bitmap_alloc(); + for(j=0; jcpuset, Lprocs[j].Pproc); + if (!doneinfos) { + hwloc__move_infos(&obj->infos, &obj->infos_count, &Lprocs[j].infos, &Lprocs[j].infos_count); + doneinfos = 1; + } + } + hwloc_debug_1arg_bitmap("package %d has cpuset %s\n", i, obj->cpuset); + hwloc_insert_object_by_cpuset(topology, obj); + } + hwloc_debug("%s", "\n"); + } + + /* fill Lprocs[].Lcore, Lcore_to_Ppkg and Lcore_to_Pcore */ + for(Lproc=0; Lproc0) { + for (i = 0; i < numcores; i++) { + struct hwloc_obj *obj = hwloc_alloc_setup_object(HWLOC_OBJ_CORE, Lcore_to_Pcore[i]); + obj->cpuset = hwloc_bitmap_alloc(); + for(j=0; jcpuset, Lprocs[j].Pproc); + hwloc_debug_1arg_bitmap("Core %d has cpuset %s\n", i, obj->cpuset); + hwloc_insert_object_by_cpuset(topology, obj); + } + hwloc_debug("%s", "\n"); + } + + free(Lcore_to_Pcore); + free(Lcore_to_Ppkg); + free(Lpkg_to_Ppkg); + + hwloc_linux_free_cpuinfo(Lprocs, numprocs, global_infos, global_infos_count); + + look_powerpc_device_tree(topology, data); + return 0; +} + + + +/************************************* + ****** Main Topology Discovery ****** + *************************************/ + +static void +hwloc__linux_get_mic_sn(struct hwloc_topology *topology, struct hwloc_linux_backend_data_s *data) +{ + FILE *file; + char line[64], *tmp, *end; + file = hwloc_fopen("/proc/elog", "r", data->root_fd); + if (!file) + return; + if (!fgets(line, sizeof(line), file)) + goto out_with_file; + if (strncmp(line, "Card ", 5)) + goto out_with_file; + tmp = line + 5; + end = strchr(tmp, ':'); + if (!end) + goto out_with_file; + *end = '\0'; + hwloc_obj_add_info(hwloc_get_root_obj(topology), "MICSerialNumber", tmp); + + out_with_file: + fclose(file); +} + +static void +hwloc_linux_fallback_pu_level(struct hwloc_topology *topology) +{ + if (topology->is_thissystem) + hwloc_setup_pu_level(topology, hwloc_fallback_nbprocessors(topology)); + else + /* fsys-root but not this system, no way, assume there's just 1 + * processor :/ */ + hwloc_setup_pu_level(topology, 1); +} + +static void +hwloc_gather_system_info(struct hwloc_topology *topology, + struct hwloc_linux_backend_data_s *data) +{ + FILE *file; + char line[128]; /* enough for utsname fields */ + const char *env; + + /* initialize to something sane */ + memset(&data->utsname, 0, sizeof(data->utsname)); + + /* read thissystem info */ + if (topology->is_thissystem) + uname(&data->utsname); + + /* overwrite with optional /proc/hwloc-nofile-info */ + file = hwloc_fopen("/proc/hwloc-nofile-info", "r", data->root_fd); + if (file) { + while (fgets(line, sizeof(line), file)) { + char *tmp = strchr(line, '\n'); + if (!strncmp("OSName: ", line, 8)) { + if (tmp) + *tmp = '\0'; + strncpy(data->utsname.sysname, line+8, sizeof(data->utsname.sysname)); + data->utsname.sysname[sizeof(data->utsname.sysname)-1] = '\0'; + } else if (!strncmp("OSRelease: ", line, 11)) { + if (tmp) + *tmp = '\0'; + strncpy(data->utsname.release, line+11, sizeof(data->utsname.release)); + data->utsname.release[sizeof(data->utsname.release)-1] = '\0'; + } else if (!strncmp("OSVersion: ", line, 11)) { + if (tmp) + *tmp = '\0'; + strncpy(data->utsname.version, line+11, sizeof(data->utsname.version)); + data->utsname.version[sizeof(data->utsname.version)-1] = '\0'; + } else if (!strncmp("HostName: ", line, 10)) { + if (tmp) + *tmp = '\0'; + strncpy(data->utsname.nodename, line+10, sizeof(data->utsname.nodename)); + data->utsname.nodename[sizeof(data->utsname.nodename)-1] = '\0'; + } else if (!strncmp("Architecture: ", line, 14)) { + if (tmp) + *tmp = '\0'; + strncpy(data->utsname.machine, line+14, sizeof(data->utsname.machine)); + data->utsname.machine[sizeof(data->utsname.machine)-1] = '\0'; + } else { + hwloc_debug("ignored /proc/hwloc-nofile-info line %s\n", line); + /* ignored */ + } + } + fclose(file); + } + + env = getenv("HWLOC_DUMP_NOFILE_INFO"); + if (env && *env) { + file = fopen(env, "w"); + if (file) { + if (*data->utsname.sysname) + fprintf(file, "OSName: %s\n", data->utsname.sysname); + if (*data->utsname.release) + fprintf(file, "OSRelease: %s\n", data->utsname.release); + if (*data->utsname.version) + fprintf(file, "OSVersion: %s\n", data->utsname.version); + if (*data->utsname.nodename) + fprintf(file, "HostName: %s\n", data->utsname.nodename); + if (*data->utsname.machine) + fprintf(file, "Architecture: %s\n", data->utsname.machine); + fclose(file); + } + } +} + +static int +hwloc_look_linuxfs(struct hwloc_backend *backend) +{ + struct hwloc_topology *topology = backend->topology; + struct hwloc_linux_backend_data_s *data = backend->private_data; + DIR *nodes_dir; + unsigned nbnodes; + char *cpuset_mntpnt, *cgroup_mntpnt, *cpuset_name = NULL; + int err; + + if (topology->levels[0][0]->cpuset) + /* somebody discovered things */ + return 0; + + hwloc_gather_system_info(topology, data); + + hwloc_alloc_obj_cpusets(topology->levels[0][0]); + + /* Gather the list of admin-disabled cpus and mems */ + hwloc_find_linux_cpuset_mntpnt(&cgroup_mntpnt, &cpuset_mntpnt, data->root_fd); + if (cgroup_mntpnt || cpuset_mntpnt) { + cpuset_name = hwloc_read_linux_cpuset_name(data->root_fd, topology->pid); + if (cpuset_name) { + hwloc_admin_disable_set_from_cpuset(data, cgroup_mntpnt, cpuset_mntpnt, cpuset_name, "cpus", topology->levels[0][0]->allowed_cpuset); + hwloc_admin_disable_set_from_cpuset(data, cgroup_mntpnt, cpuset_mntpnt, cpuset_name, "mems", topology->levels[0][0]->allowed_nodeset); + } + free(cgroup_mntpnt); + free(cpuset_mntpnt); + } + + nodes_dir = hwloc_opendir("/proc/nodes", data->root_fd); + if (nodes_dir) { + /* Kerrighed */ + struct dirent *dirent; + char path[128]; + hwloc_obj_t machine; + hwloc_bitmap_t machine_online_set; + + /* replace top-level object type with SYSTEM and add some MACHINE underneath */ + + topology->levels[0][0]->type = HWLOC_OBJ_SYSTEM; + topology->levels[0][0]->name = strdup("Kerrighed"); + + /* No cpuset support for now. */ + /* No sys support for now. */ + while ((dirent = readdir(nodes_dir)) != NULL) { + unsigned long node; + if (strncmp(dirent->d_name, "node", 4)) + continue; + machine_online_set = hwloc_bitmap_alloc(); + node = strtoul(dirent->d_name+4, NULL, 0); + snprintf(path, sizeof(path), "/proc/nodes/node%lu/cpuinfo", node); + err = look_cpuinfo(topology, data, path, machine_online_set); + if (err < 0) { + hwloc_bitmap_free(machine_online_set); + continue; + } + hwloc_bitmap_or(topology->levels[0][0]->online_cpuset, topology->levels[0][0]->online_cpuset, machine_online_set); + machine = hwloc_alloc_setup_object(HWLOC_OBJ_MACHINE, node); + machine->cpuset = machine_online_set; + hwloc_debug_1arg_bitmap("machine number %lu has cpuset %s\n", + node, machine_online_set); + + /* Get the machine memory attributes */ + hwloc_get_kerrighed_node_meminfo_info(topology, data, node, &machine->memory); + + /* Gather DMI info */ + /* FIXME: get the right DMI info of each machine */ + hwloc__get_dmi_id_info(data, machine); + + hwloc_insert_object_by_cpuset(topology, machine); + } + closedir(nodes_dir); + } else { + /* Get the machine memory attributes */ + hwloc_get_procfs_meminfo_info(topology, data, &topology->levels[0][0]->memory); + + /* Gather NUMA information. Must be after hwloc_get_procfs_meminfo_info so that the hugepage size is known */ + if (look_sysfsnode(topology, data, "/sys/bus/node/devices", &nbnodes) < 0) + look_sysfsnode(topology, data, "/sys/devices/system/node", &nbnodes); + + /* if we found some numa nodes, the machine object has no local memory */ + if (nbnodes) { + unsigned i; + topology->levels[0][0]->memory.local_memory = 0; + if (topology->levels[0][0]->memory.page_types) + for(i=0; ilevels[0][0]->memory.page_types_len; i++) + topology->levels[0][0]->memory.page_types[i].count = 0; + } + + /* Gather the list of cpus now */ + if (getenv("HWLOC_LINUX_USE_CPUINFO") + || (hwloc_access("/sys/devices/system/cpu/cpu0/topology/core_siblings", R_OK, data->root_fd) < 0 + && hwloc_access("/sys/devices/system/cpu/cpu0/topology/thread_siblings", R_OK, data->root_fd) < 0 + && hwloc_access("/sys/bus/cpu/devices/cpu0/topology/thread_siblings", R_OK, data->root_fd) < 0 + && hwloc_access("/sys/bus/cpu/devices/cpu0/topology/core_siblings", R_OK, data->root_fd) < 0)) { + /* revert to reading cpuinfo only if /sys/.../topology unavailable (before 2.6.16) + * or not containing anything interesting */ + err = look_cpuinfo(topology, data, "/proc/cpuinfo", topology->levels[0][0]->online_cpuset); + if (err < 0) + hwloc_linux_fallback_pu_level(topology); + + } else { + struct hwloc_linux_cpuinfo_proc * Lprocs = NULL; + struct hwloc_obj_info_s *global_infos = NULL; + unsigned global_infos_count = 0; + int numprocs = hwloc_linux_parse_cpuinfo(data, "/proc/cpuinfo", &Lprocs, &global_infos, &global_infos_count); + if (numprocs <= 0) + Lprocs = NULL; + if (look_sysfscpu(topology, data, "/sys/bus/cpu/devices", Lprocs, numprocs) < 0) + if (look_sysfscpu(topology, data, "/sys/devices/system/cpu", Lprocs, numprocs) < 0) + /* sysfs but we failed to read cpu topology, fallback */ + hwloc_linux_fallback_pu_level(topology); + hwloc__move_infos(&hwloc_get_root_obj(topology)->infos, &hwloc_get_root_obj(topology)->infos_count, + &global_infos, &global_infos_count); + hwloc_linux_free_cpuinfo(Lprocs, numprocs, global_infos, global_infos_count); + } + + /* Gather DMI info */ + hwloc__get_dmi_id_info(data, topology->levels[0][0]); + if (hwloc_topology_get_flags(topology) & (HWLOC_TOPOLOGY_FLAG_IO_DEVICES|HWLOC_TOPOLOGY_FLAG_WHOLE_IO)) + hwloc__get_firmware_dmi_memory_info(topology, data); + } + + hwloc_obj_add_info(topology->levels[0][0], "Backend", "Linux"); + if (cpuset_name) { + hwloc_obj_add_info(topology->levels[0][0], "LinuxCgroup", cpuset_name); + free(cpuset_name); + } + + hwloc__linux_get_mic_sn(topology, data); + + /* data->utsname was filled with real uname or \0, we can safely pass it */ + hwloc_add_uname_info(topology, &data->utsname); + + return 1; +} + + + +/**************************************** + ***** Linux PCI backend callbacks ****** + **************************************** + * Do not support changing the fsroot (use sysfs) + */ + +static hwloc_obj_t +hwloc_linux_add_os_device(struct hwloc_backend *backend, struct hwloc_obj *pcidev, hwloc_obj_osdev_type_t type, const char *name) +{ + struct hwloc_topology *topology = backend->topology; + struct hwloc_obj *obj = hwloc_alloc_setup_object(HWLOC_OBJ_OS_DEVICE, -1); + obj->name = strdup(name); + obj->logical_index = -1; + obj->attr->osdev.type = type; + + hwloc_insert_object_by_parent(topology, pcidev, obj); + /* insert_object_by_parent() doesn't merge during insert, so obj is still valid */ + + return obj; +} + +typedef void (*hwloc_linux_class_fillinfos_t)(struct hwloc_backend *backend, struct hwloc_obj *osdev, const char *osdevpath); + +/* cannot be used in fsroot-aware code, would have to move to a per-topology variable */ + +static void +hwloc_linux_check_deprecated_classlinks_model(struct hwloc_linux_backend_data_s *data) +{ + int root_fd = data->root_fd; + DIR *dir; + struct dirent *dirent; + char path[128]; + struct stat st; + + data->deprecated_classlinks_model = -1; + + dir = hwloc_opendir("/sys/class/net", root_fd); + if (!dir) + return; + while ((dirent = readdir(dir)) != NULL) { + if (!strcmp(dirent->d_name, ".") || !strcmp(dirent->d_name, "..") || !strcmp(dirent->d_name, "lo")) + continue; + snprintf(path, sizeof(path), "/sys/class/net/%s/device/net/%s", dirent->d_name, dirent->d_name); + if (hwloc_stat(path, &st, root_fd) == 0) { + data->deprecated_classlinks_model = 0; + goto out; + } + snprintf(path, sizeof(path), "/sys/class/net/%s/device/net:%s", dirent->d_name, dirent->d_name); + if (hwloc_stat(path, &st, root_fd) == 0) { + data->deprecated_classlinks_model = 1; + goto out; + } + } +out: + closedir(dir); +} + +/* class objects that are immediately below pci devices: + * look for objects of the given classname below a sysfs (pcidev) directory + */ +static int +hwloc_linux_class_readdir(struct hwloc_backend *backend, + struct hwloc_obj *pcidev, const char *devicepath, + hwloc_obj_osdev_type_t type, const char *classname, + hwloc_linux_class_fillinfos_t fillinfo) +{ + struct hwloc_linux_backend_data_s *data = backend->private_data; + int root_fd = data->root_fd; + size_t classnamelen = strlen(classname); + char path[256]; + DIR *dir; + struct dirent *dirent; + hwloc_obj_t obj; + int res = 0, err; + + if (data->deprecated_classlinks_model == -2) + hwloc_linux_check_deprecated_classlinks_model(data); + + if (data->deprecated_classlinks_model != 1) { + /* modern sysfs: // */ + struct stat st; + snprintf(path, sizeof(path), "%s/%s", devicepath, classname); + + /* some very host kernel (2.6.9/RHEL4) have / symlink without any way to find . + * make sure / is a directory to avoid this case. + */ + err = hwloc_lstat(path, &st, root_fd); + if (err < 0 || !S_ISDIR(st.st_mode)) + goto trydeprecated; + + dir = hwloc_opendir(path, root_fd); + if (dir) { + data->deprecated_classlinks_model = 0; + while ((dirent = readdir(dir)) != NULL) { + if (!strcmp(dirent->d_name, ".") || !strcmp(dirent->d_name, "..")) + continue; + obj = hwloc_linux_add_os_device(backend, pcidev, type, dirent->d_name); + if (fillinfo) { + snprintf(path, sizeof(path), "%s/%s/%s", devicepath, classname, dirent->d_name); + fillinfo(backend, obj, path); + } + res++; + } + closedir(dir); + return res; + } + } + +trydeprecated: + if (data->deprecated_classlinks_model != 0) { + /* deprecated sysfs: /: */ + dir = hwloc_opendir(devicepath, root_fd); + if (dir) { + while ((dirent = readdir(dir)) != NULL) { + if (strncmp(dirent->d_name, classname, classnamelen) || dirent->d_name[classnamelen] != ':') + continue; + data->deprecated_classlinks_model = 1; + obj = hwloc_linux_add_os_device(backend, pcidev, type, dirent->d_name + classnamelen+1); + if (fillinfo) { + snprintf(path, sizeof(path), "%s/%s", devicepath, dirent->d_name); + fillinfo(backend, obj, path); + } + res++; + } + closedir(dir); + return res; + } + } + + return 0; +} + +/* + * look for net objects below a pcidev in sysfs + */ +static void +hwloc_linux_net_class_fillinfos(struct hwloc_backend *backend, + struct hwloc_obj *obj, const char *osdevpath) +{ + struct hwloc_linux_backend_data_s *data = backend->private_data; + int root_fd = data->root_fd; + FILE *fd; + struct stat st; + char path[256]; + snprintf(path, sizeof(path), "%s/address", osdevpath); + fd = hwloc_fopen(path, "r", root_fd); + if (fd) { + char address[128]; + if (fgets(address, sizeof(address), fd)) { + char *eol = strchr(address, '\n'); + if (eol) + *eol = 0; + hwloc_obj_add_info(obj, "Address", address); + } + fclose(fd); + } + snprintf(path, sizeof(path), "%s/device/infiniband", osdevpath); + if (!hwloc_stat(path, &st, root_fd)) { + snprintf(path, sizeof(path), "%s/dev_id", osdevpath); + fd = hwloc_fopen(path, "r", root_fd); + if (fd) { + char hexid[16]; + if (fgets(hexid, sizeof(hexid), fd)) { + char *eoid; + unsigned long port; + port = strtoul(hexid, &eoid, 0); + if (eoid != hexid) { + char portstr[16]; + snprintf(portstr, sizeof(portstr), "%ld", port+1); + hwloc_obj_add_info(obj, "Port", portstr); + } + } + fclose(fd); + } + } +} + +static int +hwloc_linux_lookup_net_class(struct hwloc_backend *backend, + struct hwloc_obj *pcidev, const char *pcidevpath) +{ + return hwloc_linux_class_readdir(backend, pcidev, pcidevpath, HWLOC_OBJ_OSDEV_NETWORK, "net", hwloc_linux_net_class_fillinfos); +} + +/* + * look for infiniband objects below a pcidev in sysfs + */ +static void +hwloc_linux_infiniband_class_fillinfos(struct hwloc_backend *backend, + struct hwloc_obj *obj, const char *osdevpath) +{ + struct hwloc_linux_backend_data_s *data = backend->private_data; + int root_fd = data->root_fd; + FILE *fd; + char path[256]; + unsigned i,j; + + snprintf(path, sizeof(path), "%s/node_guid", osdevpath); + fd = hwloc_fopen(path, "r", root_fd); + if (fd) { + char guidvalue[20]; + if (fgets(guidvalue, sizeof(guidvalue), fd)) { + size_t len; + len = strspn(guidvalue, "0123456789abcdefx:"); + assert(len == 19); + guidvalue[len] = '\0'; + hwloc_obj_add_info(obj, "NodeGUID", guidvalue); + } + fclose(fd); + } + + snprintf(path, sizeof(path), "%s/sys_image_guid", osdevpath); + fd = hwloc_fopen(path, "r", root_fd); + if (fd) { + char guidvalue[20]; + if (fgets(guidvalue, sizeof(guidvalue), fd)) { + size_t len; + len = strspn(guidvalue, "0123456789abcdefx:"); + assert(len == 19); + guidvalue[len] = '\0'; + hwloc_obj_add_info(obj, "SysImageGUID", guidvalue); + } + fclose(fd); + } + + for(i=1; ; i++) { + snprintf(path, sizeof(path), "%s/ports/%u/state", osdevpath, i); + fd = hwloc_fopen(path, "r", root_fd); + if (fd) { + char statevalue[2]; + if (fgets(statevalue, sizeof(statevalue), fd)) { + char statename[32]; + statevalue[1] = '\0'; /* only keep the first byte/digit */ + snprintf(statename, sizeof(statename), "Port%uState", i); + hwloc_obj_add_info(obj, statename, statevalue); + } + fclose(fd); + } else { + /* no such port */ + break; + } + + snprintf(path, sizeof(path), "%s/ports/%u/lid", osdevpath, i); + fd = hwloc_fopen(path, "r", root_fd); + if (fd) { + char lidvalue[11]; + if (fgets(lidvalue, sizeof(lidvalue), fd)) { + char lidname[32]; + size_t len; + len = strspn(lidvalue, "0123456789abcdefx"); + lidvalue[len] = '\0'; + snprintf(lidname, sizeof(lidname), "Port%uLID", i); + hwloc_obj_add_info(obj, lidname, lidvalue); + } + fclose(fd); + } + + snprintf(path, sizeof(path), "%s/ports/%u/lid_mask_count", osdevpath, i); + fd = hwloc_fopen(path, "r", root_fd); + if (fd) { + char lidvalue[11]; + if (fgets(lidvalue, sizeof(lidvalue), fd)) { + char lidname[32]; + size_t len; + len = strspn(lidvalue, "0123456789"); + lidvalue[len] = '\0'; + snprintf(lidname, sizeof(lidname), "Port%uLMC", i); + hwloc_obj_add_info(obj, lidname, lidvalue); + } + fclose(fd); + } + + for(j=0; ; j++) { + snprintf(path, sizeof(path), "%s/ports/%u/gids/%u", osdevpath, i, j); + fd = hwloc_fopen(path, "r", root_fd); + if (fd) { + char gidvalue[40]; + if (fgets(gidvalue, sizeof(gidvalue), fd)) { + char gidname[32]; + size_t len; + len = strspn(gidvalue, "0123456789abcdefx:"); + assert(len == 39); + gidvalue[len] = '\0'; + if (strncmp(gidvalue+20, "0000:0000:0000:0000", 19)) { + /* only keep initialized GIDs */ + snprintf(gidname, sizeof(gidname), "Port%uGID%u", i, j); + hwloc_obj_add_info(obj, gidname, gidvalue); + } + } + fclose(fd); + } else { + /* no such port */ + break; + } + } + } +} + +static int +hwloc_linux_lookup_openfabrics_class(struct hwloc_backend *backend, + struct hwloc_obj *pcidev, const char *pcidevpath) +{ + return hwloc_linux_class_readdir(backend, pcidev, pcidevpath, HWLOC_OBJ_OSDEV_OPENFABRICS, "infiniband", hwloc_linux_infiniband_class_fillinfos); +} + +/* look for dma objects below a pcidev in sysfs */ +static int +hwloc_linux_lookup_dma_class(struct hwloc_backend *backend, + struct hwloc_obj *pcidev, const char *pcidevpath) +{ + return hwloc_linux_class_readdir(backend, pcidev, pcidevpath, HWLOC_OBJ_OSDEV_DMA, "dma", NULL); +} + +/* look for drm objects below a pcidev in sysfs */ +static int +hwloc_linux_lookup_drm_class(struct hwloc_backend *backend, + struct hwloc_obj *pcidev, const char *pcidevpath) +{ + return hwloc_linux_class_readdir(backend, pcidev, pcidevpath, HWLOC_OBJ_OSDEV_GPU, "drm", NULL); + + /* we could look at the "graphics" class too, but it doesn't help for proprietary drivers either */ + + /* GPU devices (even with a proprietary driver) seem to have a boot_vga field in their PCI device directory (since 2.6.30), + * so we could create a OS device for each PCI devices with such a field. + * boot_vga is actually created when class >> 8 == VGA (it contains 1 for boot vga device), so it's trivial anyway. + */ +} + +/* + * look for block objects below a pcidev in sysfs + */ + +static void +hwloc_linux_block_class_fillinfos(struct hwloc_backend *backend, + struct hwloc_obj *obj, const char *osdevpath) +{ + struct hwloc_linux_backend_data_s *data = backend->private_data; + int root_fd = data->root_fd; + FILE *fd; + char path[256]; + char line[128]; + char vendor[64] = ""; + char model[64] = ""; + char serial[64] = ""; + char revision[64] = ""; + char blocktype[64] = ""; + unsigned major_id, minor_id; + char *tmp; + + snprintf(path, sizeof(path), "%s/dev", osdevpath); + fd = hwloc_fopen(path, "r", root_fd); + if (!fd) + return; + + if (NULL == fgets(line, sizeof(line), fd)) { + fclose(fd); + return; + } + fclose(fd); + + if (sscanf(line, "%u:%u", &major_id, &minor_id) != 2) + return; + tmp = strchr(line, '\n'); + if (tmp) + *tmp = '\0'; + hwloc_obj_add_info(obj, "LinuxDeviceID", line); + +#ifdef HAVE_LIBUDEV_H + if (data->udev) { + struct udev_device *dev; + const char *prop; + dev = udev_device_new_from_subsystem_sysname(data->udev, "block", obj->name); + if (!dev) + return; + prop = udev_device_get_property_value(dev, "ID_VENDOR"); + if (prop) + strcpy(vendor, prop); + prop = udev_device_get_property_value(dev, "ID_MODEL"); + if (prop) + strcpy(model, prop); + prop = udev_device_get_property_value(dev, "ID_REVISION"); + if (prop) + strcpy(revision, prop); + prop = udev_device_get_property_value(dev, "ID_SERIAL_SHORT"); + if (prop) + strcpy(serial, prop); + prop = udev_device_get_property_value(dev, "ID_TYPE"); + if (prop) + strcpy(blocktype, prop); + + udev_device_unref(dev); + } else + /* fallback to reading files, works with any fsroot */ +#endif + { + snprintf(path, sizeof(path), "/run/udev/data/b%u:%u", major_id, minor_id); + fd = hwloc_fopen(path, "r", root_fd); + if (!fd) + return; + + while (NULL != fgets(line, sizeof(line), fd)) { + tmp = strchr(line, '\n'); + if (tmp) + *tmp = '\0'; + if (!strncmp(line, "E:ID_VENDOR=", strlen("E:ID_VENDOR="))) { + strcpy(vendor, line+strlen("E:ID_VENDOR=")); + } else if (!strncmp(line, "E:ID_MODEL=", strlen("E:ID_MODEL="))) { + strcpy(model, line+strlen("E:ID_MODEL=")); + } else if (!strncmp(line, "E:ID_REVISION=", strlen("E:ID_REVISION="))) { + strcpy(revision, line+strlen("E:ID_REVISION=")); + } else if (!strncmp(line, "E:ID_SERIAL_SHORT=", strlen("E:ID_SERIAL_SHORT="))) { + strcpy(serial, line+strlen("E:ID_SERIAL_SHORT=")); + } else if (!strncmp(line, "E:ID_TYPE=", strlen("E:ID_TYPE="))) { + strcpy(blocktype, line+strlen("E:ID_TYPE=")); + } + } + fclose(fd); + } + + /* clear fake "ATA" vendor name */ + if (!strcasecmp(vendor, "ATA")) + *vendor = '\0'; + /* overwrite vendor name from model when possible */ + if (!*vendor) { + if (!strncasecmp(model, "wd", 2)) + strcpy(vendor, "Western Digital"); + else if (!strncasecmp(model, "st", 2)) + strcpy(vendor, "Seagate"); + else if (!strncasecmp(model, "samsung", 7)) + strcpy(vendor, "Samsung"); + else if (!strncasecmp(model, "sandisk", 7)) + strcpy(vendor, "SanDisk"); + else if (!strncasecmp(model, "toshiba", 7)) + strcpy(vendor, "Toshiba"); + } + + if (*vendor) + hwloc_obj_add_info(obj, "Vendor", vendor); + if (*model) + hwloc_obj_add_info(obj, "Model", model); + if (*revision) + hwloc_obj_add_info(obj, "Revision", revision); + if (*serial) + hwloc_obj_add_info(obj, "SerialNumber", serial); + + if (!strcmp(blocktype, "disk")) + hwloc_obj_add_info(obj, "Type", "Disk"); + else if (!strcmp(blocktype, "tape")) + hwloc_obj_add_info(obj, "Type", "Tape"); + else if (!strcmp(blocktype, "cd") || !strcmp(blocktype, "floppy") || !strcmp(blocktype, "optical")) + hwloc_obj_add_info(obj, "Type", "Removable Media Device"); + else /* generic, usb mass storage/rbc, usb mass storage/scsi */ + hwloc_obj_add_info(obj, "Type", "Other"); +} + +/* block class objects are in + * host%d/target%d:%d:%d/%d:%d:%d:%d/ + * or + * host%d/port-%d:%d/end_device-%d:%d/target%d:%d:%d/%d:%d:%d:%d/ + * or + * ide%d/%d.%d/ + * below pci devices */ +static int +hwloc_linux_lookup_host_block_class(struct hwloc_backend *backend, + struct hwloc_obj *pcidev, char *path, size_t pathlen) +{ + struct hwloc_linux_backend_data_s *data = backend->private_data; + int root_fd = data->root_fd; + DIR *hostdir, *portdir, *targetdir; + struct dirent *hostdirent, *portdirent, *targetdirent; + size_t hostdlen, portdlen, targetdlen; + int dummy; + int res = 0; + + hostdir = hwloc_opendir(path, root_fd); + if (!hostdir) + return 0; + + while ((hostdirent = readdir(hostdir)) != NULL) { + if (sscanf(hostdirent->d_name, "port-%d:%d", &dummy, &dummy) == 2) + { + /* found host%d/port-%d:%d */ + path[pathlen] = '/'; + strcpy(&path[pathlen+1], hostdirent->d_name); + pathlen += hostdlen = 1+strlen(hostdirent->d_name); + portdir = hwloc_opendir(path, root_fd); + if (!portdir) + continue; + while ((portdirent = readdir(portdir)) != NULL) { + if (sscanf(portdirent->d_name, "end_device-%d:%d", &dummy, &dummy) == 2) { + /* found host%d/port-%d:%d/end_device-%d:%d */ + path[pathlen] = '/'; + strcpy(&path[pathlen+1], portdirent->d_name); + pathlen += portdlen = 1+strlen(portdirent->d_name); + res += hwloc_linux_lookup_host_block_class(backend, pcidev, path, pathlen); + /* restore parent path */ + pathlen -= portdlen; + path[pathlen] = '\0'; + } + } + closedir(portdir); + /* restore parent path */ + pathlen -= hostdlen; + path[pathlen] = '\0'; + continue; + } else if (sscanf(hostdirent->d_name, "target%d:%d:%d", &dummy, &dummy, &dummy) == 3) { + /* found host%d/target%d:%d:%d */ + path[pathlen] = '/'; + strcpy(&path[pathlen+1], hostdirent->d_name); + pathlen += hostdlen = 1+strlen(hostdirent->d_name); + targetdir = hwloc_opendir(path, root_fd); + if (!targetdir) + continue; + while ((targetdirent = readdir(targetdir)) != NULL) { + if (sscanf(targetdirent->d_name, "%d:%d:%d:%d", &dummy, &dummy, &dummy, &dummy) != 4) + continue; + /* found host%d/target%d:%d:%d/%d:%d:%d:%d */ + path[pathlen] = '/'; + strcpy(&path[pathlen+1], targetdirent->d_name); + pathlen += targetdlen = 1+strlen(targetdirent->d_name); + /* lookup block class for real */ + res += hwloc_linux_class_readdir(backend, pcidev, path, HWLOC_OBJ_OSDEV_BLOCK, "block", hwloc_linux_block_class_fillinfos); + /* restore parent path */ + pathlen -= targetdlen; + path[pathlen] = '\0'; + } + closedir(targetdir); + /* restore parent path */ + pathlen -= hostdlen; + path[pathlen] = '\0'; + } + } + closedir(hostdir); + + return res; +} + +static int +hwloc_linux_lookup_block_class(struct hwloc_backend *backend, + struct hwloc_obj *pcidev, const char *pcidevpath) +{ + struct hwloc_linux_backend_data_s *data = backend->private_data; + int root_fd = data->root_fd; + size_t pathlen; + DIR *devicedir, *hostdir; + struct dirent *devicedirent, *hostdirent; + size_t devicedlen, hostdlen; + char path[256]; + int dummy; + int res = 0; + + strcpy(path, pcidevpath); + pathlen = strlen(path); + + devicedir = hwloc_opendir(pcidevpath, root_fd); + if (!devicedir) + return 0; + + while ((devicedirent = readdir(devicedir)) != NULL) { + if (sscanf(devicedirent->d_name, "ide%d", &dummy) == 1) { + /* found ide%d */ + path[pathlen] = '/'; + strcpy(&path[pathlen+1], devicedirent->d_name); + pathlen += devicedlen = 1+strlen(devicedirent->d_name); + hostdir = hwloc_opendir(path, root_fd); + if (!hostdir) + continue; + while ((hostdirent = readdir(hostdir)) != NULL) { + if (sscanf(hostdirent->d_name, "%d.%d", &dummy, &dummy) == 2) { + /* found ide%d/%d.%d */ + path[pathlen] = '/'; + strcpy(&path[pathlen+1], hostdirent->d_name); + pathlen += hostdlen = 1+strlen(hostdirent->d_name); + /* lookup block class for real */ + res += hwloc_linux_class_readdir(backend, pcidev, path, HWLOC_OBJ_OSDEV_BLOCK, "block", NULL); + /* restore parent path */ + pathlen -= hostdlen; + path[pathlen] = '\0'; + } + } + closedir(hostdir); + /* restore parent path */ + pathlen -= devicedlen; + path[pathlen] = '\0'; + } else if (sscanf(devicedirent->d_name, "host%d", &dummy) == 1) { + /* found host%d */ + path[pathlen] = '/'; + strcpy(&path[pathlen+1], devicedirent->d_name); + pathlen += devicedlen = 1+strlen(devicedirent->d_name); + res += hwloc_linux_lookup_host_block_class(backend, pcidev, path, pathlen); + /* restore parent path */ + pathlen -= devicedlen; + path[pathlen] = '\0'; + } else if (sscanf(devicedirent->d_name, "ata%d", &dummy) == 1) { + /* found ata%d */ + path[pathlen] = '/'; + strcpy(&path[pathlen+1], devicedirent->d_name); + pathlen += devicedlen = 1+strlen(devicedirent->d_name); + hostdir = hwloc_opendir(path, root_fd); + if (!hostdir) + continue; + while ((hostdirent = readdir(hostdir)) != NULL) { + if (sscanf(hostdirent->d_name, "host%d", &dummy) == 1) { + /* found ata%d/host%d */ + path[pathlen] = '/'; + strcpy(&path[pathlen+1], hostdirent->d_name); + pathlen += hostdlen = 1+strlen(hostdirent->d_name); + /* lookup block class for real */ + res += hwloc_linux_lookup_host_block_class(backend, pcidev, path, pathlen); + /* restore parent path */ + pathlen -= hostdlen; + path[pathlen] = '\0'; + } + } + closedir(hostdir); + /* restore parent path */ + pathlen -= devicedlen; + path[pathlen] = '\0'; + } + } + closedir(devicedir); + + return res; +} + +static void +hwloc_linux_mic_class_fillinfos(struct hwloc_backend *backend, + struct hwloc_obj *obj, const char *osdevpath) +{ + struct hwloc_linux_backend_data_s *data = backend->private_data; + int root_fd = data->root_fd; + FILE *fd; + char path[256]; + + hwloc_obj_add_info(obj, "CoProcType", "MIC"); + + snprintf(path, sizeof(path), "%s/family", osdevpath); + fd = hwloc_fopen(path, "r", root_fd); + if (fd) { + char family[64]; + if (fgets(family, sizeof(family), fd)) { + char *eol = strchr(family, '\n'); + if (eol) + *eol = 0; + hwloc_obj_add_info(obj, "MICFamily", family); + } + fclose(fd); + } + + snprintf(path, sizeof(path), "%s/sku", osdevpath); + fd = hwloc_fopen(path, "r", root_fd); + if (fd) { + char sku[64]; + if (fgets(sku, sizeof(sku), fd)) { + char *eol = strchr(sku, '\n'); + if (eol) + *eol = 0; + hwloc_obj_add_info(obj, "MICSKU", sku); + } + fclose(fd); + } + + snprintf(path, sizeof(path), "%s/serialnumber", osdevpath); + fd = hwloc_fopen(path, "r", root_fd); + if (fd) { + char sn[64]; + if (fgets(sn, sizeof(sn), fd)) { + char *eol = strchr(sn, '\n'); + if (eol) + *eol = 0; + hwloc_obj_add_info(obj, "MICSerialNumber", sn); + } + fclose(fd); + } + + snprintf(path, sizeof(path), "%s/active_cores", osdevpath); + fd = hwloc_fopen(path, "r", root_fd); + if (fd) { + char string[10]; + if (fgets(string, sizeof(string), fd)) { + unsigned long count = strtoul(string, NULL, 16); + snprintf(string, sizeof(string), "%lu", count); + hwloc_obj_add_info(obj, "MICActiveCores", string); + } + fclose(fd); + } + + snprintf(path, sizeof(path), "%s/memsize", osdevpath); + fd = hwloc_fopen(path, "r", root_fd); + if (fd) { + char string[20]; + if (fgets(string, sizeof(string), fd)) { + unsigned long count = strtoul(string, NULL, 16); + snprintf(string, sizeof(string), "%lu", count); + hwloc_obj_add_info(obj, "MICMemorySize", string); + } + fclose(fd); + } +} + +static int +hwloc_linux_lookup_mic_class(struct hwloc_backend *backend, + struct hwloc_obj *pcidev, const char *pcidevpath) +{ + return hwloc_linux_class_readdir(backend, pcidev, pcidevpath, HWLOC_OBJ_OSDEV_COPROC, "mic", hwloc_linux_mic_class_fillinfos); +} + +static int +hwloc_linux_directlookup_mic_class(struct hwloc_backend *backend, + struct hwloc_obj *pcidev) +{ + struct hwloc_linux_backend_data_s *data = backend->private_data; + int root_fd = data->root_fd; + char path[256]; + struct stat st; + hwloc_obj_t obj; + unsigned idx; + int res = 0; + + if (!data->mic_directlookup_id_max) + /* already tried, nothing to do */ + return 0; + + if (data->mic_directlookup_id_max == (unsigned) -1) { + /* never tried, find out the max id */ + DIR *dir; + struct dirent *dirent; + + /* make sure we never do this lookup again */ + data->mic_directlookup_id_max = 0; + + /* read the entire class and find the max id of mic%u dirents */ + dir = hwloc_opendir("/sys/devices/virtual/mic", root_fd); + if (!dir) { + dir = opendir("/sys/class/mic"); + if (!dir) + return 0; + } + while ((dirent = readdir(dir)) != NULL) { + if (!strcmp(dirent->d_name, ".") || !strcmp(dirent->d_name, "..")) + continue; + if (sscanf(dirent->d_name, "mic%u", &idx) != 1) + continue; + if (idx >= data->mic_directlookup_id_max) + data->mic_directlookup_id_max = idx+1; + } + closedir(dir); + } + + /* now iterate over the mic ids and see if one matches our pcidev */ + for(idx=0; idxmic_directlookup_id_max; idx++) { + snprintf(path, sizeof(path), "/sys/class/mic/mic%u/pci_%02x:%02x.%02x", + idx, pcidev->attr->pcidev.bus, pcidev->attr->pcidev.dev, pcidev->attr->pcidev.func); + if (hwloc_stat(path, &st, root_fd) < 0) + continue; + snprintf(path, sizeof(path), "mic%u", idx); + obj = hwloc_linux_add_os_device(backend, pcidev, HWLOC_OBJ_OSDEV_COPROC, path); + snprintf(path, sizeof(path), "/sys/class/mic/mic%u", idx); + hwloc_linux_mic_class_fillinfos(backend, obj, path); + res++; + } + + return res; +} + +/* + * backend callback for inserting objects inside a pci device + */ +static int +hwloc_linux_backend_notify_new_object(struct hwloc_backend *backend, struct hwloc_backend *caller __hwloc_attribute_unused, + struct hwloc_obj *obj) +{ + struct hwloc_linux_backend_data_s *data = backend->private_data; + char pcidevpath[256]; + int res = 0; + + /* this callback is only used in the libpci backend for now */ + assert(obj->type == HWLOC_OBJ_PCI_DEVICE); + + snprintf(pcidevpath, sizeof(pcidevpath), "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/", + obj->attr->pcidev.domain, obj->attr->pcidev.bus, + obj->attr->pcidev.dev, obj->attr->pcidev.func); + + res += hwloc_linux_lookup_net_class(backend, obj, pcidevpath); + res += hwloc_linux_lookup_openfabrics_class(backend, obj, pcidevpath); + res += hwloc_linux_lookup_dma_class(backend, obj, pcidevpath); + res += hwloc_linux_lookup_drm_class(backend, obj, pcidevpath); + res += hwloc_linux_lookup_block_class(backend, obj, pcidevpath); + + if (data->mic_need_directlookup == -1) { + struct stat st; + if (hwloc_stat("/sys/class/mic/mic0", &st, data->root_fd) == 0 + && hwloc_stat("/sys/class/mic/mic0/device/mic/mic0", &st, data->root_fd) == -1) + /* hwloc_linux_lookup_mic_class will fail because pcidev sysfs directories + * do not have mic/mic%u symlinks to mic devices (old mic driver). + * if so, try from the mic class. + */ + data->mic_need_directlookup = 1; + else + data->mic_need_directlookup = 0; + } + if (data->mic_need_directlookup) + res += hwloc_linux_directlookup_mic_class(backend, obj); + else + res += hwloc_linux_lookup_mic_class(backend, obj, pcidevpath); + + return res; +} + +/* + * backend callback for retrieving the location of a pci device + */ +static int +hwloc_linux_backend_get_obj_cpuset(struct hwloc_backend *backend, + struct hwloc_backend *caller __hwloc_attribute_unused, + struct hwloc_obj *obj, hwloc_bitmap_t cpuset) +{ + struct hwloc_linux_backend_data_s *data = backend->private_data; + char path[256]; + FILE *file; + int err; + + /* this callback is only used in the libpci backend for now */ + assert(obj->type == HWLOC_OBJ_PCI_DEVICE + || (obj->type == HWLOC_OBJ_BRIDGE && obj->attr->bridge.upstream_type == HWLOC_OBJ_BRIDGE_PCI)); + + snprintf(path, sizeof(path), "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/local_cpus", + obj->attr->pcidev.domain, obj->attr->pcidev.bus, + obj->attr->pcidev.dev, obj->attr->pcidev.func); + file = hwloc_fopen(path, "r", data->root_fd); + if (file) { + err = hwloc_linux_parse_cpumap_file(file, cpuset); + fclose(file); + if (!err && !hwloc_bitmap_iszero(cpuset)) + return 0; + } + return -1; +} + + + +/******************************* + ******* Linux component ******* + *******************************/ + +static void +hwloc_linux_backend_disable(struct hwloc_backend *backend) +{ + struct hwloc_linux_backend_data_s *data = backend->private_data; +#ifdef HAVE_OPENAT + close(data->root_fd); +#endif +#ifdef HAVE_LIBUDEV_H + if (data->udev) + udev_unref(data->udev); +#endif + free(data); +} + +static struct hwloc_backend * +hwloc_linux_component_instantiate(struct hwloc_disc_component *component, + const void *_data1, + const void *_data2 __hwloc_attribute_unused, + const void *_data3 __hwloc_attribute_unused) +{ + struct hwloc_backend *backend; + struct hwloc_linux_backend_data_s *data; + const char * fsroot_path = _data1; + int flags, root = -1; + + backend = hwloc_backend_alloc(component); + if (!backend) + goto out; + + data = malloc(sizeof(*data)); + if (!data) { + errno = ENOMEM; + goto out_with_backend; + } + + backend->private_data = data; + backend->discover = hwloc_look_linuxfs; + backend->get_obj_cpuset = hwloc_linux_backend_get_obj_cpuset; + backend->notify_new_object = hwloc_linux_backend_notify_new_object; + backend->disable = hwloc_linux_backend_disable; + + /* default values */ + data->is_real_fsroot = 1; + if (!fsroot_path) + fsroot_path = "/"; + +#ifdef HAVE_OPENAT + root = open(fsroot_path, O_RDONLY | O_DIRECTORY); + if (root < 0) + goto out_with_data; + + if (strcmp(fsroot_path, "/")) { + backend->is_thissystem = 0; + data->is_real_fsroot = 0; + } + + /* Since this fd stays open after hwloc returns, mark it as + close-on-exec so that children don't inherit it. Stevens says + that we should GETFD before we SETFD, so we do. */ + flags = fcntl(root, F_GETFD, 0); + if (-1 == flags || + -1 == fcntl(root, F_SETFD, FD_CLOEXEC | flags)) { + close(root); + root = -1; + goto out_with_data; + } +#else + if (strcmp(fsroot_path, "/")) { + errno = ENOSYS; + goto out_with_data; + } +#endif + data->root_fd = root; + +#ifdef HAVE_LIBUDEV_H + data->udev = NULL; + if (data->is_real_fsroot) { + data->udev = udev_new(); + } +#endif + + data->deprecated_classlinks_model = -2; /* never tried */ + data->mic_need_directlookup = -1; /* not initialized */ + data->mic_directlookup_id_max = -1; /* not initialized */ + + return backend; + + out_with_data: + free(data); + out_with_backend: + free(backend); + out: + return NULL; +} + +static struct hwloc_disc_component hwloc_linux_disc_component = { + HWLOC_DISC_COMPONENT_TYPE_CPU, + "linux", + HWLOC_DISC_COMPONENT_TYPE_GLOBAL, + hwloc_linux_component_instantiate, + 50, + NULL +}; + +const struct hwloc_component hwloc_linux_component = { + HWLOC_COMPONENT_ABI, + NULL, NULL, + HWLOC_COMPONENT_TYPE_DISC, + 0, + &hwloc_linux_disc_component +}; + + + + +#ifdef HWLOC_HAVE_LINUXPCI + +/*********************************** + ******* Linux PCI component ******* + ***********************************/ + +#define HWLOC_PCI_REVISION_ID 0x08 +#define HWLOC_PCI_CAP_ID_EXP 0x10 +#define HWLOC_PCI_CLASS_NOT_DEFINED 0x0000 + +static int +hwloc_look_linuxfs_pci(struct hwloc_backend *backend) +{ + struct hwloc_topology *topology = backend->topology; + struct hwloc_backend *tmpbackend; + hwloc_obj_t first_obj = NULL, last_obj = NULL; + int root_fd = -1; + DIR *dir; + struct dirent *dirent; + int res = 0; + + if (!(hwloc_topology_get_flags(topology) & (HWLOC_TOPOLOGY_FLAG_IO_DEVICES|HWLOC_TOPOLOGY_FLAG_WHOLE_IO))) + return 0; + + if (hwloc_get_next_pcidev(topology, NULL)) { + hwloc_debug("%s", "PCI objects already added, ignoring linuxpci backend.\n"); + return 0; + } + + /* hackily find the linux backend to steal its fsroot */ + tmpbackend = topology->backends; + while (tmpbackend) { + if (tmpbackend->component == &hwloc_linux_disc_component) { + root_fd = ((struct hwloc_linux_backend_data_s *) tmpbackend->private_data)->root_fd; + hwloc_debug("linuxpci backend stole linux backend root_fd %d\n", root_fd); + break; } + tmpbackend = tmpbackend->next; + } + /* take our own descriptor, either pointing to linux fsroot, or to / if not found */ + if (root_fd >= 0) + root_fd = dup(root_fd); + else + root_fd = open("/", O_RDONLY | O_DIRECTORY); + + dir = hwloc_opendir("/sys/bus/pci/devices/", root_fd); + if (!dir) + goto out_with_rootfd; + + while ((dirent = readdir(dir)) != NULL) { + unsigned domain, bus, dev, func; + hwloc_obj_t obj; + struct hwloc_pcidev_attr_s *attr; + unsigned os_index; + char path[64]; + char value[16]; + size_t read; + FILE *file; + + if (sscanf(dirent->d_name, "%04x:%02x:%02x.%01x", &domain, &bus, &dev, &func) != 4) + continue; + + os_index = (domain << 20) + (bus << 12) + (dev << 4) + func; + obj = hwloc_alloc_setup_object(HWLOC_OBJ_PCI_DEVICE, os_index); + if (!obj) + break; + attr = &obj->attr->pcidev; + + attr->domain = domain; + attr->bus = bus; + attr->dev = dev; + attr->func = func; + + /* default (unknown) values */ + attr->vendor_id = 0; + attr->device_id = 0; + attr->class_id = HWLOC_PCI_CLASS_NOT_DEFINED; + attr->revision = 0; + attr->subvendor_id = 0; + attr->subdevice_id = 0; + attr->linkspeed = 0; + + snprintf(path, sizeof(path), "/sys/bus/pci/devices/%s/vendor", dirent->d_name); + file = hwloc_fopen(path, "r", root_fd); + if (file) { + read = fread(value, 1, sizeof(value), file); + fclose(file); + if (read) + attr->vendor_id = strtoul(value, NULL, 16); + } + snprintf(path, sizeof(path), "/sys/bus/pci/devices/%s/device", dirent->d_name); + file = hwloc_fopen(path, "r", root_fd); + if (file) { + read = fread(value, 1, sizeof(value), file); + fclose(file); + if (read) + attr->device_id = strtoul(value, NULL, 16); + } + snprintf(path, sizeof(path), "/sys/bus/pci/devices/%s/class", dirent->d_name); + file = hwloc_fopen(path, "r", root_fd); + if (file) { + read = fread(value, 1, sizeof(value), file); + fclose(file); + if (read) + attr->class_id = strtoul(value, NULL, 16) >> 8; + } + snprintf(path, sizeof(path), "/sys/bus/pci/devices/%s/subsystem_vendor", dirent->d_name); + file = hwloc_fopen(path, "r", root_fd); + if (file) { + read = fread(value, 1, sizeof(value), file); + fclose(file); + if (read) + attr->subvendor_id = strtoul(value, NULL, 16); + } + snprintf(path, sizeof(path), "/sys/bus/pci/devices/%s/subsystem_device", dirent->d_name); + file = hwloc_fopen(path, "r", root_fd); + if (file) { + read = fread(value, 1, sizeof(value), file); + fclose(file); + if (read) + attr->subdevice_id = strtoul(value, NULL, 16); + } + + snprintf(path, sizeof(path), "/sys/bus/pci/devices/%s/config", dirent->d_name); + file = hwloc_fopen(path, "r", root_fd); + if (file) { +#define CONFIG_SPACE_CACHESIZE 256 + unsigned char config_space_cache[CONFIG_SPACE_CACHESIZE]; + unsigned offset; + + /* initialize the config space in case we fail to read it (missing permissions, etc). */ + memset(config_space_cache, 0xff, CONFIG_SPACE_CACHESIZE); + read = fread(config_space_cache, 1, CONFIG_SPACE_CACHESIZE, file); + (void) read; /* we initialized config_space_cache in case we don't read enough, ignore the read length */ + fclose(file); + + /* is this a bridge? */ + hwloc_pci_prepare_bridge(obj, config_space_cache); + + /* get the revision */ + attr->revision = config_space_cache[HWLOC_PCI_REVISION_ID]; + + /* try to get the link speed */ + offset = hwloc_pci_find_cap(config_space_cache, HWLOC_PCI_CAP_ID_EXP); + if (offset > 0 && offset + 20 /* size of PCI express block up to link status */ <= CONFIG_SPACE_CACHESIZE) + hwloc_pci_find_linkspeed(config_space_cache, offset, &attr->linkspeed); + } + + if (first_obj) + last_obj->next_sibling = obj; + else + first_obj = obj; + last_obj = obj; + } + + closedir(dir); + + dir = hwloc_opendir("/sys/bus/pci/slots/", root_fd); + if (dir) { + while ((dirent = readdir(dir)) != NULL) { + char path[64]; + FILE *file; + if (dirent->d_name[0] == '.') + continue; + snprintf(path, sizeof(path), "/sys/bus/pci/slots/%s/address", dirent->d_name); + file = hwloc_fopen(path, "r", root_fd); + if (file) { + unsigned domain, bus, dev; + if (fscanf(file, "%x:%x:%x", &domain, &bus, &dev) == 3) { + hwloc_obj_t obj = first_obj; + while (obj) { + if (obj->attr->pcidev.domain == domain + && obj->attr->pcidev.bus == bus + && obj->attr->pcidev.dev == dev + && obj->attr->pcidev.func == 0) { + hwloc_obj_add_info(obj, "PCISlot", dirent->d_name); + break; + } + obj = obj->next_sibling; + } + } + fclose(file); + } + } + closedir(dir); + } + + res = hwloc_insert_pci_device_list(backend, first_obj); + + out_with_rootfd: + close(root_fd); + return res; +} + +static struct hwloc_backend * +hwloc_linuxpci_component_instantiate(struct hwloc_disc_component *component, + const void *_data1 __hwloc_attribute_unused, + const void *_data2 __hwloc_attribute_unused, + const void *_data3 __hwloc_attribute_unused) +{ + struct hwloc_backend *backend; + + /* thissystem may not be fully initialized yet, we'll check flags in discover() */ + + backend = hwloc_backend_alloc(component); + if (!backend) + return NULL; + backend->flags = HWLOC_BACKEND_FLAG_NEED_LEVELS; + backend->discover = hwloc_look_linuxfs_pci; + return backend; +} + +static struct hwloc_disc_component hwloc_linuxpci_disc_component = { + HWLOC_DISC_COMPONENT_TYPE_MISC, + "linuxpci", + HWLOC_DISC_COMPONENT_TYPE_GLOBAL, + hwloc_linuxpci_component_instantiate, + 19, /* after pci */ + NULL +}; + +const struct hwloc_component hwloc_linuxpci_component = { + HWLOC_COMPONENT_ABI, + NULL, NULL, + HWLOC_COMPONENT_TYPE_DISC, + 0, + &hwloc_linuxpci_disc_component +}; + +#endif /* HWLOC_HAVE_LINUXPCI */ diff --git a/opal/mca/hwloc/hwloc1110/hwloc/src/topology-netbsd.c b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-netbsd.c new file mode 100644 index 0000000000..2c5fbaa0c3 --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-netbsd.c @@ -0,0 +1,214 @@ +/* + * Copyright © 2012 Aleksej Saushev, The NetBSD Foundation + * Copyright © 2009-2014 Inria. All rights reserved. + * Copyright © 2009-2010 Université Bordeaux + * Copyright © 2011 Cisco Systems, Inc. All rights reserved. + * See COPYING in top-level directory. + */ + +#define _NETBSD_SOURCE /* request "_np" functions */ + +#include + +#include +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_SYSCTL_H +#include +#endif + +#include +#include +#include + +static void +hwloc_netbsd_bsd2hwloc(hwloc_bitmap_t hwloc_cpuset, const cpuset_t *cpuset) +{ + unsigned cpu, cpulimit; + int found = 0; + hwloc_bitmap_zero(hwloc_cpuset); + cpulimit = cpuset_size(cpuset) * CHAR_BIT; + for (cpu = 0; cpu < cpulimit; cpu++) + if (cpuset_isset(cpu, cpuset)) { + hwloc_bitmap_set(hwloc_cpuset, cpu); + found++; + } + /* when never bound, it returns an empty set, fill it instead */ + if (!found) + hwloc_bitmap_fill(hwloc_cpuset); +} + +static void +hwloc_netbsd_hwloc2bsd(hwloc_const_bitmap_t hwloc_cpuset, cpuset_t *cpuset) +{ + unsigned cpu, cpulimit; + cpuset_zero(cpuset); + cpulimit = cpuset_size(cpuset) * CHAR_BIT; + for (cpu = 0; cpu < cpulimit; cpu++) + if (hwloc_bitmap_isset(hwloc_cpuset, cpu)) + cpuset_set(cpu, cpuset); +} + +static int +hwloc_netbsd_set_proc_cpubind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_pid_t pid, hwloc_const_bitmap_t hwloc_cpuset, int flags __hwloc_attribute_unused) +{ + int status; + cpuset_t *cpuset = cpuset_create(); + hwloc_netbsd_hwloc2bsd(hwloc_cpuset, cpuset); + status = sched_setaffinity_np(pid, cpuset_size(cpuset), cpuset); + cpuset_destroy(cpuset); + return status; +} + +static int +hwloc_netbsd_get_proc_cpubind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_pid_t pid, hwloc_bitmap_t hwloc_cpuset, int flags __hwloc_attribute_unused) +{ + int status; + cpuset_t *cpuset = cpuset_create(); + status = sched_getaffinity_np(pid, cpuset_size(cpuset), cpuset); + hwloc_netbsd_bsd2hwloc(hwloc_cpuset, cpuset); + cpuset_destroy(cpuset); + return status; +} + + +static int +hwloc_netbsd_set_thisproc_cpubind(hwloc_topology_t topology, hwloc_const_bitmap_t hwloc_cpuset, int flags) +{ + return hwloc_netbsd_set_proc_cpubind(topology, 0, hwloc_cpuset, flags); +} + +static int +hwloc_netbsd_get_thisproc_cpubind(hwloc_topology_t topology, hwloc_bitmap_t hwloc_cpuset, int flags) +{ + return hwloc_netbsd_get_proc_cpubind(topology, 0, hwloc_cpuset, flags); +} + + +static int +hwloc_netbsd_set_thread_cpubind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_thread_t tid, hwloc_const_bitmap_t hwloc_cpuset, int flags __hwloc_attribute_unused) +{ + int status; + cpuset_t *cpuset = cpuset_create(); + hwloc_netbsd_hwloc2bsd(hwloc_cpuset, cpuset); + status = pthread_setaffinity_np(tid, cpuset_size(cpuset), cpuset); + cpuset_destroy(cpuset); + + if (status) { + errno = status; + return -1; + } + return 0; +} + +static int +hwloc_netbsd_get_thread_cpubind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_thread_t tid, hwloc_bitmap_t hwloc_cpuset, int flags __hwloc_attribute_unused) +{ + int status; + cpuset_t *cpuset = cpuset_create(); + status = pthread_getaffinity_np(tid, cpuset_size(cpuset), cpuset); + hwloc_netbsd_bsd2hwloc(hwloc_cpuset, cpuset); + cpuset_destroy(cpuset); + + if (status) { + errno = status; + return -1; + } + return 0; +} + + +static int +hwloc_netbsd_set_thisthread_cpubind(hwloc_topology_t topology, hwloc_const_bitmap_t hwloc_cpuset, int flags) +{ + return hwloc_netbsd_set_thread_cpubind(topology, pthread_self(), hwloc_cpuset, flags); +} + +static int +hwloc_netbsd_get_thisthread_cpubind(hwloc_topology_t topology, hwloc_bitmap_t hwloc_cpuset, int flags) +{ + return hwloc_netbsd_get_thread_cpubind(topology, pthread_self(), hwloc_cpuset, flags); +} + +#if (defined HAVE_SYSCTL) && (defined HAVE_SYS_SYSCTL_H) +static void +hwloc_netbsd_node_meminfo_info(struct hwloc_topology *topology) +{ + int mib[2] = { CTL_HW, HW_PHYSMEM64 }; + unsigned long physmem; + size_t len = sizeof(physmem); + sysctl(mib, 2, &physmem, &len, NULL, 0); + topology->levels[0][0]->memory.local_memory = physmem; +} +#endif + +static int +hwloc_look_netbsd(struct hwloc_backend *backend) +{ + struct hwloc_topology *topology = backend->topology; + unsigned nbprocs = hwloc_fallback_nbprocessors(topology); + + if (!topology->levels[0][0]->cpuset) { + /* Nobody (even the x86 backend) created objects yet, setup basic objects */ + hwloc_alloc_obj_cpusets(topology->levels[0][0]); + hwloc_setup_pu_level(topology, nbprocs); + } + + /* Add NetBSD specific information */ +#if (defined HAVE_SYSCTL) && (defined HAVE_SYS_SYSCTL_H) + hwloc_netbsd_node_meminfo_info(topology); +#endif + hwloc_obj_add_info(topology->levels[0][0], "Backend", "NetBSD"); + if (topology->is_thissystem) + hwloc_add_uname_info(topology, NULL); + return 1; +} + +void +hwloc_set_netbsd_hooks(struct hwloc_binding_hooks *hooks __hwloc_attribute_unused, + struct hwloc_topology_support *support __hwloc_attribute_unused) +{ + hooks->set_proc_cpubind = hwloc_netbsd_set_proc_cpubind; + hooks->get_proc_cpubind = hwloc_netbsd_get_proc_cpubind; + hooks->set_thisproc_cpubind = hwloc_netbsd_set_thisproc_cpubind; + hooks->get_thisproc_cpubind = hwloc_netbsd_get_thisproc_cpubind; + + hooks->set_thread_cpubind = hwloc_netbsd_set_thread_cpubind; + hooks->get_thread_cpubind = hwloc_netbsd_get_thread_cpubind; + hooks->set_thisthread_cpubind = hwloc_netbsd_set_thisthread_cpubind; + hooks->get_thisthread_cpubind = hwloc_netbsd_get_thisthread_cpubind; +} + +static struct hwloc_backend * +hwloc_netbsd_component_instantiate(struct hwloc_disc_component *component, + const void *_data1 __hwloc_attribute_unused, + const void *_data2 __hwloc_attribute_unused, + const void *_data3 __hwloc_attribute_unused) +{ + struct hwloc_backend *backend; + backend = hwloc_backend_alloc(component); + if (!backend) + return NULL; + backend->discover = hwloc_look_netbsd; + return backend; +} + +static struct hwloc_disc_component hwloc_netbsd_disc_component = { + HWLOC_DISC_COMPONENT_TYPE_CPU, + "netbsd", + HWLOC_DISC_COMPONENT_TYPE_GLOBAL, + hwloc_netbsd_component_instantiate, + 50, + NULL +}; + +const struct hwloc_component hwloc_netbsd_component = { + HWLOC_COMPONENT_ABI, + NULL, NULL, + HWLOC_COMPONENT_TYPE_DISC, + 0, + &hwloc_netbsd_disc_component +}; diff --git a/opal/mca/hwloc/hwloc1110/hwloc/src/topology-noos.c b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-noos.c new file mode 100644 index 0000000000..a926428e96 --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-noos.c @@ -0,0 +1,58 @@ +/* + * Copyright © 2009 CNRS + * Copyright © 2009-2014 Inria. All rights reserved. + * Copyright © 2009-2012 Université Bordeaux + * Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved. + * See COPYING in top-level directory. + */ + +#include +#include +#include + +static int +hwloc_look_noos(struct hwloc_backend *backend) +{ + struct hwloc_topology *topology = backend->topology; + + if (topology->levels[0][0]->cpuset) + /* somebody discovered things */ + return 0; + + hwloc_alloc_obj_cpusets(topology->levels[0][0]); + hwloc_setup_pu_level(topology, hwloc_fallback_nbprocessors(topology)); + if (topology->is_thissystem) + hwloc_add_uname_info(topology, NULL); + return 1; +} + +static struct hwloc_backend * +hwloc_noos_component_instantiate(struct hwloc_disc_component *component, + const void *_data1 __hwloc_attribute_unused, + const void *_data2 __hwloc_attribute_unused, + const void *_data3 __hwloc_attribute_unused) +{ + struct hwloc_backend *backend; + backend = hwloc_backend_alloc(component); + if (!backend) + return NULL; + backend->discover = hwloc_look_noos; + return backend; +} + +static struct hwloc_disc_component hwloc_noos_disc_component = { + HWLOC_DISC_COMPONENT_TYPE_CPU, + "no_os", + HWLOC_DISC_COMPONENT_TYPE_GLOBAL, + hwloc_noos_component_instantiate, + 40, /* lower than native OS component, higher than globals */ + NULL +}; + +const struct hwloc_component hwloc_noos_component = { + HWLOC_COMPONENT_ABI, + NULL, NULL, + HWLOC_COMPONENT_TYPE_DISC, + 0, + &hwloc_noos_disc_component +}; diff --git a/opal/mca/hwloc/hwloc1110/hwloc/src/topology-nvml.c b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-nvml.c new file mode 100644 index 0000000000..9c36d0a40b --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-nvml.c @@ -0,0 +1,239 @@ +/* + * Copyright © 2012-2014 Inria. All rights reserved. + * See COPYING in top-level directory. + */ + +#include +#include +#include + +/* private headers allowed for convenience because this plugin is built within hwloc */ +#include +#include + +#include + +struct hwloc_nvml_backend_data_s { + unsigned nr_devices; /* -1 when unknown yet, first callback will setup */ + struct hwloc_nvml_device_info_s { + char name[64]; + char serial[64]; + char uuid[64]; + unsigned pcidomain, pcibus, pcidev, pcifunc; + float maxlinkspeed; + } * devices; +}; + +static void +hwloc_nvml_query_devices(struct hwloc_nvml_backend_data_s *data) +{ + nvmlReturn_t ret; + unsigned nb, i; + + /* mark the number of devices as 0 in case we fail below, + * so that we don't try again later. + */ + data->nr_devices = 0; + + ret = nvmlInit(); + if (NVML_SUCCESS != ret) + goto out; + ret = nvmlDeviceGetCount(&nb); + if (NVML_SUCCESS != ret) + goto out_with_init; + + /* allocate structs */ + data->devices = malloc(nb * sizeof(*data->devices)); + if (!data->devices) + goto out_with_init; + + for(i=0; idevices[data->nr_devices]; + nvmlPciInfo_t pci; + nvmlDevice_t device; + + ret = nvmlDeviceGetHandleByIndex(i, &device); + assert(ret == NVML_SUCCESS); + + ret = nvmlDeviceGetPciInfo(device, &pci); + if (NVML_SUCCESS != ret) + continue; + + info->pcidomain = pci.domain; + info->pcibus = pci.bus; + info->pcidev = pci.device; + info->pcifunc = 0; + + info->name[0] = '\0'; + ret = nvmlDeviceGetName(device, info->name, sizeof(info->name)); + /* these may fail with NVML_ERROR_NOT_SUPPORTED on old devices */ + info->serial[0] = '\0'; + ret = nvmlDeviceGetSerial(device, info->serial, sizeof(info->serial)); + info->uuid[0] = '\0'; + ret = nvmlDeviceGetUUID(device, info->uuid, sizeof(info->uuid)); + + info->maxlinkspeed = 0.0f; +#if HAVE_DECL_NVMLDEVICEGETMAXPCIELINKGENERATION + { + unsigned maxwidth = 0, maxgen = 0; + float lanespeed; + nvmlDeviceGetMaxPcieLinkWidth(device, &maxwidth); + nvmlDeviceGetMaxPcieLinkGeneration(device, &maxgen); + /* PCIe Gen1 = 2.5GT/s signal-rate per lane with 8/10 encoding = 0.25GB/s data-rate per lane + * PCIe Gen2 = 5 GT/s signal-rate per lane with 8/10 encoding = 0.5 GB/s data-rate per lane + * PCIe Gen3 = 8 GT/s signal-rate per lane with 128/130 encoding = 1 GB/s data-rate per lane + */ + lanespeed = maxgen <= 2 ? 2.5 * maxgen * 0.8 : 8.0 * 128/130; /* Gbit/s per lane */ + info->maxlinkspeed = lanespeed * maxwidth / 8; /* GB/s */ + } +#endif + + /* validate this device */ + data->nr_devices++; + } + +out_with_init: + nvmlShutdown(); +out: + return; +} + +static int +hwloc_nvml_backend_notify_new_object(struct hwloc_backend *backend, struct hwloc_backend *caller __hwloc_attribute_unused, + struct hwloc_obj *pcidev) +{ + struct hwloc_topology *topology = backend->topology; + struct hwloc_nvml_backend_data_s *data = backend->private_data; + unsigned i; + + if (!(hwloc_topology_get_flags(topology) & (HWLOC_TOPOLOGY_FLAG_IO_DEVICES|HWLOC_TOPOLOGY_FLAG_WHOLE_IO))) + return 0; + + if (!hwloc_topology_is_thissystem(topology)) { + hwloc_debug("%s", "\nno NVML detection (not thissystem)\n"); + return 0; + } + + if (HWLOC_OBJ_PCI_DEVICE != pcidev->type) + return 0; + + if (data->nr_devices == (unsigned) -1) { + /* first call, lookup all devices */ + hwloc_nvml_query_devices(data); + /* if it fails, data->nr_devices = 0 so we won't do anything below and in next callbacks */ + } + + if (!data->nr_devices) + /* found no devices */ + return 0; + + /* now the devices array is ready to use */ + for(i=0; inr_devices; i++) { + struct hwloc_nvml_device_info_s *info = &data->devices[i]; + hwloc_obj_t osdev; + char buffer[64]; + + if (info->pcidomain != pcidev->attr->pcidev.domain) + continue; + if (info->pcibus != pcidev->attr->pcidev.bus) + continue; + if (info->pcidev != pcidev->attr->pcidev.dev) + continue; + if (info->pcifunc != pcidev->attr->pcidev.func) + continue; + + osdev = hwloc_alloc_setup_object(HWLOC_OBJ_OS_DEVICE, -1); + snprintf(buffer, sizeof(buffer), "nvml%d", i); + osdev->name = strdup(buffer); + osdev->depth = (unsigned) HWLOC_TYPE_DEPTH_UNKNOWN; + osdev->attr->osdev.type = HWLOC_OBJ_OSDEV_GPU; + + hwloc_obj_add_info(osdev, "Backend", "NVML"); + hwloc_obj_add_info(osdev, "GPUVendor", "NVIDIA Corporation"); + hwloc_obj_add_info(osdev, "GPUModel", info->name); + if (info->serial[0] != '\0') + hwloc_obj_add_info(osdev, "NVIDIASerial", info->serial); + if (info->uuid[0] != '\0') + hwloc_obj_add_info(osdev, "NVIDIAUUID", info->uuid); + + hwloc_insert_object_by_parent(topology, pcidev, osdev); + + if (info->maxlinkspeed != 0.0f) + /* we found the max link speed, replace the current link speed found by pci (or none) */ + pcidev->attr->pcidev.linkspeed = info->maxlinkspeed; + + return 1; + } + + return 0; +} + +static void +hwloc_nvml_backend_disable(struct hwloc_backend *backend) +{ + struct hwloc_nvml_backend_data_s *data = backend->private_data; + free(data->devices); + free(data); +} + +static struct hwloc_backend * +hwloc_nvml_component_instantiate(struct hwloc_disc_component *component, + const void *_data1 __hwloc_attribute_unused, + const void *_data2 __hwloc_attribute_unused, + const void *_data3 __hwloc_attribute_unused) +{ + struct hwloc_backend *backend; + struct hwloc_nvml_backend_data_s *data; + + /* thissystem may not be fully initialized yet, we'll check flags in discover() */ + + backend = hwloc_backend_alloc(component); + if (!backend) + return NULL; + + data = malloc(sizeof(*data)); + if (!data) { + free(backend); + return NULL; + } + /* the first callback will initialize those */ + data->nr_devices = (unsigned) -1; /* unknown yet */ + data->devices = NULL; + + backend->private_data = data; + backend->disable = hwloc_nvml_backend_disable; + + backend->notify_new_object = hwloc_nvml_backend_notify_new_object; + return backend; +} + +static struct hwloc_disc_component hwloc_nvml_disc_component = { + HWLOC_DISC_COMPONENT_TYPE_MISC, + "nvml", + HWLOC_DISC_COMPONENT_TYPE_GLOBAL, + hwloc_nvml_component_instantiate, + 5, /* after pci, and after cuda since likely less useful */ + NULL +}; + +static int +hwloc_nvml_component_init(unsigned long flags) +{ + if (flags) + return -1; + if (hwloc_plugin_check_namespace("nvml", "hwloc_backend_alloc") < 0) + return -1; + return 0; +} + +#ifdef HWLOC_INSIDE_PLUGIN +HWLOC_DECLSPEC extern const struct hwloc_component hwloc_nvml_component; +#endif + +const struct hwloc_component hwloc_nvml_component = { + HWLOC_COMPONENT_ABI, + hwloc_nvml_component_init, NULL, + HWLOC_COMPONENT_TYPE_DISC, + 0, + &hwloc_nvml_disc_component +}; diff --git a/opal/mca/hwloc/hwloc1110/hwloc/src/topology-opencl.c b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-opencl.c new file mode 100644 index 0000000000..85057c7c15 --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-opencl.c @@ -0,0 +1,346 @@ +/* + * Copyright © 2012-2014 Inria. All rights reserved. + * Copyright © 2013 Université Bordeaux. All right reserved. + * See COPYING in top-level directory. + */ + +#include +#include +#include + +/* private headers allowed for convenience because this plugin is built within hwloc */ +#include +#include + +#include + +typedef enum hwloc_opencl_device_type_e { + HWLOC_OPENCL_DEVICE_AMD +} hwloc_opencl_device_type_t; + +struct hwloc_opencl_backend_data_s { + unsigned nr_devices; /* -1 when unknown yet, first callback will setup */ + struct hwloc_opencl_device_info_s { + hwloc_opencl_device_type_t type; + + unsigned platformidx; + char platformname[64]; + unsigned platformdeviceidx; + char devicename[64]; + char devicevendor[64]; + char devicetype[64]; + + unsigned computeunits; + unsigned long long globalmemsize; + + union hwloc_opencl_device_info_u { + struct hwloc_opencl_device_info_amd_s { + unsigned pcidomain, pcibus, pcidev, pcifunc; + } amd; + } specific; + } * devices; +}; + +static void +hwloc_opencl_query_devices(struct hwloc_opencl_backend_data_s *data) +{ + cl_platform_id *platform_ids = NULL; + cl_uint nr_platforms; + cl_device_id *device_ids = NULL; + cl_uint nr_devices, nr_total_devices, tmp; + cl_int clret; + unsigned curpfidx, curpfdvidx, i; + + /* mark the number of devices as 0 in case we fail below, + * so that we don't try again later. + */ + data->nr_devices = 0; + + /* count platforms, allocate and get them */ + clret = clGetPlatformIDs(0, NULL, &nr_platforms); + if (CL_SUCCESS != clret || !nr_platforms) + goto out; + hwloc_debug("%u OpenCL platforms\n", nr_platforms); + platform_ids = malloc(nr_platforms * sizeof(*platform_ids)); + if (!platform_ids) + goto out; + clret = clGetPlatformIDs(nr_platforms, platform_ids, &nr_platforms); + if (CL_SUCCESS != clret || !nr_platforms) + goto out_with_platform_ids; + + /* how many devices, total? */ + tmp = 0; + for(i=0; idevices = malloc(nr_total_devices * sizeof(*data->devices)); + if (!data->devices || !device_ids) + goto out_with_device_ids; + /* actually query device ids */ + tmp = 0; + for(i=0; idevices[data->nr_devices]; + cl_platform_id platform_id = 0; + cl_device_type type; +#ifdef CL_DEVICE_TOPOLOGY_AMD + cl_device_topology_amd amdtopo; +#endif + cl_ulong globalmemsize; + cl_uint computeunits; + + hwloc_debug("Looking device %p\n", device_ids[i]); + + info->platformname[0] = '\0'; + clret = clGetDeviceInfo(device_ids[i], CL_DEVICE_PLATFORM, sizeof(platform_id), &platform_id, NULL); + if (CL_SUCCESS != clret) + continue; + clGetPlatformInfo(platform_id, CL_PLATFORM_NAME, sizeof(info->platformname), info->platformname, NULL); + + info->devicename[0] = '\0'; +#ifdef CL_DEVICE_BOARD_NAME_AMD + clGetDeviceInfo(device_ids[i], CL_DEVICE_BOARD_NAME_AMD, sizeof(info->devicename), info->devicename, NULL); +#else + clGetDeviceInfo(device_ids[i], CL_DEVICE_NAME, sizeof(info->devicename), info->devicename, NULL); +#endif + info->devicevendor[0] = '\0'; + clGetDeviceInfo(device_ids[i], CL_DEVICE_VENDOR, sizeof(info->devicevendor), info->devicevendor, NULL); + + clGetDeviceInfo(device_ids[i], CL_DEVICE_TYPE, sizeof(type), &type, NULL); + switch (type) { + case CL_DEVICE_TYPE_CPU: /* FIXME: cannot happen in PCI devices? */ + strcpy(info->devicetype, "CPU"); + break; + case CL_DEVICE_TYPE_GPU: + strcpy(info->devicetype, "GPU"); + break; + case CL_DEVICE_TYPE_ACCELERATOR: + strcpy(info->devicetype, "Accelerator"); + break; + default: + strcpy(info->devicetype, "Unknown"); + break; + } + + clGetDeviceInfo(device_ids[i], CL_DEVICE_GLOBAL_MEM_SIZE, sizeof(globalmemsize), &globalmemsize, NULL); + info->globalmemsize = globalmemsize / 1024; + + clGetDeviceInfo(device_ids[i], CL_DEVICE_MAX_COMPUTE_UNITS, sizeof(computeunits), &computeunits, NULL); + info->computeunits = computeunits; + + hwloc_debug("platform %s device %s vendor %s type %s\n", info->platformname, info->devicename, info->devicevendor, info->devicetype); + + /* find our indexes */ + while (platform_id != platform_ids[curpfidx]) { + curpfidx++; + curpfdvidx = 0; + } + info->platformidx = curpfidx; + info->platformdeviceidx = curpfdvidx; + curpfdvidx++; + + hwloc_debug("This is opencl%dd%d\n", info->platformidx, info->platformdeviceidx); + +#ifdef CL_DEVICE_TOPOLOGY_AMD + clret = clGetDeviceInfo(device_ids[i], CL_DEVICE_TOPOLOGY_AMD, sizeof(amdtopo), &amdtopo, NULL); + if (CL_SUCCESS != clret) { + hwloc_debug("no AMD-specific device information: %d\n", clret); + continue; + } + if (CL_DEVICE_TOPOLOGY_TYPE_PCIE_AMD != amdtopo.raw.type) { + hwloc_debug("not a PCIe device: %u\n", amdtopo.raw.type); + continue; + } + + info->type = HWLOC_OPENCL_DEVICE_AMD; + info->specific.amd.pcidomain = 0; + info->specific.amd.pcibus = amdtopo.pcie.bus; + info->specific.amd.pcidev = amdtopo.pcie.device; + info->specific.amd.pcifunc = amdtopo.pcie.function; + + hwloc_debug("OpenCL device on PCI 0000:%02x:%02x.%u\n", amdtopo.pcie.bus, amdtopo.pcie.device, amdtopo.pcie.function); + + /* validate this device */ + data->nr_devices++; +#endif /* HAVE_DECL_CL_DEVICE_TOPOLOGY_AMD */ + } + free(device_ids); + free(platform_ids); + return; + +out_with_device_ids: + free(device_ids); + free(data->devices); + data->devices = NULL; +out_with_platform_ids: + free(platform_ids); +out: + return; +} + +static int +hwloc_opencl_backend_notify_new_object(struct hwloc_backend *backend, struct hwloc_backend *caller __hwloc_attribute_unused, + struct hwloc_obj *pcidev) +{ + struct hwloc_topology *topology = backend->topology; + struct hwloc_opencl_backend_data_s *data = backend->private_data; + unsigned i; + + if (!(hwloc_topology_get_flags(topology) & (HWLOC_TOPOLOGY_FLAG_IO_DEVICES|HWLOC_TOPOLOGY_FLAG_WHOLE_IO))) + return 0; + + if (!hwloc_topology_is_thissystem(topology)) { + hwloc_debug("%s", "\nno OpenCL detection (not thissystem)\n"); + return 0; + } + + if (HWLOC_OBJ_PCI_DEVICE != pcidev->type) + return 0; + + if (data->nr_devices == (unsigned) -1) { + /* first call, lookup all devices */ + hwloc_opencl_query_devices(data); + /* if it fails, data->nr_devices = 0 so we won't do anything below and in next callbacks */ + } + + if (!data->nr_devices) + /* found no devices */ + return 0; + + /* now the devices array is ready to use */ + for(i=0; inr_devices; i++) { + struct hwloc_opencl_device_info_s *info = &data->devices[i]; + hwloc_obj_t osdev; + char buffer[64]; + + assert(info->type == HWLOC_OPENCL_DEVICE_AMD); + if (info->specific.amd.pcidomain != pcidev->attr->pcidev.domain) + continue; + if (info->specific.amd.pcibus != pcidev->attr->pcidev.bus) + continue; + if (info->specific.amd.pcidev != pcidev->attr->pcidev.dev) + continue; + if (info->specific.amd.pcifunc != pcidev->attr->pcidev.func) + continue; + + osdev = hwloc_alloc_setup_object(HWLOC_OBJ_OS_DEVICE, -1); + snprintf(buffer, sizeof(buffer), "opencl%dd%d", info->platformidx, info->platformdeviceidx); + osdev->name = strdup(buffer); + osdev->depth = (unsigned) HWLOC_TYPE_DEPTH_UNKNOWN; + osdev->attr->osdev.type = HWLOC_OBJ_OSDEV_COPROC; + + hwloc_obj_add_info(osdev, "CoProcType", "OpenCL"); + hwloc_obj_add_info(osdev, "Backend", "OpenCL"); + hwloc_obj_add_info(osdev, "OpenCLDeviceType", info->devicetype); + + if (info->devicevendor[0] != '\0') + hwloc_obj_add_info(osdev, "GPUVendor", info->devicevendor); + if (info->devicename[0] != '\0') + hwloc_obj_add_info(osdev, "GPUModel", info->devicename); + + snprintf(buffer, sizeof(buffer), "%u", info->platformidx); + hwloc_obj_add_info(osdev, "OpenCLPlatformIndex", buffer); + if (info->platformname[0] != '\0') + hwloc_obj_add_info(osdev, "OpenCLPlatformName", info->platformname); + + snprintf(buffer, sizeof(buffer), "%u", info->platformdeviceidx); + hwloc_obj_add_info(osdev, "OpenCLPlatformDeviceIndex", buffer); + + snprintf(buffer, sizeof(buffer), "%u", info->computeunits); + hwloc_obj_add_info(osdev, "OpenCLComputeUnits", buffer); + + snprintf(buffer, sizeof(buffer), "%llu", info->globalmemsize); + hwloc_obj_add_info(osdev, "OpenCLGlobalMemorySize", buffer); + + hwloc_insert_object_by_parent(topology, pcidev, osdev); + return 1; + } + + return 0; +} + +static void +hwloc_opencl_backend_disable(struct hwloc_backend *backend) +{ + struct hwloc_opencl_backend_data_s *data = backend->private_data; + free(data->devices); + free(data); +} + +static struct hwloc_backend * +hwloc_opencl_component_instantiate(struct hwloc_disc_component *component, + const void *_data1 __hwloc_attribute_unused, + const void *_data2 __hwloc_attribute_unused, + const void *_data3 __hwloc_attribute_unused) +{ + struct hwloc_backend *backend; + struct hwloc_opencl_backend_data_s *data; + + /* thissystem may not be fully initialized yet, we'll check flags in discover() */ + + backend = hwloc_backend_alloc(component); + if (!backend) + return NULL; + + data = malloc(sizeof(*data)); + if (!data) { + free(backend); + return NULL; + } + /* the first callback will initialize those */ + data->nr_devices = (unsigned) -1; /* unknown yet */ + data->devices = NULL; + + backend->private_data = data; + backend->disable = hwloc_opencl_backend_disable; + + backend->notify_new_object = hwloc_opencl_backend_notify_new_object; + return backend; +} + +static struct hwloc_disc_component hwloc_opencl_disc_component = { + HWLOC_DISC_COMPONENT_TYPE_MISC, + "opencl", + HWLOC_DISC_COMPONENT_TYPE_GLOBAL, + hwloc_opencl_component_instantiate, + 10, /* after pci */ + NULL +}; + +static int +hwloc_opencl_component_init(unsigned long flags) +{ + if (flags) + return -1; + if (hwloc_plugin_check_namespace("opencl", "hwloc_backend_alloc") < 0) + return -1; + return 0; +} + +#ifdef HWLOC_INSIDE_PLUGIN +HWLOC_DECLSPEC extern const struct hwloc_component hwloc_opencl_component; +#endif + +const struct hwloc_component hwloc_opencl_component = { + HWLOC_COMPONENT_ABI, + hwloc_opencl_component_init, NULL, + HWLOC_COMPONENT_TYPE_DISC, + 0, + &hwloc_opencl_disc_component +}; diff --git a/opal/mca/hwloc/hwloc1110/hwloc/src/topology-osf.c b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-osf.c new file mode 100644 index 0000000000..57158883d6 --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-osf.c @@ -0,0 +1,392 @@ +/* + * Copyright © 2009 CNRS + * Copyright © 2009-2014 Inria. All rights reserved. + * Copyright © 2009-2011 Université Bordeaux + * Copyright © 2011 Cisco Systems, Inc. All rights reserved. + * See COPYING in top-level directory. + */ + +#include + +#include +#ifdef HAVE_DIRENT_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +/* + * TODO + * + * nsg_init(), nsg_attach_pid(), RAD_MIGRATE/RAD_WAIT + * assign_pid_to_pset() + * + * pthread_use_only_cpu too? + */ + +static int +prepare_radset(hwloc_topology_t topology __hwloc_attribute_unused, radset_t *radset, hwloc_const_bitmap_t hwloc_set) +{ + unsigned cpu; + cpuset_t target_cpuset; + cpuset_t cpuset, xor_cpuset; + radid_t radid; + int ret = 0; + int ret_errno = 0; + int nbnodes = rad_get_num(); + + cpusetcreate(&target_cpuset); + cpuemptyset(target_cpuset); + hwloc_bitmap_foreach_begin(cpu, hwloc_set) + cpuaddset(target_cpuset, cpu); + hwloc_bitmap_foreach_end(); + + cpusetcreate(&cpuset); + cpusetcreate(&xor_cpuset); + for (radid = 0; radid < nbnodes; radid++) { + cpuemptyset(cpuset); + if (rad_get_cpus(radid, cpuset)==-1) { + fprintf(stderr,"rad_get_cpus(%d) failed: %s\n",radid,strerror(errno)); + continue; + } + cpuxorset(target_cpuset, cpuset, xor_cpuset); + if (cpucountset(xor_cpuset) == 0) { + /* Found it */ + radsetcreate(radset); + rademptyset(*radset); + radaddset(*radset, radid); + ret = 1; + goto out; + } + } + /* radset containing exactly this set of CPUs not found */ + ret_errno = EXDEV; + +out: + cpusetdestroy(&target_cpuset); + cpusetdestroy(&cpuset); + cpusetdestroy(&xor_cpuset); + errno = ret_errno; + return ret; +} + +/* Note: get_cpubind not available on OSF */ + +static int +hwloc_osf_set_thread_cpubind(hwloc_topology_t topology, hwloc_thread_t thread, hwloc_const_bitmap_t hwloc_set, int flags) +{ + radset_t radset; + + if (hwloc_bitmap_isequal(hwloc_set, hwloc_topology_get_complete_cpuset(topology))) { + if ((errno = pthread_rad_detach(thread))) + return -1; + return 0; + } + + /* Apparently OSF migrates pages */ + if (flags & HWLOC_CPUBIND_NOMEMBIND) { + errno = ENOSYS; + return -1; + } + + if (!prepare_radset(topology, &radset, hwloc_set)) + return -1; + + if (flags & HWLOC_CPUBIND_STRICT) { + if ((errno = pthread_rad_bind(thread, radset, RAD_INSIST | RAD_WAIT))) + return -1; + } else { + if ((errno = pthread_rad_attach(thread, radset, RAD_WAIT))) + return -1; + } + radsetdestroy(&radset); + + return 0; +} + +static int +hwloc_osf_set_proc_cpubind(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_const_bitmap_t hwloc_set, int flags) +{ + radset_t radset; + + if (hwloc_bitmap_isequal(hwloc_set, hwloc_topology_get_complete_cpuset(topology))) { + if (rad_detach_pid(pid)) + return -1; + return 0; + } + + /* Apparently OSF migrates pages */ + if (flags & HWLOC_CPUBIND_NOMEMBIND) { + errno = ENOSYS; + return -1; + } + + if (!prepare_radset(topology, &radset, hwloc_set)) + return -1; + + if (flags & HWLOC_CPUBIND_STRICT) { + if (rad_bind_pid(pid, radset, RAD_INSIST | RAD_WAIT)) + return -1; + } else { + if (rad_attach_pid(pid, radset, RAD_WAIT)) + return -1; + } + radsetdestroy(&radset); + + return 0; +} + +static int +hwloc_osf_set_thisthread_cpubind(hwloc_topology_t topology, hwloc_const_bitmap_t hwloc_set, int flags) +{ + return hwloc_osf_set_thread_cpubind(topology, pthread_self(), hwloc_set, flags); +} + +static int +hwloc_osf_set_thisproc_cpubind(hwloc_topology_t topology, hwloc_const_bitmap_t hwloc_set, int flags) +{ + return hwloc_osf_set_proc_cpubind(topology, getpid(), hwloc_set, flags); +} + +static int +hwloc_osf_prepare_mattr(hwloc_topology_t topology __hwloc_attribute_unused, memalloc_attr_t *mattr, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags __hwloc_attribute_unused) +{ + unsigned long osf_policy; + int node; + + switch (policy) { + case HWLOC_MEMBIND_FIRSTTOUCH: + osf_policy = MPOL_THREAD; + break; + case HWLOC_MEMBIND_DEFAULT: + case HWLOC_MEMBIND_BIND: + osf_policy = MPOL_DIRECTED; + break; + case HWLOC_MEMBIND_INTERLEAVE: + osf_policy = MPOL_STRIPPED; + break; + case HWLOC_MEMBIND_REPLICATE: + osf_policy = MPOL_REPLICATED; + break; + default: + errno = ENOSYS; + return -1; + } + + memset(mattr, 0, sizeof(*mattr)); + mattr->mattr_policy = osf_policy; + mattr->mattr_rad = RAD_NONE; + radsetcreate(&mattr->mattr_radset); + rademptyset(mattr->mattr_radset); + + hwloc_bitmap_foreach_begin(node, nodeset) + radaddset(mattr->mattr_radset, node); + hwloc_bitmap_foreach_end(); + return 0; +} + +static int +hwloc_osf_set_area_membind(hwloc_topology_t topology, const void *addr, size_t len, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags) +{ + memalloc_attr_t mattr; + int behavior = 0; + int ret; + + if (flags & HWLOC_MEMBIND_MIGRATE) + behavior |= MADV_CURRENT; + if (flags & HWLOC_MEMBIND_STRICT) + behavior |= MADV_INSIST; + + if (hwloc_osf_prepare_mattr(topology, &mattr, nodeset, policy, flags)) + return -1; + + ret = nmadvise(addr, len, MADV_CURRENT, &mattr); + radsetdestroy(&mattr.mattr_radset); + return ret; +} + +static void * +hwloc_osf_alloc_membind(hwloc_topology_t topology, size_t len, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags) +{ + memalloc_attr_t mattr; + void *ptr; + + if (hwloc_osf_prepare_mattr(topology, &mattr, nodeset, policy, flags)) + return hwloc_alloc_or_fail(topology, len, flags); + + /* TODO: rather use acreate/amalloc ? */ + ptr = nmmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, + 0, &mattr); + radsetdestroy(&mattr.mattr_radset); + return ptr; +} + +static int +hwloc_look_osf(struct hwloc_backend *backend) +{ + struct hwloc_topology *topology = backend->topology; + cpu_cursor_t cursor; + unsigned nbnodes; + radid_t radid, radid2; + radset_t radset, radset2; + cpuid_t cpuid; + cpuset_t cpuset; + struct hwloc_obj *obj; + unsigned distance; + + if (topology->levels[0][0]->cpuset) + /* somebody discovered things */ + return 0; + + hwloc_alloc_obj_cpusets(topology->levels[0][0]); + + nbnodes = rad_get_num(); + + cpusetcreate(&cpuset); + radsetcreate(&radset); + radsetcreate(&radset2); + { + hwloc_obj_t *nodes = calloc(nbnodes, sizeof(hwloc_obj_t)); + unsigned *indexes = calloc(nbnodes, sizeof(unsigned)); + float *distances = calloc(nbnodes*nbnodes, sizeof(float)); + unsigned nfound; + numa_attr_t attr; + + attr.nattr_type = R_RAD; + attr.nattr_descr.rd_radset = radset; + attr.nattr_flags = 0; + + for (radid = 0; radid < (radid_t) nbnodes; radid++) { + rademptyset(radset); + radaddset(radset, radid); + cpuemptyset(cpuset); + if (rad_get_cpus(radid, cpuset)==-1) { + fprintf(stderr,"rad_get_cpus(%d) failed: %s\n",radid,strerror(errno)); + continue; + } + + indexes[radid] = radid; + nodes[radid] = obj = hwloc_alloc_setup_object(HWLOC_OBJ_NUMANODE, radid); + obj->nodeset = hwloc_bitmap_alloc(); + hwloc_bitmap_set(obj->nodeset, radid); + obj->cpuset = hwloc_bitmap_alloc(); + obj->memory.local_memory = rad_get_physmem(radid) * hwloc_getpagesize(); + obj->memory.page_types_len = 2; + obj->memory.page_types = malloc(2*sizeof(*obj->memory.page_types)); + memset(obj->memory.page_types, 0, 2*sizeof(*obj->memory.page_types)); + obj->memory.page_types[0].size = hwloc_getpagesize(); +#ifdef HAVE__SC_LARGE_PAGESIZE + obj->memory.page_types[1].size = sysconf(_SC_LARGE_PAGESIZE); +#endif + + cursor = SET_CURSOR_INIT; + while((cpuid = cpu_foreach(cpuset, 0, &cursor)) != CPU_NONE) + hwloc_bitmap_set(obj->cpuset, cpuid); + + hwloc_debug_1arg_bitmap("node %d has cpuset %s\n", + radid, obj->cpuset); + + hwloc_insert_object_by_cpuset(topology, obj); + + nfound = 0; + for (radid2 = 0; radid2 < (radid_t) nbnodes; radid2++) + distances[radid*nbnodes+radid2] = RAD_DIST_REMOTE; + for (distance = RAD_DIST_LOCAL; distance < RAD_DIST_REMOTE; distance++) { + attr.nattr_distance = distance; + /* get set of NUMA nodes at distance <= DISTANCE */ + if (nloc(&attr, radset2)) { + fprintf(stderr,"nloc failed: %s\n", strerror(errno)); + continue; + } + cursor = SET_CURSOR_INIT; + while ((radid2 = rad_foreach(radset2, 0, &cursor)) != RAD_NONE) { + if (distances[radid*nbnodes+radid2] == RAD_DIST_REMOTE) { + distances[radid*nbnodes+radid2] = (float) distance; + nfound++; + } + } + if (nfound == nbnodes) + /* Finished finding distances, no need to go up to RAD_DIST_REMOTE */ + break; + } + } + + hwloc_distances_set(topology, HWLOC_OBJ_NUMANODE, nbnodes, indexes, nodes, distances, 0 /* OS cannot force */); + } + radsetdestroy(&radset2); + radsetdestroy(&radset); + cpusetdestroy(&cpuset); + + /* add PU objects */ + hwloc_setup_pu_level(topology, hwloc_fallback_nbprocessors(topology)); + + hwloc_obj_add_info(topology->levels[0][0], "Backend", "OSF"); + if (topology->is_thissystem) + hwloc_add_uname_info(topology, NULL); + return 1; +} + +void +hwloc_set_osf_hooks(struct hwloc_binding_hooks *hooks, + struct hwloc_topology_support *support) +{ + hooks->set_thread_cpubind = hwloc_osf_set_thread_cpubind; + hooks->set_thisthread_cpubind = hwloc_osf_set_thisthread_cpubind; + hooks->set_proc_cpubind = hwloc_osf_set_proc_cpubind; + hooks->set_thisproc_cpubind = hwloc_osf_set_thisproc_cpubind; + hooks->set_area_membind = hwloc_osf_set_area_membind; + hooks->alloc_membind = hwloc_osf_alloc_membind; + hooks->alloc = hwloc_alloc_mmap; + hooks->free_membind = hwloc_free_mmap; + support->membind->firsttouch_membind = 1; + support->membind->bind_membind = 1; + support->membind->interleave_membind = 1; + support->membind->replicate_membind = 1; +} + +static struct hwloc_backend * +hwloc_osf_component_instantiate(struct hwloc_disc_component *component, + const void *_data1 __hwloc_attribute_unused, + const void *_data2 __hwloc_attribute_unused, + const void *_data3 __hwloc_attribute_unused) +{ + struct hwloc_backend *backend; + backend = hwloc_backend_alloc(component); + if (!backend) + return NULL; + backend->discover = hwloc_look_osf; + return backend; +} + +static struct hwloc_disc_component hwloc_osf_disc_component = { + HWLOC_DISC_COMPONENT_TYPE_CPU, + "osf", + HWLOC_DISC_COMPONENT_TYPE_GLOBAL, + hwloc_osf_component_instantiate, + 50, + NULL +}; + +const struct hwloc_component hwloc_osf_component = { + HWLOC_COMPONENT_ABI, + NULL, NULL, + HWLOC_COMPONENT_TYPE_DISC, + 0, + &hwloc_osf_disc_component +}; diff --git a/opal/mca/hwloc/hwloc1110/hwloc/src/topology-pci.c b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-pci.c new file mode 100644 index 0000000000..3a3ad6bb55 --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-pci.c @@ -0,0 +1,341 @@ +/* + * Copyright © 2009 CNRS + * Copyright © 2009-2014 Inria. All rights reserved. + * Copyright © 2009-2011, 2013 Université Bordeaux + * Copyright © 2014 Cisco Systems, Inc. All rights reserved. + * See COPYING in top-level directory. + */ + +#include +#include +#include +#include + +/* private headers allowed for convenience because this plugin is built within hwloc */ +#include +#include + +#include +#include +#include +#include +#include +#include +#ifdef HWLOC_LINUX_SYS +#include +#endif + +#include + +#ifndef PCI_HEADER_TYPE +#define PCI_HEADER_TYPE 0x0e +#endif +#ifndef PCI_HEADER_TYPE_BRIDGE +#define PCI_HEADER_TYPE_BRIDGE 1 +#endif + +#ifndef PCI_CLASS_DEVICE +#define PCI_CLASS_DEVICE 0x0a +#endif +#ifndef PCI_CLASS_BRIDGE_PCI +#define PCI_CLASS_BRIDGE_PCI 0x0604 +#endif + +#ifndef PCI_REVISION_ID +#define PCI_REVISION_ID 0x08 +#endif + +#ifndef PCI_SUBSYSTEM_VENDOR_ID +#define PCI_SUBSYSTEM_VENDOR_ID 0x2c +#endif +#ifndef PCI_SUBSYSTEM_ID +#define PCI_SUBSYSTEM_ID 0x2e +#endif + +#ifndef PCI_PRIMARY_BUS +#define PCI_PRIMARY_BUS 0x18 +#endif +#ifndef PCI_SECONDARY_BUS +#define PCI_SECONDARY_BUS 0x19 +#endif +#ifndef PCI_SUBORDINATE_BUS +#define PCI_SUBORDINATE_BUS 0x1a +#endif + +#ifndef PCI_CAP_ID_EXP +#define PCI_CAP_ID_EXP 0x10 +#endif + +#ifndef PCI_CAP_NORMAL +#define PCI_CAP_NORMAL 1 +#endif + +#define CONFIG_SPACE_CACHESIZE 256 + + +static int +hwloc_look_pci(struct hwloc_backend *backend) +{ + struct hwloc_topology *topology = backend->topology; + struct hwloc_obj *first_obj = NULL, *last_obj = NULL; + int ret; + struct pci_device_iterator *iter; + struct pci_device *pcidev; +#ifdef HWLOC_LINUX_SYS + DIR *dir; +#endif + + if (!(hwloc_topology_get_flags(topology) & (HWLOC_TOPOLOGY_FLAG_IO_DEVICES|HWLOC_TOPOLOGY_FLAG_WHOLE_IO))) + return 0; + + if (hwloc_get_next_pcidev(topology, NULL)) { + hwloc_debug("%s", "PCI objects already added, ignoring pci backend.\n"); + return 0; + } + + if (!hwloc_topology_is_thissystem(topology)) { + hwloc_debug("%s", "\nno PCI detection (not thissystem)\n"); + return 0; + } + + hwloc_debug("%s", "\nScanning PCI buses...\n"); + + /* initialize PCI scanning */ + ret = pci_system_init(); + if (ret) { + hwloc_debug("%s", "Can not initialize libpciaccess\n"); + return -1; + } + + iter = pci_slot_match_iterator_create(NULL); + + /* iterate over devices */ + for (pcidev = pci_device_next(iter); + pcidev; + pcidev = pci_device_next(iter)) + { + const char *vendorname, *devicename, *fullname; + unsigned char config_space_cache[CONFIG_SPACE_CACHESIZE]; + struct hwloc_obj *obj; + unsigned os_index; + unsigned domain; + unsigned device_class; + unsigned short tmp16; + char name[128]; + unsigned offset; + + /* initialize the config space in case we fail to read it (missing permissions, etc). */ + memset(config_space_cache, 0xff, CONFIG_SPACE_CACHESIZE); + pci_device_probe(pcidev); + pci_device_cfg_read(pcidev, config_space_cache, 0, CONFIG_SPACE_CACHESIZE, NULL); + + /* try to read the domain */ + domain = pcidev->domain; + + /* try to read the device_class */ + device_class = pcidev->device_class >> 8; + + /* fixup SR-IOV buggy VF device/vendor IDs */ + if (0xffff == pcidev->vendor_id && 0xffff == pcidev->device_id) { + /* SR-IOV puts ffff:ffff in Virtual Function config space. + * The actual VF device ID is stored at a special (dynamic) location in the Physical Function config space. + * VF and PF have the same vendor ID. + * + * libpciaccess just returns ffff:ffff, needs to be fixed. + * linuxpci is OK because sysfs files are already fixed the kernel. + * (pciutils is OK when it uses those Linux sysfs files.) + * + * Reading these files is an easy way to work around the libpciaccess issue on Linux, + * but we have no way to know if this is caused by SR-IOV or not. + * + * TODO: + * If PF has CAP_ID_PCIX or CAP_ID_EXP (offset>0), + * look for extended capability PCI_EXT_CAP_ID_SRIOV (need extended config space (more than 256 bytes)), + * then read the VF device ID after it (PCI_IOV_DID bytes later). + * Needs access to extended config space (needs root on Linux). + * TODO: + * Add string info attributes in VF and PF objects? + */ +#ifdef HWLOC_LINUX_SYS + /* Workaround for Linux (the kernel returns the VF device/vendor IDs). */ + char path[64]; + char value[16]; + FILE *file; + size_t read; + + snprintf(path, sizeof(path), "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/vendor", + domain, pcidev->bus, pcidev->dev, pcidev->func); + file = fopen(path, "r"); + if (file) { + read = fread(value, 1, sizeof(value), file); + fclose(file); + if (read) + /* fixup the pciaccess struct so that pci_device_get_vendor_name() is correct later. */ + pcidev->vendor_id = strtoul(value, NULL, 16); + } + + snprintf(path, sizeof(path), "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/device", + domain, pcidev->bus, pcidev->dev, pcidev->func); + file = fopen(path, "r"); + if (file) { + read = fread(value, 1, sizeof(value), file); + fclose(file); + if (read) + /* fixup the pciaccess struct so that pci_device_get_device_name() is correct later. */ + pcidev->device_id = strtoul(value, NULL, 16); + } +#endif + } + + /* might be useful for debugging (note that domain might be truncated) */ + os_index = (domain << 20) + (pcidev->bus << 12) + (pcidev->dev << 4) + pcidev->func; + + obj = hwloc_alloc_setup_object(HWLOC_OBJ_PCI_DEVICE, os_index); + obj->attr->pcidev.domain = domain; + obj->attr->pcidev.bus = pcidev->bus; + obj->attr->pcidev.dev = pcidev->dev; + obj->attr->pcidev.func = pcidev->func; + obj->attr->pcidev.vendor_id = pcidev->vendor_id; + obj->attr->pcidev.device_id = pcidev->device_id; + obj->attr->pcidev.class_id = device_class; + obj->attr->pcidev.revision = config_space_cache[PCI_REVISION_ID]; + + obj->attr->pcidev.linkspeed = 0; /* unknown */ + offset = hwloc_pci_find_cap(config_space_cache, PCI_CAP_ID_EXP); + + if (offset > 0 && offset + 20 /* size of PCI express block up to link status */ <= CONFIG_SPACE_CACHESIZE) + hwloc_pci_find_linkspeed(config_space_cache, offset, &obj->attr->pcidev.linkspeed); + + hwloc_pci_prepare_bridge(obj, config_space_cache); + + if (obj->type == HWLOC_OBJ_PCI_DEVICE) { + memcpy(&tmp16, &config_space_cache[PCI_SUBSYSTEM_VENDOR_ID], sizeof(tmp16)); + obj->attr->pcidev.subvendor_id = tmp16; + memcpy(&tmp16, &config_space_cache[PCI_SUBSYSTEM_ID], sizeof(tmp16)); + obj->attr->pcidev.subdevice_id = tmp16; + } else { + /* TODO: + * bridge must lookup PCI_CAP_ID_SSVID and then look at offset+PCI_SSVID_VENDOR/DEVICE_ID + * cardbus must look at PCI_CB_SUBSYSTEM_VENDOR_ID and PCI_CB_SUBSYSTEM_ID + */ + } + + /* get the vendor name */ + vendorname = pci_device_get_vendor_name(pcidev); + if (vendorname && *vendorname) + hwloc_obj_add_info(obj, "PCIVendor", vendorname); + + /* get the device name */ + devicename = pci_device_get_device_name(pcidev); + if (devicename && *devicename) + hwloc_obj_add_info(obj, "PCIDevice", devicename); + + /* generate or get the fullname */ + snprintf(name, sizeof(name), "%s%s%s", + vendorname ? vendorname : "", + vendorname && devicename ? " " : "", + devicename ? devicename : ""); + fullname = name; + if (*name) + obj->name = strdup(name); + hwloc_debug(" %04x:%02x:%02x.%01x %04x %04x:%04x %s\n", + domain, pcidev->bus, pcidev->dev, pcidev->func, + device_class, pcidev->vendor_id, pcidev->device_id, + fullname && *fullname ? fullname : "??"); + + /* queue the object for now */ + if (first_obj) + last_obj->next_sibling = obj; + else + first_obj = obj; + last_obj = obj; + } + + /* finalize device scanning */ + pci_iterator_destroy(iter); + pci_system_cleanup(); + +#ifdef HWLOC_LINUX_SYS + dir = opendir("/sys/bus/pci/slots/"); + if (dir) { + struct dirent *dirent; + while ((dirent = readdir(dir)) != NULL) { + char path[64]; + FILE *file; + if (dirent->d_name[0] == '.') + continue; + snprintf(path, sizeof(path), "/sys/bus/pci/slots/%s/address", dirent->d_name); + file = fopen(path, "r"); + if (file) { + unsigned domain, bus, dev; + if (fscanf(file, "%x:%x:%x", &domain, &bus, &dev) == 3) { + hwloc_obj_t obj = first_obj; + while (obj) { + if (obj->attr->pcidev.domain == domain + && obj->attr->pcidev.bus == bus + && obj->attr->pcidev.dev == dev + && obj->attr->pcidev.func == 0) { + hwloc_obj_add_info(obj, "PCISlot", dirent->d_name); + break; + } + obj = obj->next_sibling; + } + } + fclose(file); + } + } + closedir(dir); + } +#endif + + return hwloc_insert_pci_device_list(backend, first_obj); +} + +static struct hwloc_backend * +hwloc_pci_component_instantiate(struct hwloc_disc_component *component, + const void *_data1 __hwloc_attribute_unused, + const void *_data2 __hwloc_attribute_unused, + const void *_data3 __hwloc_attribute_unused) +{ + struct hwloc_backend *backend; + + /* thissystem may not be fully initialized yet, we'll check flags in discover() */ + + backend = hwloc_backend_alloc(component); + if (!backend) + return NULL; + backend->flags = HWLOC_BACKEND_FLAG_NEED_LEVELS; + backend->discover = hwloc_look_pci; + return backend; +} + +static struct hwloc_disc_component hwloc_pci_disc_component = { + HWLOC_DISC_COMPONENT_TYPE_MISC, + "pci", + HWLOC_DISC_COMPONENT_TYPE_GLOBAL, + hwloc_pci_component_instantiate, + 20, + NULL +}; + +static int +hwloc_pci_component_init(unsigned long flags) +{ + if (flags) + return -1; + if (hwloc_plugin_check_namespace("pci", "hwloc_backend_alloc") < 0) + return -1; + return 0; +} + +#ifdef HWLOC_INSIDE_PLUGIN +HWLOC_DECLSPEC extern const struct hwloc_component hwloc_pci_component; +#endif + +const struct hwloc_component hwloc_pci_component = { + HWLOC_COMPONENT_ABI, + hwloc_pci_component_init, NULL, + HWLOC_COMPONENT_TYPE_DISC, + 0, + &hwloc_pci_disc_component +}; diff --git a/opal/mca/hwloc/hwloc1110/hwloc/src/topology-solaris-chiptype.c b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-solaris-chiptype.c new file mode 100644 index 0000000000..2127e128ff --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-solaris-chiptype.c @@ -0,0 +1,339 @@ +/* + * Copyright © 2009-2010 Oracle and/or its affiliates. All rights reserved. + * Copyright © 2013 Université Bordeaux. All rights reserved. + * + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ + +#include +#include +#include +#include +#include + +#ifdef HAVE_PICL_H +#include +#include + +/***************************************************************************** + Order of this list is important for the assign_value and + assign_string_value routines +*****************************************************************************/ + +static const char* items[] = { + "clock-frequency", + "cpu-mhz", + "ecache-size", + "l2-cache-size", + "sectored-l2-cache-size", + "implementation#", + "manufacturer#", + "compatible", + "ProcessorType", + "vendor-id", + "brand-string" +}; + +#define NUM_ITEMS (sizeof(items) / sizeof(items[0])) + +/***************************************************************************** +SPARC strings for chip modes and implementation +*****************************************************************************/ +static const char* sparc_modes[] = { + "UNKNOWN", + "SPITFIRE", + "BLACKBIRD", + "CHEETAH", + "SPARC64_VI", + "T1", + "T2", + "SPARC64_VII", + "ROCK" +}; + +/***************************************************************************** +Default values are for Unknown so we can build up from there. +*****************************************************************************/ + +static long dss_chip_mode = MODE_UNKNOWN; +static long dss_chip_impl = IMPL_SPITFIRE; +static long dss_chip_cache = TWO_MEG_CACHE; +static long dss_chip_manufacturer = TI_MANUFACTURER; +static long long dss_chip_speed = SPITFIRE_SPEED; +static char dss_chip_type[PICL_PROPNAMELEN_MAX]; +static char dss_chip_model[PICL_PROPNAMELEN_MAX]; +static int called_cpu_probe = 0; + +/***************************************************************************** +Assigns values based on the value of index. For this reason, the order of +the items array is important. +*****************************************************************************/ +static void assign_value(int index, long long val) { + if (index == 0) { /* clock-frequency */ + dss_chip_speed = val; + } + if (index == 1) { /* cpu-mhz */ + dss_chip_speed = val * 1000000; /* Scale since value was in MHz */ + } + else if ((index >= 2) && (index <= 4)) { + /* ecache-size, l2-cache-size, sectored-l2-cache-size */ + dss_chip_cache = val; + } + else if (index == 5) { + /* implementation# T1, T2, and Rock do not have this, see RFE 6615268 */ + dss_chip_impl = val; + if (dss_chip_impl == IMPL_SPITFIRE) { + dss_chip_mode = 1; + } + else if ((dss_chip_impl >= IMPL_BLACKBIRD) && + (dss_chip_impl <= IMPL_HUMMINGBIRD)) { + dss_chip_mode = 2; + } + else if ((dss_chip_impl >= IMPL_CHEETAH) && + (dss_chip_impl <= IMPL_PANTHER)) { + dss_chip_mode = 3; + } + else if (dss_chip_impl == IMPL_SPARC64_VI) { + dss_chip_mode = 4; + } + else if (dss_chip_impl == IMPL_NIAGARA) { + dss_chip_mode = 5; + } + else if (dss_chip_impl == IMPL_NIAGARA_2) { + dss_chip_mode = 6; + } + else if (dss_chip_impl == IMPL_SPARC64_VII) { + dss_chip_mode = 7; + } + else if (dss_chip_impl == IMPL_ROCK) { + dss_chip_mode = 8; + } + } + else if (index == 6) { /* manufacturer# */ + dss_chip_manufacturer = val; + } +} + +/***************************************************************************** +Assigns values based on the value of index. For this reason, the order of +the items array is important. +*****************************************************************************/ +static void assign_string_value(int index, char* string_val) { + if (index == 7) { /* compatible */ + if (strncasecmp(string_val, "FJSV,SPARC64-VI", + PICL_PROPNAMELEN_MAX) == 0) { + dss_chip_mode = 4; + } + else if (strncasecmp(string_val, "SUNW,UltraSPARC-T1", + PICL_PROPNAMELEN_MAX) == 0) { + dss_chip_mode = 5; + } + else if (strncasecmp(string_val, "SUNW,UltraSPARC-T2", + PICL_PROPNAMELEN_MAX) == 0) { + dss_chip_mode = 6; + } + else if (strncasecmp(string_val, "FJSV,SPARC64-VII", + PICL_PROPNAMELEN_MAX) == 0) { + dss_chip_mode = 7; + } + else if (strncasecmp(string_val, "SUNW,Rock", + PICL_PROPNAMELEN_MAX) == 0) { + dss_chip_mode = 8; + } + } else if (index == 8) { /* ProcessorType */ + strncpy(&dss_chip_type[0], string_val, PICL_PROPNAMELEN_MAX); + } else if (index == 10) { /* brand-string */ + strncpy(&dss_chip_model[0], string_val, PICL_PROPNAMELEN_MAX); + } + +} + +/***************************************************************************** +Gets called by probe_cpu. Cycles through the table values until we find +what we are looking for. +*****************************************************************************/ +static void search_table(int index, picl_prophdl_t table_hdl) { + + picl_prophdl_t col_hdl; + picl_prophdl_t row_hdl; + picl_propinfo_t p_info; + int val; + char string_val[PICL_PROPNAMELEN_MAX]; + + for (val = picl_get_next_by_col(table_hdl, &row_hdl); val != PICL_ENDOFLIST; + val = picl_get_next_by_col(row_hdl, &row_hdl)) { + if (val == PICL_SUCCESS) { + for (col_hdl = row_hdl; val != PICL_ENDOFLIST; + val = picl_get_next_by_row(col_hdl, &col_hdl)) { + if (val == PICL_SUCCESS) { + val = picl_get_propinfo(col_hdl, &p_info); + if (val == PICL_SUCCESS) { + if (p_info.type == PICL_PTYPE_CHARSTRING) { + val = picl_get_propval(col_hdl, &string_val, sizeof(string_val)); + if (val == PICL_SUCCESS) { + assign_string_value(index, string_val); + } + } + } + } + } + } + } +} + +/***************************************************************************** +Gets called by picl_walk_tree_by_class. Then it cycles through the properties +until we find what we are looking for. Once we are done, we return +PICL_WALK_TERMINATE to stop picl_walk_tree_by_class from traversing the tree. + +Note that PICL_PTYPE_UNSIGNED_INT and PICL_PTYPE_INT can either be 4-bytes +or 8-bytes. +*****************************************************************************/ +static int probe_cpu(picl_nodehdl_t node_hdl, void* dummy_arg __hwloc_attribute_unused) { + + picl_prophdl_t p_hdl; + picl_prophdl_t table_hdl; + picl_propinfo_t p_info; + long long long_long_val; + unsigned int uint_val; + unsigned int index; + int int_val; + int val; + char string_val[PICL_PROPNAMELEN_MAX]; + + val = picl_get_first_prop(node_hdl, &p_hdl); + while (val == PICL_SUCCESS) { + called_cpu_probe = 1; + val = picl_get_propinfo(p_hdl, &p_info); + if (val == PICL_SUCCESS) { + for (index = 0; index < NUM_ITEMS; index++) { + if (strcasecmp(p_info.name, items[index]) == 0) { + if (p_info.type == PICL_PTYPE_UNSIGNED_INT) { + if (p_info.size == sizeof(uint_val)) { + val = picl_get_propval(p_hdl, &uint_val, sizeof(uint_val)); + if (val == PICL_SUCCESS) { + long_long_val = uint_val; + assign_value(index, long_long_val); + } + } + else if (p_info.size == sizeof(long_long_val)) { + val = picl_get_propval(p_hdl, &long_long_val, + sizeof(long_long_val)); + if (val == PICL_SUCCESS) { + assign_value(index, long_long_val); + } + } + } + else if (p_info.type == PICL_PTYPE_INT) { + if (p_info.size == sizeof(int_val)) { + val = picl_get_propval(p_hdl, &int_val, sizeof(int_val)); + if (val == PICL_SUCCESS) { + long_long_val = int_val; + assign_value(index, long_long_val); + } + } + else if (p_info.size == sizeof(long_long_val)) { + val = picl_get_propval(p_hdl, &long_long_val, + sizeof(long_long_val)); + if (val == PICL_SUCCESS) { + assign_value(index, long_long_val); + } + } + } + else if (p_info.type == PICL_PTYPE_CHARSTRING) { + val = picl_get_propval(p_hdl, &string_val, sizeof(string_val)); + if (val == PICL_SUCCESS) { + assign_string_value(index, string_val); + } + } + else if (p_info.type == PICL_PTYPE_TABLE) { + val = picl_get_propval(p_hdl, &table_hdl, p_info.size); + if (val == PICL_SUCCESS) { + search_table(index, table_hdl); + } + } + break; + } else if (index == NUM_ITEMS-1) { + if (p_info.type == PICL_PTYPE_CHARSTRING) { + val = picl_get_propval(p_hdl, &string_val, sizeof(string_val)); + if (val == PICL_SUCCESS) { + } + } + } + } + } + + val = picl_get_next_prop(p_hdl, &p_hdl); + } + return PICL_WALK_TERMINATE; +} + + +/***************************************************************************** +Initializes, gets the root, then walks the picl tree looking for information + +Currently, the "core" class is only needed for OPL systems +*****************************************************************************/ +char* hwloc_solaris_get_chip_type(void) { + picl_nodehdl_t root; + int val; + static char chip_type[PICL_PROPNAMELEN_MAX]; + + val = picl_initialize(); + if (val != PICL_SUCCESS) { /* Can't initialize session with PICL daemon */ + return(NULL); + } + val = picl_get_root(&root); + if (val != PICL_SUCCESS) { /* Failed to get root node of the PICL tree */ + return(NULL); + } + val = picl_walk_tree_by_class(root, "cpu", (void *)NULL, probe_cpu); + val = picl_walk_tree_by_class(root, "core", (void *)NULL, probe_cpu); + picl_shutdown(); + + if (called_cpu_probe) { +#if (defined HWLOC_X86_64_ARCH) || (defined HWLOC_X86_32_ARCH) + /* PICL returns some corrupted chip_type strings on x86, + * and CPUType only used on Sparc anyway, at least for now. + * So we just ignore this attribute on x86. */ +#else + strncpy(chip_type, dss_chip_type, PICL_PROPNAMELEN_MAX); +#endif + } else { + /* no picl information on machine available */ + sysinfo(SI_HW_PROVIDER, chip_type, PICL_PROPNAMELEN_MAX); + } + return(chip_type); +} + +/***************************************************************************** +Initializes, gets the root, then walks the picl tree looking for information + +Currently, the "core" class is only needed for OPL systems +*****************************************************************************/ +char *hwloc_solaris_get_chip_model(void) { + + if (called_cpu_probe) { + if (dss_chip_mode != MODE_UNKNOWN) { /* SPARC chip */ + strncpy(dss_chip_model, sparc_modes[dss_chip_mode], + PICL_PROPNAMELEN_MAX); + } + } else { + /* no picl information on machine available */ + sysinfo(SI_PLATFORM, dss_chip_model, PICL_PROPNAMELEN_MAX); + } + return(dss_chip_model); +} + +#else +char* hwloc_solaris_get_chip_type(void) { + return NULL; +} +char *hwloc_solaris_get_chip_model(void) { + return NULL; +} +#endif diff --git a/opal/mca/hwloc/hwloc1110/hwloc/src/topology-solaris.c b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-solaris.c new file mode 100644 index 0000000000..cd0e5aa339 --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-solaris.c @@ -0,0 +1,804 @@ +/* + * Copyright © 2009 CNRS + * Copyright © 2009-2014 Inria. All rights reserved. + * Copyright © 2009-2011 Université Bordeaux + * Copyright © 2011 Cisco Systems, Inc. All rights reserved. + * Copyright © 2011 Oracle and/or its affiliates. All rights reserved. + * See COPYING in top-level directory. + */ + +#include +#include +#include +#include +#include + +#include +#include +#ifdef HAVE_DIRENT_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include +#include +#include +#include + +#ifdef HAVE_LIBLGRP +# include +#endif + +/* TODO: use psets? (only for root) + * TODO: get cache info from prtdiag? (it is setgid sys to be able to read from + * crw-r----- 1 root sys 88, 0 nov 3 14:35 /devices/pseudo/devinfo@0:devinfo + * and run (apparently undocumented) ioctls on it. + */ + +static int +hwloc_solaris_set_sth_cpubind(hwloc_topology_t topology, idtype_t idtype, id_t id, hwloc_const_bitmap_t hwloc_set, int flags) +{ + unsigned target_cpu; + + /* The resulting binding is always strict */ + + if (hwloc_bitmap_isequal(hwloc_set, hwloc_topology_get_complete_cpuset(topology))) { + if (processor_bind(idtype, id, PBIND_NONE, NULL) != 0) + return -1; +#ifdef HAVE_LIBLGRP + if (!(flags & HWLOC_CPUBIND_NOMEMBIND)) { + int depth = hwloc_get_type_depth(topology, HWLOC_OBJ_NUMANODE); + if (depth >= 0) { + int n = hwloc_get_nbobjs_by_depth(topology, depth); + int i; + + for (i = 0; i < n; i++) { + hwloc_obj_t obj = hwloc_get_obj_by_depth(topology, depth, i); + lgrp_affinity_set(idtype, id, obj->os_index, LGRP_AFF_NONE); + } + } + } +#endif /* HAVE_LIBLGRP */ + return 0; + } + +#ifdef HAVE_LIBLGRP + if (!(flags & HWLOC_CPUBIND_NOMEMBIND)) { + int depth = hwloc_get_type_depth(topology, HWLOC_OBJ_NUMANODE); + if (depth >= 0) { + int n = hwloc_get_nbobjs_by_depth(topology, depth); + int i; + int ok; + hwloc_bitmap_t target = hwloc_bitmap_alloc(); + + for (i = 0; i < n; i++) { + hwloc_obj_t obj = hwloc_get_obj_by_depth(topology, depth, i); + if (hwloc_bitmap_isincluded(obj->cpuset, hwloc_set)) + hwloc_bitmap_or(target, target, obj->cpuset); + } + + ok = hwloc_bitmap_isequal(target, hwloc_set); + hwloc_bitmap_free(target); + + if (ok) { + /* Ok, managed to achieve hwloc_set by just combining NUMA nodes */ + + for (i = 0; i < n; i++) { + hwloc_obj_t obj = hwloc_get_obj_by_depth(topology, depth, i); + + if (hwloc_bitmap_isincluded(obj->cpuset, hwloc_set)) { + lgrp_affinity_set(idtype, id, obj->os_index, LGRP_AFF_STRONG); + } else { + if (flags & HWLOC_CPUBIND_STRICT) + lgrp_affinity_set(idtype, id, obj->os_index, LGRP_AFF_NONE); + else + lgrp_affinity_set(idtype, id, obj->os_index, LGRP_AFF_WEAK); + } + } + + return 0; + } + } + } +#endif /* HAVE_LIBLGRP */ + + if (hwloc_bitmap_weight(hwloc_set) != 1) { + errno = EXDEV; + return -1; + } + + target_cpu = hwloc_bitmap_first(hwloc_set); + + if (processor_bind(idtype, id, + (processorid_t) (target_cpu), NULL) != 0) + return -1; + + return 0; +} + +static int +hwloc_solaris_set_proc_cpubind(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_const_bitmap_t hwloc_set, int flags) +{ + return hwloc_solaris_set_sth_cpubind(topology, P_PID, pid, hwloc_set, flags); +} + +static int +hwloc_solaris_set_thisproc_cpubind(hwloc_topology_t topology, hwloc_const_bitmap_t hwloc_set, int flags) +{ + return hwloc_solaris_set_sth_cpubind(topology, P_PID, P_MYID, hwloc_set, flags); +} + +static int +hwloc_solaris_set_thisthread_cpubind(hwloc_topology_t topology, hwloc_const_bitmap_t hwloc_set, int flags) +{ + return hwloc_solaris_set_sth_cpubind(topology, P_LWPID, P_MYID, hwloc_set, flags); +} + +#ifdef HAVE_LIBLGRP +static int +hwloc_solaris_get_sth_cpubind(hwloc_topology_t topology, idtype_t idtype, id_t id, hwloc_bitmap_t hwloc_set, int flags __hwloc_attribute_unused) +{ + processorid_t binding; + int depth = hwloc_get_type_depth(topology, HWLOC_OBJ_NUMANODE); + int n; + int i; + + if (depth < 0) { + errno = ENOSYS; + return -1; + } + + /* first check if processor_bind() was used to bind to a single processor rather than to an lgroup */ + if ( processor_bind(idtype, id, PBIND_QUERY, &binding) == 0 && binding != PBIND_NONE ) { + hwloc_bitmap_only(hwloc_set, binding); + return 0; + } + + /* if not, check lgroups */ + hwloc_bitmap_zero(hwloc_set); + n = hwloc_get_nbobjs_by_depth(topology, depth); + for (i = 0; i < n; i++) { + hwloc_obj_t obj = hwloc_get_obj_by_depth(topology, depth, i); + lgrp_affinity_t aff = lgrp_affinity_get(idtype, id, obj->os_index); + + if (aff == LGRP_AFF_STRONG) + hwloc_bitmap_or(hwloc_set, hwloc_set, obj->cpuset); + } + + if (hwloc_bitmap_iszero(hwloc_set)) + hwloc_bitmap_copy(hwloc_set, hwloc_topology_get_complete_cpuset(topology)); + + return 0; +} + +static int +hwloc_solaris_get_proc_cpubind(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_bitmap_t hwloc_set, int flags) +{ + return hwloc_solaris_get_sth_cpubind(topology, P_PID, pid, hwloc_set, flags); +} + +static int +hwloc_solaris_get_thisproc_cpubind(hwloc_topology_t topology, hwloc_bitmap_t hwloc_set, int flags) +{ + return hwloc_solaris_get_sth_cpubind(topology, P_PID, P_MYID, hwloc_set, flags); +} + +static int +hwloc_solaris_get_thisthread_cpubind(hwloc_topology_t topology, hwloc_bitmap_t hwloc_set, int flags) +{ + return hwloc_solaris_get_sth_cpubind(topology, P_LWPID, P_MYID, hwloc_set, flags); +} +#endif /* HAVE_LIBLGRP */ + +/* TODO: given thread, probably not easy because of the historical n:m implementation */ +#ifdef HAVE_LIBLGRP +static int +hwloc_solaris_set_sth_membind(hwloc_topology_t topology, idtype_t idtype, id_t id, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags) +{ + int depth; + int n, i; + + switch (policy) { + case HWLOC_MEMBIND_DEFAULT: + case HWLOC_MEMBIND_BIND: + break; + default: + errno = ENOSYS; + return -1; + } + + if (flags & HWLOC_MEMBIND_NOCPUBIND) { + errno = ENOSYS; + return -1; + } + + depth = hwloc_get_type_depth(topology, HWLOC_OBJ_NUMANODE); + if (depth < 0) { + errno = EXDEV; + return -1; + } + n = hwloc_get_nbobjs_by_depth(topology, depth); + + for (i = 0; i < n; i++) { + hwloc_obj_t obj = hwloc_get_obj_by_depth(topology, depth, i); + if (hwloc_bitmap_isset(nodeset, obj->os_index)) { + lgrp_affinity_set(idtype, id, obj->os_index, LGRP_AFF_STRONG); + } else { + if (flags & HWLOC_CPUBIND_STRICT) + lgrp_affinity_set(idtype, id, obj->os_index, LGRP_AFF_NONE); + else + lgrp_affinity_set(idtype, id, obj->os_index, LGRP_AFF_WEAK); + } + } + + return 0; +} + +static int +hwloc_solaris_set_proc_membind(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags) +{ + return hwloc_solaris_set_sth_membind(topology, P_PID, pid, nodeset, policy, flags); +} + +static int +hwloc_solaris_set_thisproc_membind(hwloc_topology_t topology, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags) +{ + return hwloc_solaris_set_sth_membind(topology, P_PID, P_MYID, nodeset, policy, flags); +} + +static int +hwloc_solaris_set_thisthread_membind(hwloc_topology_t topology, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags) +{ + return hwloc_solaris_set_sth_membind(topology, P_LWPID, P_MYID, nodeset, policy, flags); +} + +static int +hwloc_solaris_get_sth_membind(hwloc_topology_t topology, idtype_t idtype, id_t id, hwloc_nodeset_t nodeset, hwloc_membind_policy_t *policy, int flags __hwloc_attribute_unused) +{ + int depth = hwloc_get_type_depth(topology, HWLOC_OBJ_NUMANODE); + int n; + int i; + + if (depth < 0) { + errno = ENOSYS; + return -1; + } + + hwloc_bitmap_zero(nodeset); + n = hwloc_get_nbobjs_by_depth(topology, depth); + + for (i = 0; i < n; i++) { + hwloc_obj_t obj = hwloc_get_obj_by_depth(topology, depth, i); + lgrp_affinity_t aff = lgrp_affinity_get(idtype, id, obj->os_index); + + if (aff == LGRP_AFF_STRONG) + hwloc_bitmap_set(nodeset, obj->os_index); + } + + if (hwloc_bitmap_iszero(nodeset)) + hwloc_bitmap_copy(nodeset, hwloc_topology_get_complete_nodeset(topology)); + + *policy = HWLOC_MEMBIND_DEFAULT; + return 0; +} + +static int +hwloc_solaris_get_proc_membind(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_nodeset_t nodeset, hwloc_membind_policy_t *policy, int flags) +{ + return hwloc_solaris_get_sth_membind(topology, P_PID, pid, nodeset, policy, flags); +} + +static int +hwloc_solaris_get_thisproc_membind(hwloc_topology_t topology, hwloc_nodeset_t nodeset, hwloc_membind_policy_t *policy, int flags) +{ + return hwloc_solaris_get_sth_membind(topology, P_PID, P_MYID, nodeset, policy, flags); +} + +static int +hwloc_solaris_get_thisthread_membind(hwloc_topology_t topology, hwloc_nodeset_t nodeset, hwloc_membind_policy_t *policy, int flags) +{ + return hwloc_solaris_get_sth_membind(topology, P_LWPID, P_MYID, nodeset, policy, flags); +} +#endif /* HAVE_LIBLGRP */ + + +#ifdef MADV_ACCESS_LWP +static int +hwloc_solaris_set_area_membind(hwloc_topology_t topology, const void *addr, size_t len, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags __hwloc_attribute_unused) +{ + int advice; + size_t remainder; + + /* Can not give a set of nodes just for an area. */ + if (!hwloc_bitmap_isequal(nodeset, hwloc_topology_get_complete_nodeset(topology))) { + errno = EXDEV; + return -1; + } + + switch (policy) { + case HWLOC_MEMBIND_DEFAULT: + case HWLOC_MEMBIND_BIND: + advice = MADV_ACCESS_DEFAULT; + break; + case HWLOC_MEMBIND_FIRSTTOUCH: + case HWLOC_MEMBIND_NEXTTOUCH: + advice = MADV_ACCESS_LWP; + break; + case HWLOC_MEMBIND_INTERLEAVE: + advice = MADV_ACCESS_MANY; + break; + default: + errno = ENOSYS; + return -1; + } + + remainder = (uintptr_t) addr & (sysconf(_SC_PAGESIZE)-1); + addr = (char*) addr - remainder; + len += remainder; + return madvise((void*) addr, len, advice); +} +#endif + +#ifdef HAVE_LIBLGRP +static void +browse(struct hwloc_topology *topology, lgrp_cookie_t cookie, lgrp_id_t lgrp, hwloc_obj_t *glob_lgrps, unsigned *curlgrp) +{ + int n; + hwloc_obj_t obj; + lgrp_mem_size_t mem_size; + + n = lgrp_cpus(cookie, lgrp, NULL, 0, LGRP_CONTENT_HIERARCHY); + if (n == -1) + return; + + /* Is this lgrp a NUMA node? */ + if ((mem_size = lgrp_mem_size(cookie, lgrp, LGRP_MEM_SZ_INSTALLED, LGRP_CONTENT_DIRECT)) > 0) + { + int i; + processorid_t *cpuids; + cpuids = malloc(sizeof(processorid_t) * n); + assert(cpuids != NULL); + + obj = hwloc_alloc_setup_object(HWLOC_OBJ_NUMANODE, lgrp); + obj->nodeset = hwloc_bitmap_alloc(); + hwloc_bitmap_set(obj->nodeset, lgrp); + obj->cpuset = hwloc_bitmap_alloc(); + glob_lgrps[(*curlgrp)++] = obj; + + lgrp_cpus(cookie, lgrp, cpuids, n, LGRP_CONTENT_HIERARCHY); + for (i = 0; i < n ; i++) { + hwloc_debug("node %ld's cpu %d is %d\n", lgrp, i, cpuids[i]); + hwloc_bitmap_set(obj->cpuset, cpuids[i]); + } + hwloc_debug_1arg_bitmap("node %ld has cpuset %s\n", + lgrp, obj->cpuset); + + /* or LGRP_MEM_SZ_FREE */ + hwloc_debug("node %ld has %lldkB\n", lgrp, mem_size/1024); + obj->memory.local_memory = mem_size; + obj->memory.page_types_len = 2; + obj->memory.page_types = malloc(2*sizeof(*obj->memory.page_types)); + memset(obj->memory.page_types, 0, 2*sizeof(*obj->memory.page_types)); + obj->memory.page_types[0].size = hwloc_getpagesize(); +#ifdef HAVE__SC_LARGE_PAGESIZE + obj->memory.page_types[1].size = sysconf(_SC_LARGE_PAGESIZE); +#endif + hwloc_insert_object_by_cpuset(topology, obj); + free(cpuids); + } + + n = lgrp_children(cookie, lgrp, NULL, 0); + { + lgrp_id_t *lgrps; + int i; + + lgrps = malloc(sizeof(lgrp_id_t) * n); + assert(lgrps != NULL); + lgrp_children(cookie, lgrp, lgrps, n); + hwloc_debug("lgrp %ld has %d children\n", lgrp, n); + for (i = 0; i < n ; i++) + { + browse(topology, cookie, lgrps[i], glob_lgrps, curlgrp); + } + hwloc_debug("lgrp %ld's children done\n", lgrp); + free(lgrps); + } +} + +static void +hwloc_look_lgrp(struct hwloc_topology *topology) +{ + lgrp_cookie_t cookie; + unsigned curlgrp = 0; + int nlgrps; + lgrp_id_t root; + + if ((topology->flags & HWLOC_TOPOLOGY_FLAG_WHOLE_SYSTEM)) + cookie = lgrp_init(LGRP_VIEW_OS); + else + cookie = lgrp_init(LGRP_VIEW_CALLER); + if (cookie == LGRP_COOKIE_NONE) + { + hwloc_debug("lgrp_init failed: %s\n", strerror(errno)); + return; + } + nlgrps = lgrp_nlgrps(cookie); + root = lgrp_root(cookie); + { + hwloc_obj_t *glob_lgrps = calloc(nlgrps, sizeof(hwloc_obj_t)); + browse(topology, cookie, root, glob_lgrps, &curlgrp); +#ifdef HAVE_LGRP_LATENCY_COOKIE + { + float *distances = calloc(curlgrp*curlgrp, sizeof(float)); + unsigned *indexes = calloc(curlgrp,sizeof(unsigned)); + unsigned i, j; + for (i = 0; i < curlgrp; i++) { + indexes[i] = glob_lgrps[i]->os_index; + for (j = 0; j < curlgrp; j++) + distances[i*curlgrp+j] = (float) lgrp_latency_cookie(cookie, glob_lgrps[i]->os_index, glob_lgrps[j]->os_index, LGRP_LAT_CPU_TO_MEM); + } + hwloc_distances_set(topology, HWLOC_OBJ_NUMANODE, curlgrp, indexes, glob_lgrps, distances, 0 /* OS cannot force */); + } +#endif /* HAVE_LGRP_LATENCY_COOKIE */ + } + lgrp_fini(cookie); +} +#endif /* LIBLGRP */ + +#ifdef HAVE_LIBKSTAT +#include +static int +hwloc_look_kstat(struct hwloc_topology *topology) +{ + /* FIXME this assumes that all packages are identical */ + char *CPUType = hwloc_solaris_get_chip_type(); + char *CPUModel = hwloc_solaris_get_chip_model(); + + kstat_ctl_t *kc = kstat_open(); + kstat_t *ksp; + kstat_named_t *stat; + unsigned look_cores = 1, look_chips = 1; + + unsigned Pproc_max = 0; + unsigned Pproc_alloc = 256; + struct hwloc_solaris_Pproc { + unsigned Lpkg, Ppkg, Lcore, Lproc; + } * Pproc = malloc(Pproc_alloc * sizeof(*Pproc)); + + unsigned Lproc_num = 0; + unsigned Lproc_alloc = 256; + struct hwloc_solaris_Lproc { + unsigned Pproc; + } * Lproc = malloc(Lproc_alloc * sizeof(*Lproc)); + + unsigned Lcore_num = 0; + unsigned Lcore_alloc = 256; + struct hwloc_solaris_Lcore { + unsigned Pcore, Ppkg; + } * Lcore = malloc(Lcore_alloc * sizeof(*Lcore)); + + unsigned Lpkg_num = 0; + unsigned Lpkg_alloc = 256; + struct hwloc_solaris_Lpkg { + unsigned Ppkg; + } * Lpkg = malloc(Lpkg_alloc * sizeof(*Lpkg)); + + unsigned pkgid, coreid, cpuid; + unsigned i; + + for (i = 0; i < Pproc_alloc; i++) { + Pproc[i].Lproc = -1; + Pproc[i].Lpkg = -1; + Pproc[i].Ppkg = -1; + Pproc[i].Lcore = -1; + } + + if (!kc) { + hwloc_debug("kstat_open failed: %s\n", strerror(errno)); + free(Pproc); + free(Lproc); + free(Lcore); + free(Lpkg); + return 0; + } + + for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) + { + if (strncmp("cpu_info", ksp->ks_module, 8)) + continue; + + cpuid = ksp->ks_instance; + + if (kstat_read(kc, ksp, NULL) == -1) + { + fprintf(stderr, "kstat_read failed for CPU%u: %s\n", cpuid, strerror(errno)); + continue; + } + + hwloc_debug("cpu%u\n", cpuid); + + if (cpuid >= Pproc_alloc) { + Pproc_alloc *= 2; + Pproc = realloc(Pproc, Pproc_alloc * sizeof(*Pproc)); + for(i = Pproc_alloc/2; i < Pproc_alloc; i++) { + Pproc[i].Lproc = -1; + Pproc[i].Lpkg = -1; + Pproc[i].Ppkg = -1; + Pproc[i].Lcore = -1; + } + } + Pproc[cpuid].Lproc = Lproc_num; + + if (Lproc_num >= Lproc_alloc) { + Lproc_alloc *= 2; + Lproc = realloc(Lproc, Lproc_alloc * sizeof(*Lproc)); + } + Lproc[Lproc_num].Pproc = cpuid; + Lproc_num++; + + if (cpuid >= Pproc_max) + Pproc_max = cpuid + 1; + + stat = (kstat_named_t *) kstat_data_lookup(ksp, "state"); + if (!stat) + hwloc_debug("could not read state for CPU%u: %s\n", cpuid, strerror(errno)); + else if (stat->data_type != KSTAT_DATA_CHAR) + hwloc_debug("unknown kstat type %d for cpu state\n", stat->data_type); + else + { + hwloc_debug("cpu%u's state is %s\n", cpuid, stat->value.c); + if (strcmp(stat->value.c, "on-line")) + /* not online */ + hwloc_bitmap_clr(topology->levels[0][0]->online_cpuset, cpuid); + } + + if (look_chips) do { + /* Get Chip ID */ + stat = (kstat_named_t *) kstat_data_lookup(ksp, "chip_id"); + if (!stat) + { + if (Lpkg_num) + fprintf(stderr, "could not read package id for CPU%u: %s\n", cpuid, strerror(errno)); + else + hwloc_debug("could not read package id for CPU%u: %s\n", cpuid, strerror(errno)); + look_chips = 0; + continue; + } + switch (stat->data_type) { + case KSTAT_DATA_INT32: + pkgid = stat->value.i32; + break; + case KSTAT_DATA_UINT32: + pkgid = stat->value.ui32; + break; +#ifdef _INT64_TYPE + case KSTAT_DATA_UINT64: + pkgid = stat->value.ui64; + break; + case KSTAT_DATA_INT64: + pkgid = stat->value.i64; + break; +#endif + default: + fprintf(stderr, "chip_id type %d unknown\n", stat->data_type); + look_chips = 0; + continue; + } + Pproc[cpuid].Ppkg = pkgid; + for (i = 0; i < Lpkg_num; i++) + if (pkgid == Lpkg[i].Ppkg) + break; + Pproc[cpuid].Lpkg = i; + hwloc_debug("%u on package %u (%u)\n", cpuid, i, pkgid); + if (i == Lpkg_num) { + if (Lpkg_num == Lpkg_alloc) { + Lpkg_alloc *= 2; + Lpkg = realloc(Lpkg, Lpkg_alloc * sizeof(*Lpkg)); + } + Lpkg[Lpkg_num++].Ppkg = pkgid; + } + } while(0); + + if (look_cores) do { + /* Get Core ID */ + stat = (kstat_named_t *) kstat_data_lookup(ksp, "core_id"); + if (!stat) + { + if (Lcore_num) + fprintf(stderr, "could not read core id for CPU%u: %s\n", cpuid, strerror(errno)); + else + hwloc_debug("could not read core id for CPU%u: %s\n", cpuid, strerror(errno)); + look_cores = 0; + continue; + } + switch (stat->data_type) { + case KSTAT_DATA_INT32: + coreid = stat->value.i32; + break; + case KSTAT_DATA_UINT32: + coreid = stat->value.ui32; + break; +#ifdef _INT64_TYPE + case KSTAT_DATA_UINT64: + coreid = stat->value.ui64; + break; + case KSTAT_DATA_INT64: + coreid = stat->value.i64; + break; +#endif + default: + fprintf(stderr, "core_id type %d unknown\n", stat->data_type); + look_cores = 0; + continue; + } + for (i = 0; i < Lcore_num; i++) + if (coreid == Lcore[i].Pcore && Pproc[cpuid].Ppkg == Lcore[i].Ppkg) + break; + Pproc[cpuid].Lcore = i; + hwloc_debug("%u on core %u (%u)\n", cpuid, i, coreid); + if (i == Lcore_num) { + if (Lcore_num == Lcore_alloc) { + Lcore_alloc *= 2; + Lcore = realloc(Lcore, Lcore_alloc * sizeof(*Lcore)); + } + Lcore[Lcore_num].Ppkg = Pproc[cpuid].Ppkg; + Lcore[Lcore_num++].Pcore = coreid; + } + } while(0); + + /* Note: there is also clog_id for the Thread ID (not unique) and + * pkg_core_id for the core ID (not unique). They are not useful to us + * however. */ + } + + if (look_chips) { + struct hwloc_obj *obj; + unsigned j,k; + hwloc_debug("%d Packages\n", Lpkg_num); + for (j = 0; j < Lpkg_num; j++) { + obj = hwloc_alloc_setup_object(HWLOC_OBJ_PACKAGE, Lpkg[j].Ppkg); + if (CPUType) + hwloc_obj_add_info(obj, "CPUType", CPUType); + if (CPUModel) + hwloc_obj_add_info(obj, "CPUModel", CPUModel); + obj->cpuset = hwloc_bitmap_alloc(); + for(k=0; kcpuset, k); + hwloc_debug_1arg_bitmap("Package %d has cpuset %s\n", j, obj->cpuset); + hwloc_insert_object_by_cpuset(topology, obj); + } + hwloc_debug("%s", "\n"); + } + + if (look_cores) { + struct hwloc_obj *obj; + unsigned j,k; + hwloc_debug("%d Cores\n", Lcore_num); + for (j = 0; j < Lcore_num; j++) { + obj = hwloc_alloc_setup_object(HWLOC_OBJ_CORE, Lcore[j].Pcore); + obj->cpuset = hwloc_bitmap_alloc(); + for(k=0; kcpuset, k); + hwloc_debug_1arg_bitmap("Core %d has cpuset %s\n", j, obj->cpuset); + hwloc_insert_object_by_cpuset(topology, obj); + } + hwloc_debug("%s", "\n"); + } + if (Lproc_num) { + struct hwloc_obj *obj; + unsigned j,k; + hwloc_debug("%d PUs\n", Lproc_num); + for (j = 0; j < Lproc_num; j++) { + obj = hwloc_alloc_setup_object(HWLOC_OBJ_PU, Lproc[j].Pproc); + obj->cpuset = hwloc_bitmap_alloc(); + for(k=0; kcpuset, k); + hwloc_debug_1arg_bitmap("PU %d has cpuset %s\n", j, obj->cpuset); + hwloc_insert_object_by_cpuset(topology, obj); + } + hwloc_debug("%s", "\n"); + } + + kstat_close(kc); + + free(Pproc); + free(Lproc); + free(Lcore); + free(Lpkg); + + return Lproc_num > 0; +} +#endif /* LIBKSTAT */ + +static int +hwloc_look_solaris(struct hwloc_backend *backend) +{ + struct hwloc_topology *topology = backend->topology; + unsigned nbprocs = hwloc_fallback_nbprocessors (topology); + int alreadypus = 0; + + if (topology->levels[0][0]->cpuset) + /* somebody discovered things */ + return 0; + + hwloc_alloc_obj_cpusets(topology->levels[0][0]); + +#ifdef HAVE_LIBLGRP + hwloc_look_lgrp(topology); +#endif /* HAVE_LIBLGRP */ +#ifdef HAVE_LIBKSTAT + nbprocs = 0; + if (hwloc_look_kstat(topology) > 0) + alreadypus = 1; +#endif /* HAVE_LIBKSTAT */ + if (!alreadypus) + hwloc_setup_pu_level(topology, nbprocs); + + hwloc_obj_add_info(topology->levels[0][0], "Backend", "Solaris"); + if (topology->is_thissystem) + hwloc_add_uname_info(topology, NULL); + return 1; +} + +void +hwloc_set_solaris_hooks(struct hwloc_binding_hooks *hooks, + struct hwloc_topology_support *support __hwloc_attribute_unused) +{ + hooks->set_proc_cpubind = hwloc_solaris_set_proc_cpubind; + hooks->set_thisproc_cpubind = hwloc_solaris_set_thisproc_cpubind; + hooks->set_thisthread_cpubind = hwloc_solaris_set_thisthread_cpubind; +#ifdef HAVE_LIBLGRP + hooks->get_proc_cpubind = hwloc_solaris_get_proc_cpubind; + hooks->get_thisproc_cpubind = hwloc_solaris_get_thisproc_cpubind; + hooks->get_thisthread_cpubind = hwloc_solaris_get_thisthread_cpubind; + hooks->set_proc_membind = hwloc_solaris_set_proc_membind; + hooks->set_thisproc_membind = hwloc_solaris_set_thisproc_membind; + hooks->set_thisthread_membind = hwloc_solaris_set_thisthread_membind; + hooks->get_proc_membind = hwloc_solaris_get_proc_membind; + hooks->get_thisproc_membind = hwloc_solaris_get_thisproc_membind; + hooks->get_thisthread_membind = hwloc_solaris_get_thisthread_membind; +#endif /* HAVE_LIBLGRP */ +#ifdef MADV_ACCESS_LWP + hooks->set_area_membind = hwloc_solaris_set_area_membind; + support->membind->firsttouch_membind = 1; + support->membind->bind_membind = 1; + support->membind->interleave_membind = 1; + support->membind->nexttouch_membind = 1; +#endif +} + +static struct hwloc_backend * +hwloc_solaris_component_instantiate(struct hwloc_disc_component *component, + const void *_data1 __hwloc_attribute_unused, + const void *_data2 __hwloc_attribute_unused, + const void *_data3 __hwloc_attribute_unused) +{ + struct hwloc_backend *backend; + backend = hwloc_backend_alloc(component); + if (!backend) + return NULL; + backend->discover = hwloc_look_solaris; + return backend; +} + +static struct hwloc_disc_component hwloc_solaris_disc_component = { + HWLOC_DISC_COMPONENT_TYPE_CPU, + "solaris", + HWLOC_DISC_COMPONENT_TYPE_GLOBAL, + hwloc_solaris_component_instantiate, + 50, + NULL +}; + +const struct hwloc_component hwloc_solaris_component = { + HWLOC_COMPONENT_ABI, + NULL, NULL, + HWLOC_COMPONENT_TYPE_DISC, + 0, + &hwloc_solaris_disc_component +}; diff --git a/opal/mca/hwloc/hwloc1110/hwloc/src/topology-synthetic.c b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-synthetic.c new file mode 100644 index 0000000000..db7087bb92 --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-synthetic.c @@ -0,0 +1,1098 @@ +/* + * Copyright © 2009 CNRS + * Copyright © 2009-2015 Inria. All rights reserved. + * Copyright © 2009-2010 Université Bordeaux + * Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved. + * See COPYING in top-level directory. + */ + +#include +#include +#include +#include +#include + +#include +#include +#ifdef HAVE_STRINGS_H +#include +#endif + +struct hwloc_synthetic_level_data_s { + unsigned arity; + unsigned long totalwidth; + hwloc_obj_type_t type; + unsigned depth; /* For caches/groups */ + hwloc_obj_cache_type_t cachetype; /* For caches */ + hwloc_uint64_t memorysize; /* For caches/memory */ + + /* the indexes= attribute before parsing */ + const char *index_string; + unsigned long index_string_length; + /* the array of explicit indexes after parsing */ + unsigned *index_array; + + /* used while filling the topology */ + unsigned next_os_index; /* id of the next object for that level */ +}; + +struct hwloc_synthetic_backend_data_s { + /* synthetic backend parameters */ + char *string; +#define HWLOC_SYNTHETIC_MAX_DEPTH 128 + struct hwloc_synthetic_level_data_s level[HWLOC_SYNTHETIC_MAX_DEPTH]; +}; + +struct hwloc_synthetic_intlv_loop_s { + unsigned step; + unsigned nb; + unsigned level_depth; +}; + +static void +hwloc_synthetic_process_level_indexes(struct hwloc_synthetic_backend_data_s *data, + unsigned curleveldepth, + int verbose) +{ + struct hwloc_synthetic_level_data_s *curlevel = &data->level[curleveldepth]; + unsigned long total = curlevel->totalwidth; + const char *attr = curlevel->index_string; + unsigned long length = curlevel->index_string_length; + unsigned *array = NULL; + struct hwloc_synthetic_intlv_loop_s * loops = NULL; + unsigned long i; + + if (!attr) + return; + + array = calloc(total, sizeof(*array)); + if (!array) { + if (verbose) + fprintf(stderr, "Failed to allocate synthetic index array of size %lu\n", total); + goto out; + } + + i = strspn(attr, "0123456789,"); + if (i == length) { + /* explicit array of indexes */ + + for(i=0; iindex_array = array; + + } else { + /* interleaving */ + unsigned nr_loops = 1, cur_loop; + unsigned minstep = total; + unsigned long nbs = 1; + unsigned j, mul; + const char *tmp; + + tmp = attr; + while (tmp) { + tmp = strchr(tmp, ':'); + if (!tmp || tmp >= attr+length) + break; + nr_loops++; + tmp++; + } + /* nr_loops colon-separated fields, but we may need one more at the end */ + loops = malloc((nr_loops+1)*sizeof(*loops)); + if (!loops) { + if (verbose) + fprintf(stderr, "Failed to allocate synthetic index interleave loop array of size %u\n", nr_loops); + goto out_with_array; + } + + if (*attr >= '0' && *attr <= '9') { + /* interleaving as x*y:z*t:... */ + unsigned step, nb; + + tmp = attr; + cur_loop = 0; + while (tmp) { + char *tmp2, *tmp3; + step = (unsigned) strtol(tmp, &tmp2, 0); + if (tmp2 == tmp || *tmp2 != '*') { + if (verbose) + fprintf(stderr, "Failed to read synthetic index interleaving loop '%s' without number before '*'\n", tmp); + goto out_with_loops; + } + if (!step) { + if (verbose) + fprintf(stderr, "Invalid interleaving loop with step 0 at '%s'\n", tmp); + goto out_with_loops; + } + tmp2++; + nb = (unsigned) strtol(tmp2, &tmp3, 0); + if (tmp3 == tmp2 || (*tmp3 && *tmp3 != ':' && *tmp3 != ')' && *tmp3 != ' ')) { + if (verbose) + fprintf(stderr, "Failed to read synthetic index interleaving loop '%s' without number between '*' and ':'\n", tmp); + goto out_with_loops; + } + if (!nb) { + if (verbose) + fprintf(stderr, "Invalid interleaving loop with number 0 at '%s'\n", tmp2); + goto out_with_loops; + } + loops[cur_loop].step = step; + loops[cur_loop].nb = nb; + if (step < minstep) + minstep = step; + nbs *= nb; + cur_loop++; + if (*tmp3 == ')' || *tmp3 == ' ') + break; + tmp = (const char*) (tmp3+1); + } + + } else { + /* interleaving as type1:type2:... */ + hwloc_obj_type_t type; + hwloc_obj_cache_type_t cachetypeattr; + int depthattr; + int err; + + /* find level depths for each interleaving loop */ + tmp = attr; + cur_loop = 0; + while (tmp) { + err = hwloc_obj_type_sscanf(tmp, &type, &depthattr, &cachetypeattr, sizeof(cachetypeattr)); + if (err < 0) { + if (verbose) + fprintf(stderr, "Failed to read synthetic index interleaving loop type '%s'\n", tmp); + goto out_with_loops; + } + if (type == HWLOC_OBJ_MISC || type == HWLOC_OBJ_BRIDGE || type == HWLOC_OBJ_PCI_DEVICE || type == HWLOC_OBJ_OS_DEVICE) { + if (verbose) + fprintf(stderr, "Misc object type disallowed in synthetic index interleaving loop type '%s'\n", tmp); + goto out_with_loops; + } + for(i=0; ilevel[i].type) + continue; + if ((type == HWLOC_OBJ_GROUP || type == HWLOC_OBJ_CACHE) + && depthattr != -1 + && (unsigned) depthattr != data->level[i].depth) + continue; + if (type == HWLOC_OBJ_CACHE + && cachetypeattr != (hwloc_obj_cache_type_t) -1 + && cachetypeattr != data->level[i].cachetype) + continue; + loops[cur_loop].level_depth = i; + break; + } + if (i == curleveldepth) { + if (verbose) + fprintf(stderr, "Failed to find level for synthetic index interleaving loop type '%s' above '%s'\n", + tmp, hwloc_obj_type_string(curlevel->type)); + goto out_with_loops; + } + tmp = strchr(tmp, ':'); + if (!tmp || tmp > attr+length) + break; + tmp++; + cur_loop++; + } + + /* compute actual loop step/nb */ + for(cur_loop=0; cur_loop prevdepth) + prevdepth = loops[i].level_depth; + } + step = curlevel->totalwidth / data->level[mydepth].totalwidth; /* number of objects below us */ + nb = data->level[mydepth].totalwidth / data->level[prevdepth].totalwidth; /* number of us within parent */ + + loops[cur_loop].step = step; + loops[cur_loop].nb = nb; + assert(nb); + assert(step); + if (step < minstep) + minstep = step; + nbs *= nb; + } + } + assert(nbs); + + if (nbs != total) { + /* one loop of total/nbs steps is missing, add it if it's just the smallest one */ + if (minstep == total/nbs) { + loops[nr_loops].step = 1; + loops[nr_loops].nb = total/nbs; + nr_loops++; + } else { + if (verbose) + fprintf(stderr, "Invalid index interleaving total width %lu instead of %lu\n", nbs, total); + goto out_with_loops; + } + } + + /* generate the array of indexes */ + mul = 1; + for(i=0; i= total) { + if (verbose) + fprintf(stderr, "Invalid index interleaving generates out-of-range index %u\n", array[j]); + goto out_with_loops; + } + if (!array[j] && j) { + if (verbose) + fprintf(stderr, "Invalid index interleaving generates duplicate index values\n"); + goto out_with_loops; + } + } + + free(loops); + curlevel->index_array = array; + } + + return; + + out_with_loops: + free(loops); + out_with_array: + free(array); + out: + return; +} + +static hwloc_uint64_t +hwloc_synthetic_parse_memory_attr(const char *attr, const char **endp) +{ + const char *endptr; + hwloc_uint64_t size; + size = strtoull(attr, (char **) &endptr, 0); + if (!hwloc_strncasecmp(endptr, "TB", 2)) { + size <<= 40; + endptr += 2; + } else if (!hwloc_strncasecmp(endptr, "GB", 2)) { + size <<= 30; + endptr += 2; + } else if (!hwloc_strncasecmp(endptr, "MB", 2)) { + size <<= 20; + endptr += 2; + } else if (!hwloc_strncasecmp(endptr, "kB", 2)) { + size <<= 10; + endptr += 2; + } + *endp = endptr; + return size; +} + +static int +hwloc_synthetic_parse_level_attrs(const char *attrs, const char **next_posp, + struct hwloc_synthetic_level_data_s *curlevel, + int verbose) +{ + hwloc_obj_type_t type = curlevel->type; + const char *next_pos; + hwloc_uint64_t memorysize = 0; + const char *index_string = NULL; + unsigned long index_string_length = 0; + + next_pos = (const char *) strchr(attrs, ')'); + if (!next_pos) { + if (verbose) + fprintf(stderr, "Missing attribute closing bracket in synthetic string doesn't have a number of objects at '%s'\n", attrs); + errno = EINVAL; + return -1; + } + + while (')' != *attrs) { + if (HWLOC_OBJ_CACHE == type && !strncmp("size=", attrs, 5)) { + memorysize = hwloc_synthetic_parse_memory_attr(attrs+5, &attrs); + + } else if (HWLOC_OBJ_CACHE != type && !strncmp("memory=", attrs, 7)) { + memorysize = hwloc_synthetic_parse_memory_attr(attrs+7, &attrs); + + } else if (!strncmp("indexes=", attrs, 8)) { + index_string = attrs+8; + attrs += 8; + index_string_length = strcspn(attrs, " )"); + attrs += index_string_length; + + } else { + if (verbose) + fprintf(stderr, "Unknown attribute at '%s'\n", attrs); + errno = EINVAL; + return -1; + } + + if (' ' == *attrs) + attrs++; + else if (')' != *attrs) { + if (verbose) + fprintf(stderr, "Missing parameter separator at '%s'\n", attrs); + errno = EINVAL; + return -1; + } + } + + curlevel->memorysize = memorysize; + curlevel->index_string = index_string; + curlevel->index_string_length = index_string_length; + *next_posp = next_pos+1; + return 0; +} + +/* Read from description a series of integers describing a symmetrical + topology and update the hwloc_synthetic_backend_data_s accordingly. On + success, return zero. */ +static int +hwloc_backend_synthetic_init(struct hwloc_synthetic_backend_data_s *data, + const char *description) +{ + const char *pos, *next_pos; + unsigned long item, count; + unsigned i; + int cache_depth = 0, group_depth = 0; + int nb_machine_levels = 0, nb_node_levels = 0; + int nb_pu_levels = 0; + int verbose = 0; + const char *env = getenv("HWLOC_SYNTHETIC_VERBOSE"); + int err; + unsigned long totalarity = 1; + + if (env) + verbose = atoi(env); + + /* default values before we add root attributes */ + data->level[0].totalwidth = 1; + data->level[0].type = HWLOC_OBJ_MACHINE; + data->level[0].index_string = NULL; + data->level[0].index_array = NULL; + data->level[0].memorysize = 0; + if (*description == '(') { + err = hwloc_synthetic_parse_level_attrs(description+1, &description, &data->level[0], verbose); + if (err < 0) + return err; + } + + for (pos = description, count = 1; *pos; pos = next_pos) { +#define HWLOC_OBJ_TYPE_UNKNOWN ((hwloc_obj_type_t) -1) + hwloc_obj_type_t type = HWLOC_OBJ_TYPE_UNKNOWN; + int typedepth = -1; + hwloc_obj_cache_type_t cachetype = (hwloc_obj_cache_type_t) -1; + + /* initialize parent arity to 0 so that the levels are not infinite */ + data->level[count-1].arity = 0; + + while (*pos == ' ') + pos++; + + if (!*pos) + break; + + if (*pos < '0' || *pos > '9') { + if (hwloc_obj_type_sscanf(pos, &type, &typedepth, &cachetype, sizeof(cachetype)) < 0) { + if (verbose) + fprintf(stderr, "Synthetic string with unknown object type at '%s'\n", pos); + errno = EINVAL; + goto error; + } + if (type == HWLOC_OBJ_MISC || type == HWLOC_OBJ_BRIDGE || type == HWLOC_OBJ_PCI_DEVICE || type == HWLOC_OBJ_OS_DEVICE) { + if (verbose) + fprintf(stderr, "Synthetic string with disallowed object type at '%s'\n", pos); + errno = EINVAL; + goto error; + } + + next_pos = strchr(pos, ':'); + if (!next_pos) { + if (verbose) + fprintf(stderr,"Synthetic string doesn't have a `:' after object type at '%s'\n", pos); + errno = EINVAL; + goto error; + } + pos = next_pos + 1; + } + data->level[count].type = type; + data->level[count].depth = (unsigned) typedepth; + data->level[count].cachetype = cachetype; + + item = strtoul(pos, (char **)&next_pos, 0); + if (next_pos == pos) { + if (verbose) + fprintf(stderr,"Synthetic string doesn't have a number of objects at '%s'\n", pos); + errno = EINVAL; + goto error; + } + data->level[count-1].arity = (unsigned)item; + + totalarity *= item; + data->level[count].totalwidth = totalarity; + data->level[count].index_string = NULL; + data->level[count].index_array = NULL; + data->level[count].memorysize = 0; + if (*next_pos == '(') { + err = hwloc_synthetic_parse_level_attrs(next_pos+1, &next_pos, &data->level[count], verbose); + if (err < 0) + goto error; + } + + if (count + 1 >= HWLOC_SYNTHETIC_MAX_DEPTH) { + if (verbose) + fprintf(stderr,"Too many synthetic levels, max %d\n", HWLOC_SYNTHETIC_MAX_DEPTH); + errno = EINVAL; + goto error; + } + if (item > UINT_MAX) { + if (verbose) + fprintf(stderr,"Too big arity, max %u\n", UINT_MAX); + errno = EINVAL; + goto error; + } + + count++; + } + + if (count <= 0) { + if (verbose) + fprintf(stderr, "Synthetic string doesn't contain any object\n"); + errno = EINVAL; + goto error; + } + + for(i=count-1; i>0; i--) { + struct hwloc_synthetic_level_data_s *curlevel = &data->level[i]; + hwloc_obj_type_t type; + + type = curlevel->type; + + if (type == HWLOC_OBJ_TYPE_UNKNOWN) { + if (i == count-1) + type = HWLOC_OBJ_PU; + else { + switch (data->level[i+1].type) { + case HWLOC_OBJ_PU: type = HWLOC_OBJ_CORE; break; + case HWLOC_OBJ_CORE: type = HWLOC_OBJ_CACHE; break; + case HWLOC_OBJ_CACHE: type = HWLOC_OBJ_PACKAGE; break; + case HWLOC_OBJ_PACKAGE: type = HWLOC_OBJ_NUMANODE; break; + case HWLOC_OBJ_NUMANODE: + case HWLOC_OBJ_MACHINE: + case HWLOC_OBJ_GROUP: type = HWLOC_OBJ_GROUP; break; + default: + assert(0); + } + } + curlevel->type = type; + } + switch (type) { + case HWLOC_OBJ_PU: + nb_pu_levels++; + break; + case HWLOC_OBJ_CACHE: + cache_depth++; + break; + case HWLOC_OBJ_GROUP: + group_depth++; + break; + case HWLOC_OBJ_NUMANODE: + nb_node_levels++; + break; + case HWLOC_OBJ_MACHINE: + nb_machine_levels++; + break; + default: + break; + } + } + + if (!nb_pu_levels) { + if (verbose) + fprintf(stderr, "Synthetic string missing ending number of PUs\n"); + errno = EINVAL; + return -1; + } + if (nb_pu_levels > 1) { + if (verbose) + fprintf(stderr, "Synthetic string can not have several PU levels\n"); + errno = EINVAL; + return -1; + } + if (nb_node_levels > 1) { + if (verbose) + fprintf(stderr, "Synthetic string can not have several NUMA node levels\n"); + errno = EINVAL; + return -1; + } + if (nb_machine_levels > 1) { + if (verbose) + fprintf(stderr, "Synthetic string can not have several machine levels\n"); + errno = EINVAL; + return -1; + } + + if (nb_machine_levels) + data->level[0].type = HWLOC_OBJ_SYSTEM; + else { + data->level[0].type = HWLOC_OBJ_MACHINE; + nb_machine_levels++; + } + + if (cache_depth == 1) + /* if there is a single cache level, make it L2 */ + cache_depth = 2; + + for (i=0; ilevel[i]; + hwloc_obj_type_t type = curlevel->type; + + if (type == HWLOC_OBJ_GROUP) { + if (curlevel->depth == (unsigned)-1) + curlevel->depth = group_depth--; + + } else if (type == HWLOC_OBJ_CACHE) { + if (curlevel->depth == (unsigned)-1) + curlevel->depth = cache_depth--; + if (curlevel->cachetype == (hwloc_obj_cache_type_t) -1) + curlevel->cachetype = curlevel->depth == 1 ? HWLOC_OBJ_CACHE_DATA : HWLOC_OBJ_CACHE_UNIFIED; + if (!curlevel->memorysize) { + if (1 == curlevel->depth) + /* 32Kb in L1 */ + curlevel->memorysize = 32*1024; + else + /* *4 at each level, starting from 1MB for L2, unified */ + curlevel->memorysize = 256*1024 << (2*curlevel->depth); + } + + } else if (type == HWLOC_OBJ_NUMANODE && !curlevel->memorysize) { + /* 1GB in memory nodes. */ + curlevel->memorysize = 1024*1024*1024; + } + + hwloc_synthetic_process_level_indexes(data, i, verbose); + } + + data->string = strdup(description); + data->level[count-1].arity = 0; + return 0; + + error: + for(i=0; ilevel[i]; + free(curlevel->index_array); + if (!curlevel->arity) + break; + } + return -1; +} + +static void +hwloc_synthetic__post_look_hooks(struct hwloc_synthetic_level_data_s *curlevel, + hwloc_obj_t obj) +{ + switch (obj->type) { + case HWLOC_OBJ_GROUP: + obj->attr->group.depth = curlevel->depth; + break; + case HWLOC_OBJ_SYSTEM: + break; + case HWLOC_OBJ_MACHINE: + break; + case HWLOC_OBJ_NUMANODE: + break; + case HWLOC_OBJ_PACKAGE: + break; + case HWLOC_OBJ_CACHE: + obj->attr->cache.depth = curlevel->depth; + obj->attr->cache.linesize = 64; + obj->attr->cache.type = curlevel->cachetype; + obj->attr->cache.size = curlevel->memorysize; + break; + case HWLOC_OBJ_CORE: + break; + case HWLOC_OBJ_PU: + break; + case HWLOC_OBJ_BRIDGE: + case HWLOC_OBJ_PCI_DEVICE: + case HWLOC_OBJ_OS_DEVICE: + case HWLOC_OBJ_MISC: + case HWLOC_OBJ_TYPE_MAX: + /* Should never happen */ + assert(0); + break; + } + if (curlevel->memorysize && HWLOC_OBJ_CACHE != obj->type) { + obj->memory.local_memory = curlevel->memorysize; + obj->memory.page_types_len = 1; + obj->memory.page_types = malloc(sizeof(*obj->memory.page_types)); + memset(obj->memory.page_types, 0, sizeof(*obj->memory.page_types)); + obj->memory.page_types[0].size = 4096; + obj->memory.page_types[0].count = curlevel->memorysize / 4096; + } +} + +/* + * Recursively build objects whose cpu start at first_cpu + * - level gives where to look in the type, arity and id arrays + * - the id array is used as a variable to get unique IDs for a given level. + * - generated memory should be added to *memory_kB. + * - generated cpus should be added to parent_cpuset. + * - next cpu number to be used should be returned. + */ +static void +hwloc__look_synthetic(struct hwloc_topology *topology, + struct hwloc_synthetic_backend_data_s *data, + int level, + hwloc_bitmap_t parent_cpuset) +{ + hwloc_obj_t obj; + unsigned i; + struct hwloc_synthetic_level_data_s *curlevel = &data->level[level]; + hwloc_obj_type_t type = curlevel->type; + unsigned os_index; + + /* pre-hooks */ + switch (type) { + case HWLOC_OBJ_GROUP: + break; + case HWLOC_OBJ_MACHINE: + break; + case HWLOC_OBJ_NUMANODE: + break; + case HWLOC_OBJ_PACKAGE: + break; + case HWLOC_OBJ_CACHE: + break; + case HWLOC_OBJ_CORE: + break; + case HWLOC_OBJ_PU: + break; + case HWLOC_OBJ_SYSTEM: + case HWLOC_OBJ_BRIDGE: + case HWLOC_OBJ_PCI_DEVICE: + case HWLOC_OBJ_OS_DEVICE: + case HWLOC_OBJ_MISC: + case HWLOC_OBJ_TYPE_MAX: + /* Should never happen */ + assert(0); + break; + } + + os_index = curlevel->next_os_index++; + if (curlevel->index_array) + os_index = curlevel->index_array[os_index]; + obj = hwloc_alloc_setup_object(type, os_index); + obj->cpuset = hwloc_bitmap_alloc(); + + if (!curlevel->arity) { + hwloc_bitmap_set(obj->cpuset, os_index); + } else { + for (i = 0; i < curlevel->arity; i++) + hwloc__look_synthetic(topology, data, level + 1, obj->cpuset); + } + + if (type == HWLOC_OBJ_NUMANODE) { + obj->nodeset = hwloc_bitmap_alloc(); + hwloc_bitmap_set(obj->nodeset, os_index); + } + + hwloc_bitmap_or(parent_cpuset, parent_cpuset, obj->cpuset); + + hwloc_synthetic__post_look_hooks(curlevel, obj); + + hwloc_insert_object_by_cpuset(topology, obj); +} + +static int +hwloc_look_synthetic(struct hwloc_backend *backend) +{ + struct hwloc_topology *topology = backend->topology; + struct hwloc_synthetic_backend_data_s *data = backend->private_data; + hwloc_bitmap_t cpuset = hwloc_bitmap_alloc(); + unsigned i; + + assert(!topology->levels[0][0]->cpuset); + + hwloc_alloc_obj_cpusets(topology->levels[0][0]); + + topology->support.discovery->pu = 1; + + /* start with os_index 0 for each level */ + for (i = 0; data->level[i].arity > 0; i++) + data->level[i].next_os_index = 0; + /* ... including the last one */ + data->level[i].next_os_index = 0; + + /* update first level type according to the synthetic type array */ + topology->levels[0][0]->type = data->level[0].type; + hwloc_synthetic__post_look_hooks(&data->level[0], topology->levels[0][0]); + + for (i = 0; i < data->level[0].arity; i++) + hwloc__look_synthetic(topology, data, 1, cpuset); + + hwloc_bitmap_free(cpuset); + + hwloc_obj_add_info(topology->levels[0][0], "Backend", "Synthetic"); + hwloc_obj_add_info(topology->levels[0][0], "SyntheticDescription", data->string); + return 1; +} + +static void +hwloc_synthetic_backend_disable(struct hwloc_backend *backend) +{ + struct hwloc_synthetic_backend_data_s *data = backend->private_data; + unsigned i; + for(i=0; ilevel[i]; + free(curlevel->index_array); + if (!curlevel->arity) + break; + } + free(data->string); + free(data); +} + +static struct hwloc_backend * +hwloc_synthetic_component_instantiate(struct hwloc_disc_component *component, + const void *_data1, + const void *_data2 __hwloc_attribute_unused, + const void *_data3 __hwloc_attribute_unused) +{ + struct hwloc_backend *backend; + struct hwloc_synthetic_backend_data_s *data; + int err; + + if (!_data1) { + errno = EINVAL; + goto out; + } + + backend = hwloc_backend_alloc(component); + if (!backend) + goto out; + + data = malloc(sizeof(*data)); + if (!data) { + errno = ENOMEM; + goto out_with_backend; + } + + err = hwloc_backend_synthetic_init(data, (const char *) _data1); + if (err < 0) + goto out_with_data; + + backend->private_data = data; + backend->discover = hwloc_look_synthetic; + backend->disable = hwloc_synthetic_backend_disable; + backend->is_thissystem = 0; + + return backend; + + out_with_data: + free(data); + out_with_backend: + free(backend); + out: + return NULL; +} + +static struct hwloc_disc_component hwloc_synthetic_disc_component = { + HWLOC_DISC_COMPONENT_TYPE_GLOBAL, + "synthetic", + ~0, + hwloc_synthetic_component_instantiate, + 30, + NULL +}; + +const struct hwloc_component hwloc_synthetic_component = { + HWLOC_COMPONENT_ABI, + NULL, NULL, + HWLOC_COMPONENT_TYPE_DISC, + 0, + &hwloc_synthetic_disc_component +}; + +static int hwloc_topology_export_synthetic_indexes(struct hwloc_topology * topology, + hwloc_obj_t obj, + char *buffer, size_t buflen) +{ + unsigned depth = obj->depth; + unsigned total = topology->level_nbobjects[depth]; + unsigned step = 1; + unsigned nr_loops = 0; + struct hwloc_synthetic_intlv_loop_s *loops = NULL; + hwloc_obj_t cur; + unsigned i, j; + ssize_t tmplen = buflen; + char *tmp = buffer; + int res, ret = 0; + + /* must start with 0 */ + if (obj->os_index) + goto exportall; + + while (step != total) { + /* must be a divider of the total */ + if (total % step) + goto exportall; + + /* look for os_index == step */ + for(i=1; ilevels[depth][i]->os_index == step) + break; + if (i == total) + goto exportall; + for(j=2; jlevels[depth][i*j]->os_index != step*j) + break; + + nr_loops++; + loops = realloc(loops, nr_loops*sizeof(*loops)); + if (!loops) + goto exportall; + loops[nr_loops-1].step = i; + loops[nr_loops-1].nb = j; + step *= j; + } + + /* check this interleaving */ + for(i=0; ilevels[depth][i]->os_index != ind) + goto exportall; + } + + /* success, print it */ + for(j=0; j= tmplen) + res = tmplen>0 ? tmplen - 1 : 0; + tmp += res; + tmplen -= res; + } + + if (loops) + free(loops); + + return ret; + + exportall: + if (loops) + free(loops); + + /* dump all indexes */ + cur = obj; + while (cur) { + res = snprintf(tmp, tmplen, "%u%s", cur->os_index, + cur->next_cousin ? "," : ")"); + if (res < 0) + return -1; + ret += res; + if (res >= tmplen) + res = tmplen>0 ? tmplen - 1 : 0; + tmp += res; + tmplen -= res; + cur = cur->next_cousin; + } + return ret; +} + +static int hwloc_topology_export_synthetic_obj_attr(struct hwloc_topology * topology, + hwloc_obj_t obj, + char *buffer, size_t buflen) +{ + const char * separator = " "; + const char * prefix = "("; + char cachesize[64] = ""; + char memsize[64] = ""; + int needindexes = 0; + + if (HWLOC_OBJ_CACHE == obj->type && obj->attr->cache.size) { + snprintf(cachesize, sizeof(cachesize), "%ssize=%llu", + prefix, (unsigned long long) obj->attr->cache.size); + prefix = separator; + } + if (obj->memory.local_memory) { + snprintf(memsize, sizeof(memsize), "%smemory=%llu", + prefix, (unsigned long long) obj->memory.local_memory); + prefix = separator; + } + if (obj->type == HWLOC_OBJ_PU || obj->type == HWLOC_OBJ_NUMANODE) { + hwloc_obj_t cur = obj; + while (cur) { + if (cur->os_index != cur->logical_index) { + needindexes = 1; + break; + } + cur = cur->next_cousin; + } + } + if (*cachesize || *memsize || needindexes) { + ssize_t tmplen = buflen; + char *tmp = buffer; + int res, ret = 0; + + res = hwloc_snprintf(tmp, tmplen, "%s%s%s", cachesize, memsize, needindexes ? "" : ")"); + if (res < 0) + return -1; + ret += res; + if (res >= tmplen) + res = tmplen>0 ? tmplen - 1 : 0; + tmp += res; + tmplen -= res; + + if (needindexes) { + res = snprintf(tmp, tmplen, "%sindexes=", prefix); + if (res < 0) + return -1; + ret += res; + if (res >= tmplen) + res = tmplen>0 ? tmplen - 1 : 0; + tmp += res; + tmplen -= res; + + res = hwloc_topology_export_synthetic_indexes(topology, obj, tmp, tmplen); + if (res < 0) + return -1; + ret += res; + if (res >= tmplen) + res = tmplen>0 ? tmplen - 1 : 0; + tmp += res; + tmplen -= res; + } + return ret; + } else { + return 0; + } +} + +int +hwloc_topology_export_synthetic(struct hwloc_topology * topology, + char *buffer, size_t buflen, + unsigned long flags) +{ + hwloc_obj_t obj = hwloc_get_root_obj(topology); + ssize_t tmplen = buflen; + char *tmp = buffer; + int res, ret = 0; + int arity; + const char * separator = " "; + const char * prefix = ""; + + if (flags & ~(HWLOC_TOPOLOGY_EXPORT_SYNTHETIC_FLAG_NO_EXTENDED_TYPES|HWLOC_TOPOLOGY_EXPORT_SYNTHETIC_FLAG_NO_ATTRS)) { + errno = EINVAL; + return -1; + } + + /* TODO: add a flag to ignore symmetric_subtree and I/Os. + * just assume things are symmetric with the left branches of the tree. + * but the number of objects per level may be wrong, what to do with OS index array in this case? + * only allow ignoring symmetric_subtree if the level width remains OK? + */ + + /* TODO: add a root object by default, with a prefix such as tree= + * so that we can backward-compatibly recognize whether there's a root or not. + * and add a flag to disable it. + */ + + /* TODO: flag to force all indexes, not only for PU and NUMA? */ + + if (!obj->symmetric_subtree) { + errno = EINVAL; + return -1; + } + + if (!(flags & HWLOC_TOPOLOGY_EXPORT_SYNTHETIC_FLAG_NO_ATTRS)) { + /* root attributes */ + res = hwloc_topology_export_synthetic_obj_attr(topology, obj, tmp, tmplen); + if (res < 0) + return -1; + ret += res; + if (ret > 0) + prefix = separator; + if (res >= tmplen) + res = tmplen>0 ? tmplen - 1 : 0; + tmp += res; + tmplen -= res; + } + + arity = obj->arity; + while (arity) { + /* for each level */ + obj = obj->first_child; + if (flags & HWLOC_TOPOLOGY_EXPORT_SYNTHETIC_FLAG_NO_EXTENDED_TYPES) { + res = hwloc_snprintf(tmp, tmplen, "%s%s:%u", prefix, hwloc_obj_type_string(obj->type), arity); + } else { + char types[64]; + hwloc_obj_type_snprintf(types, sizeof(types), obj, 1); + res = hwloc_snprintf(tmp, tmplen, "%s%s:%u", prefix, types, arity); + } + if (res < 0) + return -1; + ret += res; + if (res >= tmplen) + res = tmplen>0 ? tmplen - 1 : 0; + tmp += res; + tmplen -= res; + + if (!(flags & HWLOC_TOPOLOGY_EXPORT_SYNTHETIC_FLAG_NO_ATTRS)) { + /* obj attributes */ + res = hwloc_topology_export_synthetic_obj_attr(topology, obj, tmp, tmplen); + if (res < 0) + return -1; + ret += res; + if (res >= tmplen) + res = tmplen>0 ? tmplen - 1 : 0; + tmp += res; + tmplen -= res; + } + + /* next level */ + prefix = separator; + arity = obj->arity; + } + + return ret; +} diff --git a/opal/mca/hwloc/hwloc1110/hwloc/src/topology-windows.c b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-windows.c new file mode 100644 index 0000000000..371aaa1c8b --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-windows.c @@ -0,0 +1,812 @@ +/* + * Copyright © 2009 CNRS + * Copyright © 2009-2015 Inria. All rights reserved. + * Copyright © 2009-2012 Université Bordeaux + * Copyright © 2011 Cisco Systems, Inc. All rights reserved. + * See COPYING in top-level directory. + */ + +/* To try to get all declarations duplicated below. */ +#define _WIN32_WINNT 0x0601 + +#include +#include +#include +#include + +#include + +#ifndef HAVE_KAFFINITY +typedef ULONG_PTR KAFFINITY, *PKAFFINITY; +#endif + +#ifndef HAVE_PROCESSOR_CACHE_TYPE +typedef enum _PROCESSOR_CACHE_TYPE { + CacheUnified, + CacheInstruction, + CacheData, + CacheTrace +} PROCESSOR_CACHE_TYPE; +#endif + +#ifndef CACHE_FULLY_ASSOCIATIVE +#define CACHE_FULLY_ASSOCIATIVE 0xFF +#endif + +#ifndef HAVE_CACHE_DESCRIPTOR +typedef struct _CACHE_DESCRIPTOR { + BYTE Level; + BYTE Associativity; + WORD LineSize; + DWORD Size; /* in bytes */ + PROCESSOR_CACHE_TYPE Type; +} CACHE_DESCRIPTOR, *PCACHE_DESCRIPTOR; +#endif + +#ifndef HAVE_LOGICAL_PROCESSOR_RELATIONSHIP +typedef enum _LOGICAL_PROCESSOR_RELATIONSHIP { + RelationProcessorCore, + RelationNumaNode, + RelationCache, + RelationProcessorPackage, + RelationGroup, + RelationAll = 0xffff +} LOGICAL_PROCESSOR_RELATIONSHIP; +#else /* HAVE_LOGICAL_PROCESSOR_RELATIONSHIP */ +# ifndef HAVE_RELATIONPROCESSORPACKAGE +# define RelationProcessorPackage 3 +# define RelationGroup 4 +# define RelationAll 0xffff +# endif /* HAVE_RELATIONPROCESSORPACKAGE */ +#endif /* HAVE_LOGICAL_PROCESSOR_RELATIONSHIP */ + +#ifndef HAVE_SYSTEM_LOGICAL_PROCESSOR_INFORMATION +typedef struct _SYSTEM_LOGICAL_PROCESSOR_INFORMATION { + ULONG_PTR ProcessorMask; + LOGICAL_PROCESSOR_RELATIONSHIP Relationship; + _ANONYMOUS_UNION + union { + struct { + BYTE flags; + } ProcessorCore; + struct { + DWORD NodeNumber; + } NumaNode; + CACHE_DESCRIPTOR Cache; + ULONGLONG Reserved[2]; + } DUMMYUNIONNAME; +} SYSTEM_LOGICAL_PROCESSOR_INFORMATION, *PSYSTEM_LOGICAL_PROCESSOR_INFORMATION; +#endif + +/* Extended interface, for group support */ + +#ifndef HAVE_GROUP_AFFINITY +typedef struct _GROUP_AFFINITY { + KAFFINITY Mask; + WORD Group; + WORD Reserved[3]; +} GROUP_AFFINITY, *PGROUP_AFFINITY; +#endif + +#ifndef HAVE_PROCESSOR_RELATIONSHIP +typedef struct _PROCESSOR_RELATIONSHIP { + BYTE Flags; + BYTE Reserved[21]; + WORD GroupCount; + GROUP_AFFINITY GroupMask[ANYSIZE_ARRAY]; +} PROCESSOR_RELATIONSHIP, *PPROCESSOR_RELATIONSHIP; +#endif + +#ifndef HAVE_NUMA_NODE_RELATIONSHIP +typedef struct _NUMA_NODE_RELATIONSHIP { + DWORD NodeNumber; + BYTE Reserved[20]; + GROUP_AFFINITY GroupMask; +} NUMA_NODE_RELATIONSHIP, *PNUMA_NODE_RELATIONSHIP; +#endif + +#ifndef HAVE_CACHE_RELATIONSHIP +typedef struct _CACHE_RELATIONSHIP { + BYTE Level; + BYTE Associativity; + WORD LineSize; + DWORD CacheSize; + PROCESSOR_CACHE_TYPE Type; + BYTE Reserved[20]; + GROUP_AFFINITY GroupMask; +} CACHE_RELATIONSHIP, *PCACHE_RELATIONSHIP; +#endif + +#ifndef HAVE_PROCESSOR_GROUP_INFO +typedef struct _PROCESSOR_GROUP_INFO { + BYTE MaximumProcessorCount; + BYTE ActiveProcessorCount; + BYTE Reserved[38]; + KAFFINITY ActiveProcessorMask; +} PROCESSOR_GROUP_INFO, *PPROCESSOR_GROUP_INFO; +#endif + +#ifndef HAVE_GROUP_RELATIONSHIP +typedef struct _GROUP_RELATIONSHIP { + WORD MaximumGroupCount; + WORD ActiveGroupCount; + ULONGLONG Reserved[2]; + PROCESSOR_GROUP_INFO GroupInfo[ANYSIZE_ARRAY]; +} GROUP_RELATIONSHIP, *PGROUP_RELATIONSHIP; +#endif + +#ifndef HAVE_SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX +typedef struct _SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX { + LOGICAL_PROCESSOR_RELATIONSHIP Relationship; + DWORD Size; + _ANONYMOUS_UNION + union { + PROCESSOR_RELATIONSHIP Processor; + NUMA_NODE_RELATIONSHIP NumaNode; + CACHE_RELATIONSHIP Cache; + GROUP_RELATIONSHIP Group; + /* Odd: no member to tell the cpu mask of the package... */ + } DUMMYUNIONNAME; +} SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, *PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX; +#endif + +#ifndef HAVE_PSAPI_WORKING_SET_EX_BLOCK +typedef union _PSAPI_WORKING_SET_EX_BLOCK { + ULONG_PTR Flags; + struct { + unsigned Valid :1; + unsigned ShareCount :3; + unsigned Win32Protection :11; + unsigned Shared :1; + unsigned Node :6; + unsigned Locked :1; + unsigned LargePage :1; + }; +} PSAPI_WORKING_SET_EX_BLOCK; +#endif + +#ifndef HAVE_PSAPI_WORKING_SET_EX_INFORMATION +typedef struct _PSAPI_WORKING_SET_EX_INFORMATION { + PVOID VirtualAddress; + PSAPI_WORKING_SET_EX_BLOCK VirtualAttributes; +} PSAPI_WORKING_SET_EX_INFORMATION; +#endif + +static void hwloc_bitmap_set_ith_ULONG_PTR(hwloc_bitmap_t set, unsigned i, ULONG_PTR mask) +{ + /* ULONG_PTR is 64/32bits depending on the arch + * while unsigned long is always 32bits */ +#if SIZEOF_VOID_P == 8 + hwloc_bitmap_set_ith_ulong(set, 2*i, mask & 0xffffffff); + hwloc_bitmap_set_ith_ulong(set, 2*i+1, mask >> 32); +#else + hwloc_bitmap_set_ith_ulong(set, i, mask); +#endif +} + +/* TODO: SetThreadIdealProcessor */ + +static int +hwloc_win_set_thread_cpubind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_thread_t thread, hwloc_const_bitmap_t hwloc_set, int flags) +{ + DWORD mask; + + if (flags & HWLOC_CPUBIND_NOMEMBIND) { + errno = ENOSYS; + return -1; + } + /* TODO: groups SetThreadGroupAffinity */ + /* The resulting binding is always strict */ + mask = hwloc_bitmap_to_ulong(hwloc_set); + if (!SetThreadAffinityMask(thread, mask)) + return -1; + return 0; +} + +/* TODO: SetThreadGroupAffinity to get affinity */ + +static int +hwloc_win_set_thisthread_cpubind(hwloc_topology_t topology, hwloc_const_bitmap_t hwloc_set, int flags) +{ + return hwloc_win_set_thread_cpubind(topology, GetCurrentThread(), hwloc_set, flags); +} + +static int +hwloc_win_set_thisthread_membind(hwloc_topology_t topology, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags) +{ + int ret; + hwloc_cpuset_t cpuset; + + if ((policy != HWLOC_MEMBIND_DEFAULT && policy != HWLOC_MEMBIND_BIND) + || flags & HWLOC_MEMBIND_NOCPUBIND) { + errno = ENOSYS; + return -1; + } + + cpuset = hwloc_bitmap_alloc(); + hwloc_cpuset_from_nodeset(topology, cpuset, nodeset); + ret = hwloc_win_set_thisthread_cpubind(topology, cpuset, flags & HWLOC_MEMBIND_STRICT?HWLOC_CPUBIND_STRICT:0); + hwloc_bitmap_free(cpuset); + return ret; +} + +static int +hwloc_win_set_proc_cpubind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_pid_t proc, hwloc_const_bitmap_t hwloc_set, int flags) +{ + DWORD mask; + if (flags & HWLOC_CPUBIND_NOMEMBIND) { + errno = ENOSYS; + return -1; + } + /* TODO: groups, hard: has to manually bind all threads into the other group, + * and the bind the process inside the group */ + /* The resulting binding is always strict */ + mask = hwloc_bitmap_to_ulong(hwloc_set); + if (!SetProcessAffinityMask(proc, mask)) + return -1; + return 0; +} + +static int +hwloc_win_set_proc_membind(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags) +{ + int ret; + hwloc_cpuset_t cpuset; + + if ((policy != HWLOC_MEMBIND_DEFAULT && policy != HWLOC_MEMBIND_BIND) + || flags & HWLOC_MEMBIND_NOCPUBIND) { + errno = ENOSYS; + return -1; + } + + cpuset = hwloc_bitmap_alloc(); + hwloc_cpuset_from_nodeset(topology, cpuset, nodeset); + ret = hwloc_win_set_proc_cpubind(topology, pid, cpuset, flags & HWLOC_MEMBIND_STRICT?HWLOC_CPUBIND_STRICT:0); + hwloc_bitmap_free(cpuset); + return ret; +} + +static int +hwloc_win_get_proc_cpubind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_pid_t proc, hwloc_bitmap_t hwloc_set, int flags) +{ + DWORD_PTR proc_mask, sys_mask; + if (flags & HWLOC_CPUBIND_NOMEMBIND) { + errno = ENOSYS; + return -1; + } + /* TODO: groups, GetProcessGroupAffinity, or merge SetThreadGroupAffinity for all threads */ + if (!GetProcessAffinityMask(proc, &proc_mask, &sys_mask)) + return -1; + hwloc_bitmap_from_ulong(hwloc_set, proc_mask); + return 0; +} + +static int +hwloc_win_get_proc_membind(hwloc_topology_t topology, hwloc_pid_t pid, hwloc_nodeset_t nodeset, hwloc_membind_policy_t * policy, int flags) +{ + int ret; + hwloc_cpuset_t cpuset = hwloc_bitmap_alloc(); + ret = hwloc_win_get_proc_cpubind(topology, pid, cpuset, flags & HWLOC_MEMBIND_STRICT?HWLOC_CPUBIND_STRICT:0); + if (!ret) { + *policy = HWLOC_MEMBIND_BIND; + hwloc_cpuset_to_nodeset(topology, cpuset, nodeset); + } + hwloc_bitmap_free(cpuset); + return ret; +} + +static int +hwloc_win_set_thisproc_cpubind(hwloc_topology_t topology, hwloc_const_bitmap_t hwloc_set, int flags) +{ + return hwloc_win_set_proc_cpubind(topology, GetCurrentProcess(), hwloc_set, flags); +} + +static int +hwloc_win_set_thisproc_membind(hwloc_topology_t topology, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags) +{ + return hwloc_win_set_proc_membind(topology, GetCurrentProcess(), nodeset, policy, flags); +} + +static int +hwloc_win_get_thisproc_cpubind(hwloc_topology_t topology, hwloc_bitmap_t hwloc_cpuset, int flags) +{ + return hwloc_win_get_proc_cpubind(topology, GetCurrentProcess(), hwloc_cpuset, flags); +} + +static int +hwloc_win_get_thisproc_membind(hwloc_topology_t topology, hwloc_nodeset_t nodeset, hwloc_membind_policy_t * policy, int flags) +{ + return hwloc_win_get_proc_membind(topology, GetCurrentProcess(), nodeset, policy, flags); +} + +static LPVOID (WINAPI *VirtualAllocExNumaProc)(HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect, DWORD nndPreferred); +static BOOL (WINAPI *VirtualFreeExProc)(HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType); +static BOOL (WINAPI *QueryWorkingSetExProc)(HANDLE hProcess, PVOID pv, DWORD cb); + +static int hwloc_win_get_VirtualAllocExNumaProc(void) { + if (VirtualAllocExNumaProc == NULL) { + FARPROC alloc_fun = NULL, free_fun = NULL; + HMODULE kernel32; + + kernel32 = LoadLibrary("kernel32.dll"); + if (kernel32) { + alloc_fun = GetProcAddress(kernel32, "VirtualAllocExNuma"); + free_fun = GetProcAddress(kernel32, "VirtualFreeEx"); + } + + if (!alloc_fun || !free_fun) { + VirtualAllocExNumaProc = (FARPROC) -1; + errno = ENOSYS; + return -1; + } + + VirtualAllocExNumaProc = alloc_fun; + VirtualFreeExProc = free_fun; + } else if ((FARPROC) VirtualAllocExNumaProc == (FARPROC)-1) { + errno = ENOSYS; + return -1; + } + + return 0; +} + +static void * +hwloc_win_alloc(hwloc_topology_t topology __hwloc_attribute_unused, size_t len) { + return VirtualAlloc(NULL, len, MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE); +} + +static void * +hwloc_win_alloc_membind(hwloc_topology_t topology __hwloc_attribute_unused, size_t len, hwloc_const_nodeset_t nodeset, hwloc_membind_policy_t policy, int flags) { + int node; + + switch (policy) { + case HWLOC_MEMBIND_DEFAULT: + case HWLOC_MEMBIND_BIND: + break; + default: + errno = ENOSYS; + return hwloc_alloc_or_fail(topology, len, flags); + } + + if (flags & HWLOC_MEMBIND_STRICT) { + errno = ENOSYS; + return NULL; + } + + if (hwloc_bitmap_weight(nodeset) != 1) { + /* Not a single node, can't do this */ + errno = EXDEV; + return hwloc_alloc_or_fail(topology, len, flags); + } + + node = hwloc_bitmap_first(nodeset); + return VirtualAllocExNumaProc(GetCurrentProcess(), NULL, len, MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE, node); +} + +static int +hwloc_win_free_membind(hwloc_topology_t topology __hwloc_attribute_unused, void *addr, size_t len __hwloc_attribute_unused) { + if (!addr) + return 0; + if (!VirtualFreeExProc(GetCurrentProcess(), addr, 0, MEM_RELEASE)) + return -1; + return 0; +} + +static int hwloc_win_get_QueryWorkingSetExProc(void) { + if (QueryWorkingSetExProc == NULL) { + FARPROC fun = NULL; + HMODULE kernel32, psapi; + + kernel32 = LoadLibrary("kernel32.dll"); + if (kernel32) + fun = GetProcAddress(kernel32, "K32QueryWorkingSetEx"); + if (!fun) { + psapi = LoadLibrary("psapi.dll"); + if (psapi) + fun = GetProcAddress(psapi, "QueryWorkingSetEx"); + } + + if (!fun) { + QueryWorkingSetExProc = (FARPROC) -1; + errno = ENOSYS; + return -1; + } + + QueryWorkingSetExProc = fun; + } else if ((FARPROC) QueryWorkingSetExProc == (FARPROC)-1) { + errno = ENOSYS; + return -1; + } + + return 0; +} + +static int +hwloc_win_get_area_membind(hwloc_topology_t topology __hwloc_attribute_unused, const void *addr, size_t len, hwloc_nodeset_t nodeset, hwloc_membind_policy_t * policy, int flags) +{ + SYSTEM_INFO SystemInfo; + DWORD page_size; + uintptr_t start; + unsigned nb; + + GetSystemInfo(&SystemInfo); + page_size = SystemInfo.dwPageSize; + + start = (((uintptr_t) addr) / page_size) * page_size; + nb = (((uintptr_t) addr + len - start) + page_size - 1) / page_size; + + if (!nb) + nb = 1; + + { + PSAPI_WORKING_SET_EX_INFORMATION *pv; + unsigned i; + + pv = calloc(nb, sizeof(*pv)); + + for (i = 0; i < nb; i++) + pv[i].VirtualAddress = (void*) (start + i * page_size); + if (!QueryWorkingSetExProc(GetCurrentProcess(), pv, nb * sizeof(*pv))) { + free(pv); + return -1; + } + *policy = HWLOC_MEMBIND_BIND; + if (flags & HWLOC_MEMBIND_STRICT) { + unsigned node = pv[0].VirtualAttributes.Node; + for (i = 1; i < nb; i++) { + if (pv[i].VirtualAttributes.Node != node) { + errno = EXDEV; + free(pv); + return -1; + } + } + hwloc_bitmap_only(nodeset, node); + free(pv); + return 0; + } + hwloc_bitmap_zero(nodeset); + for (i = 0; i < nb; i++) + hwloc_bitmap_set(nodeset, pv[i].VirtualAttributes.Node); + free(pv); + return 0; + } +} + +static int +hwloc_look_windows(struct hwloc_backend *backend) +{ + struct hwloc_topology *topology = backend->topology; + BOOL (WINAPI *GetLogicalProcessorInformationProc)(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION Buffer, PDWORD ReturnLength); + BOOL (WINAPI *GetLogicalProcessorInformationExProc)(LOGICAL_PROCESSOR_RELATIONSHIP relationship, PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX Buffer, PDWORD ReturnLength); + BOOL (WINAPI *GetNumaAvailableMemoryNodeProc)(UCHAR Node, PULONGLONG AvailableBytes); + BOOL (WINAPI *GetNumaAvailableMemoryNodeExProc)(USHORT Node, PULONGLONG AvailableBytes); + SYSTEM_INFO SystemInfo; + + DWORD length; + + HMODULE kernel32; + + if (topology->levels[0][0]->cpuset) + /* somebody discovered things */ + return 0; + + hwloc_alloc_obj_cpusets(topology->levels[0][0]); + + GetSystemInfo(&SystemInfo); + + kernel32 = LoadLibrary("kernel32.dll"); + if (kernel32) { + GetLogicalProcessorInformationProc = GetProcAddress(kernel32, "GetLogicalProcessorInformation"); + GetNumaAvailableMemoryNodeProc = GetProcAddress(kernel32, "GetNumaAvailableMemoryNode"); + GetNumaAvailableMemoryNodeExProc = GetProcAddress(kernel32, "GetNumaAvailableMemoryNodeEx"); + GetLogicalProcessorInformationExProc = GetProcAddress(kernel32, "GetLogicalProcessorInformationEx"); + + if (!GetLogicalProcessorInformationExProc && GetLogicalProcessorInformationProc) { + PSYSTEM_LOGICAL_PROCESSOR_INFORMATION procInfo; + unsigned id; + unsigned i; + struct hwloc_obj *obj; + hwloc_obj_type_t type; + + length = 0; + procInfo = NULL; + + while (1) { + if (GetLogicalProcessorInformationProc(procInfo, &length)) + break; + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) + return -1; + procInfo = realloc(procInfo, length); + } + + assert(!length || procInfo); + + for (i = 0; i < length / sizeof(*procInfo); i++) { + + /* Ignore unknown caches */ + if (procInfo->Relationship == RelationCache + && procInfo->Cache.Type != CacheUnified + && procInfo->Cache.Type != CacheData + && procInfo->Cache.Type != CacheInstruction) + continue; + + id = -1; + switch (procInfo[i].Relationship) { + case RelationNumaNode: + type = HWLOC_OBJ_NUMANODE; + id = procInfo[i].NumaNode.NodeNumber; + break; + case RelationProcessorPackage: + type = HWLOC_OBJ_PACKAGE; + break; + case RelationCache: + type = HWLOC_OBJ_CACHE; + break; + case RelationProcessorCore: + type = HWLOC_OBJ_CORE; + break; + case RelationGroup: + default: + type = HWLOC_OBJ_GROUP; + break; + } + + obj = hwloc_alloc_setup_object(type, id); + obj->cpuset = hwloc_bitmap_alloc(); + hwloc_debug("%s#%u mask %lx\n", hwloc_obj_type_string(type), id, procInfo[i].ProcessorMask); + /* ProcessorMask is a ULONG_PTR */ + hwloc_bitmap_set_ith_ULONG_PTR(obj->cpuset, 0, procInfo[i].ProcessorMask); + hwloc_debug_2args_bitmap("%s#%u bitmap %s\n", hwloc_obj_type_string(type), id, obj->cpuset); + + switch (type) { + case HWLOC_OBJ_NUMANODE: + { + ULONGLONG avail; + obj->nodeset = hwloc_bitmap_alloc(); + hwloc_bitmap_set(obj->nodeset, id); + if ((GetNumaAvailableMemoryNodeExProc && GetNumaAvailableMemoryNodeExProc(id, &avail)) + || (GetNumaAvailableMemoryNodeProc && GetNumaAvailableMemoryNodeProc(id, &avail))) + obj->memory.local_memory = avail; + obj->memory.page_types_len = 2; + obj->memory.page_types = malloc(2 * sizeof(*obj->memory.page_types)); + memset(obj->memory.page_types, 0, 2 * sizeof(*obj->memory.page_types)); + obj->memory.page_types_len = 1; + obj->memory.page_types[0].size = SystemInfo.dwPageSize; +#ifdef HAVE__SC_LARGE_PAGESIZE + obj->memory.page_types_len++; + obj->memory.page_types[1].size = sysconf(_SC_LARGE_PAGESIZE); +#endif + break; + } + case HWLOC_OBJ_CACHE: + obj->attr->cache.size = procInfo[i].Cache.Size; + obj->attr->cache.associativity = procInfo[i].Cache.Associativity == CACHE_FULLY_ASSOCIATIVE ? -1 : procInfo[i].Cache.Associativity ; + obj->attr->cache.linesize = procInfo[i].Cache.LineSize; + obj->attr->cache.depth = procInfo[i].Cache.Level; + switch (procInfo->Cache.Type) { + case CacheUnified: + obj->attr->cache.type = HWLOC_OBJ_CACHE_UNIFIED; + break; + case CacheData: + obj->attr->cache.type = HWLOC_OBJ_CACHE_DATA; + break; + case CacheInstruction: + obj->attr->cache.type = HWLOC_OBJ_CACHE_INSTRUCTION; + break; + default: + hwloc_free_unlinked_object(obj); + continue; + } + break; + case HWLOC_OBJ_GROUP: + obj->attr->group.depth = procInfo[i].Relationship == RelationGroup; + break; + default: + break; + } + hwloc_insert_object_by_cpuset(topology, obj); + } + + free(procInfo); + } + + if (GetLogicalProcessorInformationExProc) { + PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX procInfoTotal, procInfo; + + unsigned id; + struct hwloc_obj *obj; + hwloc_obj_type_t type; + + length = 0; + procInfoTotal = NULL; + + while (1) { + if (GetLogicalProcessorInformationExProc(RelationAll, procInfoTotal, &length)) + break; + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) + return -1; + procInfoTotal = realloc(procInfoTotal, length); + } + + for (procInfo = procInfoTotal; + (void*) procInfo < (void*) ((uintptr_t) procInfoTotal + length); + procInfo = (void*) ((uintptr_t) procInfo + procInfo->Size)) { + unsigned num, i; + GROUP_AFFINITY *GroupMask; + + /* Ignore unknown caches */ + if (procInfo->Relationship == RelationCache + && procInfo->Cache.Type != CacheUnified + && procInfo->Cache.Type != CacheData + && procInfo->Cache.Type != CacheInstruction) + continue; + + id = -1; + switch (procInfo->Relationship) { + case RelationNumaNode: + type = HWLOC_OBJ_NUMANODE; + num = 1; + GroupMask = &procInfo->NumaNode.GroupMask; + id = procInfo->NumaNode.NodeNumber; + break; + case RelationProcessorPackage: + type = HWLOC_OBJ_PACKAGE; + num = procInfo->Processor.GroupCount; + GroupMask = procInfo->Processor.GroupMask; + break; + case RelationCache: + type = HWLOC_OBJ_CACHE; + num = 1; + GroupMask = &procInfo->Cache.GroupMask; + break; + case RelationProcessorCore: + type = HWLOC_OBJ_CORE; + num = procInfo->Processor.GroupCount; + GroupMask = procInfo->Processor.GroupMask; + break; + case RelationGroup: + /* So strange an interface... */ + for (id = 0; id < procInfo->Group.ActiveGroupCount; id++) { + KAFFINITY mask; + obj = hwloc_alloc_setup_object(HWLOC_OBJ_GROUP, id); + obj->cpuset = hwloc_bitmap_alloc(); + mask = procInfo->Group.GroupInfo[id].ActiveProcessorMask; + hwloc_debug("group %u %d cpus mask %lx\n", id, + procInfo->Group.GroupInfo[id].ActiveProcessorCount, mask); + /* KAFFINITY is ULONG_PTR */ + hwloc_bitmap_set_ith_ULONG_PTR(obj->cpuset, id, mask); + hwloc_debug_2args_bitmap("group %u %d bitmap %s\n", id, procInfo->Group.GroupInfo[id].ActiveProcessorCount, obj->cpuset); + hwloc_insert_object_by_cpuset(topology, obj); + } + continue; + default: + /* Don't know how to get the mask. */ + hwloc_debug("unknown relation %d\n", procInfo->Relationship); + continue; + } + + obj = hwloc_alloc_setup_object(type, id); + obj->cpuset = hwloc_bitmap_alloc(); + for (i = 0; i < num; i++) { + hwloc_debug("%s#%u %d: mask %d:%lx\n", hwloc_obj_type_string(type), id, i, GroupMask[i].Group, GroupMask[i].Mask); + /* GROUP_AFFINITY.Mask is KAFFINITY, which is ULONG_PTR */ + hwloc_bitmap_set_ith_ULONG_PTR(obj->cpuset, GroupMask[i].Group, GroupMask[i].Mask); + } + hwloc_debug("%s#%u bitmap %s\n", hwloc_obj_type_string(type), id, obj->cpuset); + + switch (type) { + case HWLOC_OBJ_NUMANODE: + { + ULONGLONG avail; + obj->nodeset = hwloc_bitmap_alloc(); + hwloc_bitmap_set(obj->nodeset, id); + if ((GetNumaAvailableMemoryNodeExProc && GetNumaAvailableMemoryNodeExProc(id, &avail)) + || (GetNumaAvailableMemoryNodeProc && GetNumaAvailableMemoryNodeProc(id, &avail))) + obj->memory.local_memory = avail; + obj->memory.page_types = malloc(2 * sizeof(*obj->memory.page_types)); + memset(obj->memory.page_types, 0, 2 * sizeof(*obj->memory.page_types)); + obj->memory.page_types_len = 1; + obj->memory.page_types[0].size = SystemInfo.dwPageSize; +#ifdef HAVE__SC_LARGE_PAGESIZE + obj->memory.page_types_len++; + obj->memory.page_types[1].size = sysconf(_SC_LARGE_PAGESIZE); +#endif + break; + } + case HWLOC_OBJ_CACHE: + obj->attr->cache.size = procInfo->Cache.CacheSize; + obj->attr->cache.associativity = procInfo->Cache.Associativity == CACHE_FULLY_ASSOCIATIVE ? -1 : procInfo->Cache.Associativity ; + obj->attr->cache.linesize = procInfo->Cache.LineSize; + obj->attr->cache.depth = procInfo->Cache.Level; + switch (procInfo->Cache.Type) { + case CacheUnified: + obj->attr->cache.type = HWLOC_OBJ_CACHE_UNIFIED; + break; + case CacheData: + obj->attr->cache.type = HWLOC_OBJ_CACHE_DATA; + break; + case CacheInstruction: + obj->attr->cache.type = HWLOC_OBJ_CACHE_INSTRUCTION; + break; + default: + hwloc_free_unlinked_object(obj); + continue; + } + break; + default: + break; + } + hwloc_insert_object_by_cpuset(topology, obj); + } + free(procInfoTotal); + } + } + + /* add PU objects */ + hwloc_setup_pu_level(topology, hwloc_fallback_nbprocessors(topology)); + + hwloc_obj_add_info(topology->levels[0][0], "Backend", "Windows"); + if (topology->is_thissystem) + hwloc_add_uname_info(topology, NULL); + return 1; +} + +void +hwloc_set_windows_hooks(struct hwloc_binding_hooks *hooks, + struct hwloc_topology_support *support) +{ + hooks->set_proc_cpubind = hwloc_win_set_proc_cpubind; + hooks->get_proc_cpubind = hwloc_win_get_proc_cpubind; + hooks->set_thread_cpubind = hwloc_win_set_thread_cpubind; + hooks->set_thisproc_cpubind = hwloc_win_set_thisproc_cpubind; + hooks->get_thisproc_cpubind = hwloc_win_get_thisproc_cpubind; + hooks->set_thisthread_cpubind = hwloc_win_set_thisthread_cpubind; + /* TODO: get_last_cpu_location: use GetCurrentProcessorNumber */ + + hooks->set_proc_membind = hwloc_win_set_proc_membind; + hooks->get_proc_membind = hwloc_win_get_proc_membind; + hooks->set_thisproc_membind = hwloc_win_set_thisproc_membind; + hooks->get_thisproc_membind = hwloc_win_get_thisproc_membind; + hooks->set_thisthread_membind = hwloc_win_set_thisthread_membind; + + if (!hwloc_win_get_VirtualAllocExNumaProc()) { + hooks->alloc_membind = hwloc_win_alloc_membind; + hooks->alloc = hwloc_win_alloc; + hooks->free_membind = hwloc_win_free_membind; + support->membind->bind_membind = 1; + } + + if (!hwloc_win_get_QueryWorkingSetExProc()) + hooks->get_area_membind = hwloc_win_get_area_membind; +} + +static struct hwloc_backend * +hwloc_windows_component_instantiate(struct hwloc_disc_component *component, + const void *_data1 __hwloc_attribute_unused, + const void *_data2 __hwloc_attribute_unused, + const void *_data3 __hwloc_attribute_unused) +{ + struct hwloc_backend *backend; + backend = hwloc_backend_alloc(component); + if (!backend) + return NULL; + backend->discover = hwloc_look_windows; + return backend; +} + +static struct hwloc_disc_component hwloc_windows_disc_component = { + HWLOC_DISC_COMPONENT_TYPE_CPU, + "windows", + HWLOC_DISC_COMPONENT_TYPE_GLOBAL, + hwloc_windows_component_instantiate, + 50, + NULL +}; + +const struct hwloc_component hwloc_windows_component = { + HWLOC_COMPONENT_ABI, + NULL, NULL, + HWLOC_COMPONENT_TYPE_DISC, + 0, + &hwloc_windows_disc_component +}; diff --git a/opal/mca/hwloc/hwloc1110/hwloc/src/topology-x86.c b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-x86.c new file mode 100644 index 0000000000..db91a5ef6d --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-x86.c @@ -0,0 +1,1104 @@ +/* + * Copyright © 2010-2015 Inria. All rights reserved. + * Copyright © 2010-2013 Université Bordeaux + * Copyright © 2010-2011 Cisco Systems, Inc. All rights reserved. + * See COPYING in top-level directory. + * + * + * This backend is only used when the operating system does not export + * the necessary hardware topology information to user-space applications. + * Currently, only the FreeBSD backend relies on this x86 backend. + * + * Other backends such as Linux have their own way to retrieve various + * pieces of hardware topology information from the operating system + * on various architectures, without having to use this x86-specific code. + */ + +#include +#include +#include +#include +#include + +#include + +struct hwloc_x86_backend_data_s { + unsigned nbprocs; + hwloc_bitmap_t apicid_set; + int apicid_unique; +}; + +#define has_topoext(features) ((features)[6] & (1 << 22)) +#define has_x2apic(features) ((features)[4] & (1 << 21)) + +struct cacheinfo { + unsigned type; + unsigned level; + unsigned nbthreads_sharing; + + unsigned linesize; + unsigned linepart; + int ways; + unsigned sets; + unsigned long size; +}; + +struct procinfo { + unsigned present; + unsigned apicid; + unsigned max_log_proc; + unsigned max_nbcores; + unsigned max_nbthreads; + unsigned packageid; + unsigned nodeid; + unsigned unitid; + unsigned logprocid; + unsigned threadid; + unsigned coreid; + unsigned *otherids; + unsigned levels; + unsigned numcaches; + struct cacheinfo *cache; + char cpuvendor[13]; + char cpumodel[3*4*4+1]; + unsigned cpustepping; + unsigned cpumodelnumber; + unsigned cpufamilynumber; +}; + +enum cpuid_type { + intel, + amd, + unknown +}; + +static void fill_amd_cache(struct procinfo *infos, unsigned level, int type, unsigned cpuid) +{ + struct cacheinfo *cache; + unsigned cachenum; + unsigned long size = 0; + + if (level == 1) + size = ((cpuid >> 24)) << 10; + else if (level == 2) + size = ((cpuid >> 16)) << 10; + else if (level == 3) + size = ((cpuid >> 18)) << 19; + if (!size) + return; + + cachenum = infos->numcaches++; + infos->cache = realloc(infos->cache, infos->numcaches*sizeof(*infos->cache)); + cache = &infos->cache[cachenum]; + + cache->type = type; + cache->level = level; + if (level <= 2) + cache->nbthreads_sharing = 1; + else + cache->nbthreads_sharing = infos->max_log_proc; + cache->linesize = cpuid & 0xff; + cache->linepart = 0; + if (level == 1) { + cache->ways = (cpuid >> 16) & 0xff; + if (cache->ways == 0xff) + /* Fully associative */ + cache->ways = -1; + } else { + static const unsigned ways_tab[] = { 0, 1, 2, 0, 4, 0, 8, 0, 16, 0, 32, 48, 64, 96, 128, -1 }; + unsigned ways = (cpuid >> 12) & 0xf; + cache->ways = ways_tab[ways]; + } + cache->size = size; + cache->sets = 0; + + hwloc_debug("cache L%u t%u linesize %u ways %u size %luKB\n", cache->level, cache->nbthreads_sharing, cache->linesize, cache->ways, cache->size >> 10); +} + +/* Fetch information from the processor itself thanks to cpuid and store it in + * infos for summarize to analyze them globally */ +static void look_proc(struct hwloc_backend *backend, struct procinfo *infos, unsigned highest_cpuid, unsigned highest_ext_cpuid, unsigned *features, enum cpuid_type cpuid_type) +{ + struct hwloc_x86_backend_data_s *data = backend->private_data; + unsigned eax, ebx, ecx = 0, edx; + unsigned cachenum; + struct cacheinfo *cache; + unsigned regs[4]; + unsigned _model, _extendedmodel, _family, _extendedfamily; + + infos->present = 1; + + /* on return from this function, the following fields must be set in infos: + * packageid, nodeid, unitid, coreid, threadid, or -1 + * apicid + * levels and levels slots in otherids[] + * numcaches and numcaches slots in caches[] + * + * max_log_proc, max_nbthreads, max_nbcores, logprocid + * are only used temporarily inside this function and its callees. + */ + + /* Get apicid, max_log_proc, packageid, logprocid from cpuid 0x01 */ + eax = 0x01; + hwloc_x86_cpuid(&eax, &ebx, &ecx, &edx); + infos->apicid = ebx >> 24; + if (edx & (1 << 28)) + infos->max_log_proc = 1 << hwloc_flsl(((ebx >> 16) & 0xff) - 1); + else + infos->max_log_proc = 1; + hwloc_debug("APIC ID 0x%02x max_log_proc %u\n", infos->apicid, infos->max_log_proc); + infos->packageid = infos->apicid / infos->max_log_proc; + infos->logprocid = infos->apicid % infos->max_log_proc; + hwloc_debug("phys %u thread %u\n", infos->packageid, infos->logprocid); + + /* Get cpu model/family/stepping numbers from same cpuid */ + _model = (eax>>4) & 0xf; + _extendedmodel = (eax>>16) & 0xf; + _family = (eax>>8) & 0xf; + _extendedfamily = (eax>>20) & 0xff; + if ((cpuid_type == intel || cpuid_type == amd) && _family == 0xf) { + infos->cpufamilynumber = _family + _extendedfamily; + } else { + infos->cpufamilynumber = _family; + } + if ((cpuid_type == intel && (_family == 0x6 || _family == 0xf)) + || (cpuid_type == amd && _family == 0xf)) { + infos->cpumodelnumber = _model + (_extendedmodel << 4); + } else { + infos->cpumodelnumber = _model; + } + infos->cpustepping = eax & 0xf; + + /* Get cpu vendor string from cpuid 0x00 */ + memset(regs, 0, sizeof(regs)); + regs[0] = 0; + hwloc_x86_cpuid(®s[0], ®s[1], ®s[3], ®s[2]); + memcpy(infos->cpuvendor, regs+1, 4*3); + /* infos was calloc'ed, already ends with \0 */ + + /* Get cpu model string from cpuid 0x80000002-4 */ + if (highest_ext_cpuid >= 0x80000004) { + memset(regs, 0, sizeof(regs)); + regs[0] = 0x80000002; + hwloc_x86_cpuid(®s[0], ®s[1], ®s[2], ®s[3]); + memcpy(infos->cpumodel, regs, 4*4); + regs[0] = 0x80000003; + hwloc_x86_cpuid(®s[0], ®s[1], ®s[2], ®s[3]); + memcpy(infos->cpumodel + 4*4, regs, 4*4); + regs[0] = 0x80000004; + hwloc_x86_cpuid(®s[0], ®s[1], ®s[2], ®s[3]); + memcpy(infos->cpumodel + 4*4*2, regs, 4*4); + /* infos was calloc'ed, already ends with \0 */ + } + + /* Get core/thread information from cpuid 0x80000008 + * (not supported on Intel) + */ + if (cpuid_type != intel && highest_ext_cpuid >= 0x80000008) { + unsigned coreidsize; + eax = 0x80000008; + hwloc_x86_cpuid(&eax, &ebx, &ecx, &edx); + coreidsize = (ecx >> 12) & 0xf; + hwloc_debug("core ID size: %u\n", coreidsize); + if (!coreidsize) { + infos->max_nbcores = (ecx & 0xff) + 1; + } else + infos->max_nbcores = 1 << coreidsize; + hwloc_debug("Thus max # of cores: %u\n", infos->max_nbcores); + /* Still no multithreaded AMD */ + infos->max_nbthreads = 1 ; + hwloc_debug("and max # of threads: %u\n", infos->max_nbthreads); + /* The legacy max_log_proc is deprecated, it can be smaller than max_nbcores, + * which is the maximum number of cores that the processor could theoretically support + * (see "Multiple Core Calculation" in the AMD CPUID specification). + * Recompute packageid/logprocid/threadid/coreid accordingly. + */ + infos->packageid = infos->apicid / infos->max_nbcores; + infos->logprocid = infos->apicid % infos->max_nbcores; + infos->threadid = infos->logprocid % infos->max_nbthreads; + infos->coreid = infos->logprocid / infos->max_nbthreads; + hwloc_debug("this is thread %u of core %u\n", infos->threadid, infos->coreid); + } + + infos->numcaches = 0; + infos->cache = NULL; + + /* Get apicid, nodeid, unitid from cpuid 0x8000001e + * and cache information from cpuid 0x8000001d + * (AMD topology extension) + */ + if (cpuid_type != intel && has_topoext(features)) { + unsigned apic_id, node_id, nodes_per_proc, unit_id, cores_per_unit; + + eax = 0x8000001e; + hwloc_x86_cpuid(&eax, &ebx, &ecx, &edx); + infos->apicid = apic_id = eax; + infos->nodeid = node_id = ecx & 0xff; + nodes_per_proc = ((ecx >> 8) & 7) + 1; + if (nodes_per_proc > 2) { + hwloc_debug("warning: undefined value %d, assuming it means %d\n", nodes_per_proc, nodes_per_proc); + } + infos->unitid = unit_id = ebx & 0xff; + cores_per_unit = ((ebx >> 8) & 3) + 1; + hwloc_debug("x2APIC %08x, %d nodes, node %d, %d cores in unit %d\n", apic_id, nodes_per_proc, node_id, cores_per_unit, unit_id); + + for (cachenum = 0; ; cachenum++) { + unsigned type; + eax = 0x8000001d; + ecx = cachenum; + hwloc_x86_cpuid(&eax, &ebx, &ecx, &edx); + type = eax & 0x1f; + if (type == 0) + break; + infos->numcaches++; + } + + cache = infos->cache = malloc(infos->numcaches * sizeof(*infos->cache)); + + for (cachenum = 0; ; cachenum++) { + unsigned long linesize, linepart, ways, sets; + unsigned type; + eax = 0x8000001d; + ecx = cachenum; + hwloc_x86_cpuid(&eax, &ebx, &ecx, &edx); + + type = eax & 0x1f; + + if (type == 0) + break; + + cache->type = type; + cache->level = (eax >> 5) & 0x7; + /* Note: actually number of cores */ + cache->nbthreads_sharing = ((eax >> 14) & 0xfff) + 1; + + cache->linesize = linesize = (ebx & 0xfff) + 1; + cache->linepart = linepart = ((ebx >> 12) & 0x3ff) + 1; + ways = ((ebx >> 22) & 0x3ff) + 1; + + if (eax & (1 << 9)) + /* Fully associative */ + cache->ways = -1; + else + cache->ways = ways; + cache->sets = sets = ecx + 1; + cache->size = linesize * linepart * ways * sets; + + hwloc_debug("cache %u type %u L%u t%u c%u linesize %lu linepart %lu ways %lu sets %lu, size %uKB\n", cachenum, cache->type, cache->level, cache->nbthreads_sharing, infos->max_nbcores, linesize, linepart, ways, sets, cache->size >> 10); + + cache++; + } + } else { + /* If there's no topoext, + * get cache information from cpuid 0x80000005 and 0x80000006 + * (not supported on Intel) + */ + if (cpuid_type != intel && highest_ext_cpuid >= 0x80000005) { + eax = 0x80000005; + hwloc_x86_cpuid(&eax, &ebx, &ecx, &edx); + fill_amd_cache(infos, 1, 1, ecx); /* L1d */ + fill_amd_cache(infos, 1, 2, edx); /* L1i */ + } + if (cpuid_type != intel && highest_ext_cpuid >= 0x80000006) { + eax = 0x80000006; + hwloc_x86_cpuid(&eax, &ebx, &ecx, &edx); + if (ecx & 0xf000) + /* This is actually supported on Intel but LinePerTag isn't returned in bits 8-11. + * Could be useful if some Intels (at least before Core micro-architecture) + * support this leaf without leaf 0x4. + */ + fill_amd_cache(infos, 2, 3, ecx); /* L2u */ + if (edx & 0xf000) + fill_amd_cache(infos, 3, 3, edx); /* L3u */ + /* FIXME: AMD MagnyCours family 0x10 model 0x9 with 8 cores or more actually + * have the L3 split in two halves, and associativity is divided as well (48) + */ + } + } + + /* Get thread/core + cache information from cpuid 0x04 + * (not supported on AMD) + */ + if (cpuid_type != amd && highest_cpuid >= 0x04) { + for (cachenum = 0; ; cachenum++) { + unsigned type; + eax = 0x04; + ecx = cachenum; + hwloc_x86_cpuid(&eax, &ebx, &ecx, &edx); + + type = eax & 0x1f; + + hwloc_debug("cache %u type %u\n", cachenum, type); + + if (type == 0) + break; + infos->numcaches++; + + if (!cachenum) { + /* by the way, get thread/core information from the first cache */ + infos->max_nbcores = ((eax >> 26) & 0x3f) + 1; + infos->max_nbthreads = infos->max_log_proc / infos->max_nbcores; + hwloc_debug("thus %u threads\n", infos->max_nbthreads); + infos->threadid = infos->logprocid % infos->max_nbthreads; + infos->coreid = infos->logprocid / infos->max_nbthreads; + hwloc_debug("this is thread %u of core %u\n", infos->threadid, infos->coreid); + } + } + + cache = infos->cache = malloc(infos->numcaches * sizeof(*infos->cache)); + + for (cachenum = 0; ; cachenum++) { + unsigned long linesize, linepart, ways, sets; + unsigned type; + eax = 0x04; + ecx = cachenum; + hwloc_x86_cpuid(&eax, &ebx, &ecx, &edx); + + type = eax & 0x1f; + + if (type == 0) + break; + + cache->type = type; + cache->level = (eax >> 5) & 0x7; + cache->nbthreads_sharing = ((eax >> 14) & 0xfff) + 1; + + cache->linesize = linesize = (ebx & 0xfff) + 1; + cache->linepart = linepart = ((ebx >> 12) & 0x3ff) + 1; + ways = ((ebx >> 22) & 0x3ff) + 1; + if (eax & (1 << 9)) + /* Fully associative */ + cache->ways = -1; + else + cache->ways = ways; + cache->sets = sets = ecx + 1; + cache->size = linesize * linepart * ways * sets; + + hwloc_debug("cache %u type %u L%u t%u c%u linesize %lu linepart %lu ways %lu sets %lu, size %uKB\n", cachenum, cache->type, cache->level, cache->nbthreads_sharing, infos->max_nbcores, linesize, linepart, ways, sets, cache->size >> 10); + + cache++; + } + } + + /* Get package/core/thread information from cpuid 0x0b + * (Intel x2APIC) + */ + if (cpuid_type == intel && has_x2apic(features)) { + unsigned level, apic_nextshift, apic_number, apic_type, apic_id = 0, apic_shift = 0, id; + for (level = 0; ; level++) { + ecx = level; + eax = 0x0b; + hwloc_x86_cpuid(&eax, &ebx, &ecx, &edx); + if (!eax && !ebx) + break; + } + if (level) { + infos->levels = level; + infos->otherids = malloc(level * sizeof(*infos->otherids)); + for (level = 0; ; level++) { + ecx = level; + eax = 0x0b; + hwloc_x86_cpuid(&eax, &ebx, &ecx, &edx); + if (!eax && !ebx) + break; + apic_nextshift = eax & 0x1f; + apic_number = ebx & 0xffff; + apic_type = (ecx & 0xff00) >> 8; + apic_id = edx; + id = (apic_id >> apic_shift) & ((1 << (apic_nextshift - apic_shift)) - 1); + hwloc_debug("x2APIC %08x %d: nextshift %d num %2d type %d id %2d\n", apic_id, level, apic_nextshift, apic_number, apic_type, id); + infos->apicid = apic_id; + infos->otherids[level] = UINT_MAX; + switch (apic_type) { + case 1: + infos->threadid = id; + break; + case 2: + infos->coreid = id; + break; + default: + hwloc_debug("x2APIC %d: unknown type %d\n", level, apic_type); + infos->otherids[level] = apic_id >> apic_shift; + break; + } + apic_shift = apic_nextshift; + } + infos->apicid = apic_id; + infos->packageid = apic_id >> apic_shift; + hwloc_debug("x2APIC remainder: %d\n", infos->packageid); + hwloc_debug("this is thread %u of core %u\n", infos->threadid, infos->coreid); + } + } + + if (hwloc_bitmap_isset(data->apicid_set, infos->apicid)) + data->apicid_unique = 0; + else + hwloc_bitmap_set(data->apicid_set, infos->apicid); +} + +static void +hwloc_x86_add_cpuinfos(hwloc_obj_t obj, struct procinfo *info, int nodup) +{ + char number[8]; + hwloc_obj_add_info_nodup(obj, "CPUVendor", info->cpuvendor, nodup); + snprintf(number, sizeof(number), "%u", info->cpufamilynumber); + hwloc_obj_add_info_nodup(obj, "CPUFamilyNumber", number, nodup); + snprintf(number, sizeof(number), "%u", info->cpumodelnumber); + hwloc_obj_add_info_nodup(obj, "CPUModelNumber", number, nodup); + if (info->cpumodel[0]) { + const char *c = info->cpumodel; + while (*c == ' ') + c++; + hwloc_obj_add_info_nodup(obj, "CPUModel", c, nodup); + } + snprintf(number, sizeof(number), "%u", info->cpustepping); + hwloc_obj_add_info_nodup(obj, "CPUStepping", number, nodup); +} + +/* Analyse information stored in infos, and build/annotate topology levels accordingly */ +static void summarize(struct hwloc_backend *backend, struct procinfo *infos, int fulldiscovery) +{ + struct hwloc_topology *topology = backend->topology; + struct hwloc_x86_backend_data_s *data = backend->private_data; + unsigned nbprocs = data->nbprocs; + hwloc_bitmap_t complete_cpuset = hwloc_bitmap_alloc(); + unsigned i, j, l, level, type; + unsigned nbpackages = 0; + int one = -1; + unsigned next_group_depth = topology->next_group_depth; + + for (i = 0; i < nbprocs; i++) + if (infos[i].present) { + hwloc_bitmap_set(complete_cpuset, i); + one = i; + } + + if (one == -1) { + hwloc_bitmap_free(complete_cpuset); + return; + } + + /* Ideally, when fulldiscovery=0, we could add any object that doesn't exist yet. + * But what if the x86 and the native backends disagree because one is buggy? Which one to trust? + * Only annotate existing objects for now. + */ + + /* Look for packages */ + if (fulldiscovery) { + hwloc_bitmap_t packages_cpuset = hwloc_bitmap_dup(complete_cpuset); + hwloc_bitmap_t package_cpuset; + hwloc_obj_t package; + + while ((i = hwloc_bitmap_first(packages_cpuset)) != (unsigned) -1) { + unsigned packageid = infos[i].packageid; + + package_cpuset = hwloc_bitmap_alloc(); + for (j = i; j < nbprocs; j++) { + if (infos[j].packageid == packageid) { + hwloc_bitmap_set(package_cpuset, j); + hwloc_bitmap_clr(packages_cpuset, j); + } + } + package = hwloc_alloc_setup_object(HWLOC_OBJ_PACKAGE, packageid); + package->cpuset = package_cpuset; + + hwloc_x86_add_cpuinfos(package, &infos[i], 0); + + hwloc_debug_1arg_bitmap("os package %u has cpuset %s\n", + packageid, package_cpuset); + hwloc_insert_object_by_cpuset(topology, package); + nbpackages++; + } + hwloc_bitmap_free(packages_cpuset); + + } else { + /* Annotate packages previously-existing packages */ + hwloc_obj_t package = NULL; + int same = 1; + nbpackages = hwloc_get_nbobjs_by_type(topology, HWLOC_OBJ_PACKAGE); + /* check whether all packages have the same info */ + for(i=1; ios_index == (unsigned) -1) { + /* try to fix the package OS index if unknown. + * FIXME: ideally, we should check all bits in case x86 and the native backend disagree. + */ + for(i=0; icpuset, i)) { + package->os_index = infos[i].packageid; + break; + } + } + } + for(i=0; ios_index || (same && package->os_index == (unsigned) -1)) { + hwloc_x86_add_cpuinfos(package, &infos[i], 1); + break; + } + } + } + } + /* If there was no package, annotate the Machine instead */ + if ((!nbpackages) && infos[0].cpumodel[0]) { + hwloc_x86_add_cpuinfos(hwloc_get_root_obj(topology), &infos[0], 1); + } + + /* Look for Numa nodes inside packages */ + if (fulldiscovery) { + hwloc_bitmap_t nodes_cpuset = hwloc_bitmap_dup(complete_cpuset); + hwloc_bitmap_t node_cpuset; + hwloc_obj_t node; + + while ((i = hwloc_bitmap_first(nodes_cpuset)) != (unsigned) -1) { + unsigned packageid = infos[i].packageid; + unsigned nodeid = infos[i].nodeid; + + if (nodeid == (unsigned)-1) { + hwloc_bitmap_clr(nodes_cpuset, i); + continue; + } + + node_cpuset = hwloc_bitmap_alloc(); + for (j = i; j < nbprocs; j++) { + if (infos[j].nodeid == (unsigned) -1) { + hwloc_bitmap_clr(nodes_cpuset, j); + continue; + } + + if (infos[j].packageid == packageid && infos[j].nodeid == nodeid) { + hwloc_bitmap_set(node_cpuset, j); + hwloc_bitmap_clr(nodes_cpuset, j); + } + } + node = hwloc_alloc_setup_object(HWLOC_OBJ_NUMANODE, nodeid); + node->cpuset = node_cpuset; + node->nodeset = hwloc_bitmap_alloc(); + hwloc_bitmap_set(node->nodeset, nodeid); + hwloc_debug_1arg_bitmap("os node %u has cpuset %s\n", + nodeid, node_cpuset); + hwloc_insert_object_by_cpuset(topology, node); + } + hwloc_bitmap_free(nodes_cpuset); + } + + /* Look for Compute units inside packages */ + if (fulldiscovery) { + hwloc_bitmap_t units_cpuset = hwloc_bitmap_dup(complete_cpuset); + hwloc_bitmap_t unit_cpuset; + hwloc_obj_t unit; + + while ((i = hwloc_bitmap_first(units_cpuset)) != (unsigned) -1) { + unsigned packageid = infos[i].packageid; + unsigned unitid = infos[i].unitid; + + if (unitid == (unsigned)-1) { + hwloc_bitmap_clr(units_cpuset, i); + continue; + } + + unit_cpuset = hwloc_bitmap_alloc(); + for (j = i; j < nbprocs; j++) { + if (infos[j].unitid == (unsigned) -1) { + hwloc_bitmap_clr(units_cpuset, j); + continue; + } + + if (infos[j].packageid == packageid && infos[j].unitid == unitid) { + hwloc_bitmap_set(unit_cpuset, j); + hwloc_bitmap_clr(units_cpuset, j); + } + } + unit = hwloc_alloc_setup_object(HWLOC_OBJ_GROUP, unitid); + unit->cpuset = unit_cpuset; + hwloc_debug_1arg_bitmap("os unit %u has cpuset %s\n", + unitid, unit_cpuset); + hwloc_insert_object_by_cpuset(topology, unit); + } + hwloc_bitmap_free(units_cpuset); + } + + /* Look for unknown objects */ + if (infos[one].otherids) { + for (level = infos[one].levels-1; level <= infos[one].levels-1; level--) { + if (infos[one].otherids[level] != UINT_MAX) { + hwloc_bitmap_t unknowns_cpuset = hwloc_bitmap_dup(complete_cpuset); + hwloc_bitmap_t unknown_cpuset; + hwloc_obj_t unknown_obj; + + while ((i = hwloc_bitmap_first(unknowns_cpuset)) != (unsigned) -1) { + unsigned unknownid = infos[i].otherids[level]; + + unknown_cpuset = hwloc_bitmap_alloc(); + for (j = i; j < nbprocs; j++) { + if (infos[j].otherids[level] == unknownid) { + hwloc_bitmap_set(unknown_cpuset, j); + hwloc_bitmap_clr(unknowns_cpuset, j); + } + } + unknown_obj = hwloc_alloc_setup_object(HWLOC_OBJ_GROUP, unknownid); + unknown_obj->cpuset = unknown_cpuset; + unknown_obj->os_level = level; + unknown_obj->attr->group.depth = topology->next_group_depth + level; + if (next_group_depth <= topology->next_group_depth + level) + next_group_depth = topology->next_group_depth + level + 1; + hwloc_debug_2args_bitmap("os unknown%d %u has cpuset %s\n", + level, unknownid, unknown_cpuset); + hwloc_insert_object_by_cpuset(topology, unknown_obj); + } + hwloc_bitmap_free(unknowns_cpuset); + } + } + } + + /* Look for cores */ + if (fulldiscovery) { + hwloc_bitmap_t cores_cpuset = hwloc_bitmap_dup(complete_cpuset); + hwloc_bitmap_t core_cpuset; + hwloc_obj_t core; + + while ((i = hwloc_bitmap_first(cores_cpuset)) != (unsigned) -1) { + unsigned packageid = infos[i].packageid; + unsigned coreid = infos[i].coreid; + + if (coreid == (unsigned) -1) { + hwloc_bitmap_clr(cores_cpuset, i); + continue; + } + + core_cpuset = hwloc_bitmap_alloc(); + for (j = i; j < nbprocs; j++) { + if (infos[j].coreid == (unsigned) -1) { + hwloc_bitmap_clr(cores_cpuset, j); + continue; + } + + if (infos[j].packageid == packageid && infos[j].coreid == coreid) { + hwloc_bitmap_set(core_cpuset, j); + hwloc_bitmap_clr(cores_cpuset, j); + } + } + core = hwloc_alloc_setup_object(HWLOC_OBJ_CORE, coreid); + core->cpuset = core_cpuset; + hwloc_debug_1arg_bitmap("os core %u has cpuset %s\n", + coreid, core_cpuset); + hwloc_insert_object_by_cpuset(topology, core); + } + hwloc_bitmap_free(cores_cpuset); + } + + /* Look for caches */ + /* First find max level */ + level = 0; + for (i = 0; i < nbprocs; i++) + for (j = 0; j < infos[i].numcaches; j++) + if (infos[i].cache[j].level > level) + level = infos[i].cache[j].level; + + /* Look for known types */ + if (fulldiscovery) while (level > 0) { + for (type = 1; type <= 3; type++) { + /* Look for caches of that type at level level */ + { + hwloc_bitmap_t caches_cpuset = hwloc_bitmap_dup(complete_cpuset); + hwloc_bitmap_t cache_cpuset; + hwloc_obj_t cache; + + while ((i = hwloc_bitmap_first(caches_cpuset)) != (unsigned) -1) { + unsigned packageid = infos[i].packageid; + + for (l = 0; l < infos[i].numcaches; l++) { + if (infos[i].cache[l].level == level && infos[i].cache[l].type == type) + break; + } + if (l == infos[i].numcaches) { + /* no cache Llevel of that type in i */ + hwloc_bitmap_clr(caches_cpuset, i); + continue; + } + + /* Found a matching cache, now look for others sharing it */ + { + unsigned cacheid = infos[i].apicid / infos[i].cache[l].nbthreads_sharing; + + cache_cpuset = hwloc_bitmap_alloc(); + for (j = i; j < nbprocs; j++) { + unsigned l2; + for (l2 = 0; l2 < infos[j].numcaches; l2++) { + if (infos[j].cache[l2].level == level && infos[j].cache[l2].type == type) + break; + } + if (l2 == infos[j].numcaches) { + /* no cache Llevel of that type in j */ + hwloc_bitmap_clr(caches_cpuset, j); + continue; + } + if (infos[j].packageid == packageid && infos[j].apicid / infos[j].cache[l2].nbthreads_sharing == cacheid) { + hwloc_bitmap_set(cache_cpuset, j); + hwloc_bitmap_clr(caches_cpuset, j); + } + } + cache = hwloc_alloc_setup_object(HWLOC_OBJ_CACHE, cacheid); + cache->attr->cache.depth = level; + cache->attr->cache.size = infos[i].cache[l].size; + cache->attr->cache.linesize = infos[i].cache[l].linesize; + cache->attr->cache.associativity = infos[i].cache[l].ways; + switch (infos[i].cache[l].type) { + case 1: + cache->attr->cache.type = HWLOC_OBJ_CACHE_DATA; + break; + case 2: + cache->attr->cache.type = HWLOC_OBJ_CACHE_INSTRUCTION; + break; + case 3: + cache->attr->cache.type = HWLOC_OBJ_CACHE_UNIFIED; + break; + } + cache->cpuset = cache_cpuset; + hwloc_debug_2args_bitmap("os L%u cache %u has cpuset %s\n", + level, cacheid, cache_cpuset); + hwloc_insert_object_by_cpuset(topology, cache); + } + } + hwloc_bitmap_free(caches_cpuset); + } + } + level--; + } + + for (i = 0; i < nbprocs; i++) { + free(infos[i].cache); + if (infos[i].otherids) + free(infos[i].otherids); + } + + hwloc_bitmap_free(complete_cpuset); + topology->next_group_depth = next_group_depth; +} + +static int +look_procs(struct hwloc_backend *backend, struct procinfo *infos, int fulldiscovery, + unsigned highest_cpuid, unsigned highest_ext_cpuid, unsigned *features, enum cpuid_type cpuid_type, + int (*get_cpubind)(hwloc_topology_t topology, hwloc_cpuset_t set, int flags), + int (*set_cpubind)(hwloc_topology_t topology, hwloc_const_cpuset_t set, int flags)) +{ + struct hwloc_x86_backend_data_s *data = backend->private_data; + struct hwloc_topology *topology = backend->topology; + unsigned nbprocs = data->nbprocs; + hwloc_bitmap_t orig_cpuset = hwloc_bitmap_alloc(); + hwloc_bitmap_t set; + unsigned i; + + if (get_cpubind(topology, orig_cpuset, HWLOC_CPUBIND_STRICT)) { + hwloc_bitmap_free(orig_cpuset); + return -1; + } + + set = hwloc_bitmap_alloc(); + + for (i = 0; i < nbprocs; i++) { + hwloc_bitmap_only(set, i); + hwloc_debug("binding to CPU%d\n", i); + if (set_cpubind(topology, set, HWLOC_CPUBIND_STRICT)) { + hwloc_debug("could not bind to CPU%d: %s\n", i, strerror(errno)); + continue; + } + look_proc(backend, &infos[i], highest_cpuid, highest_ext_cpuid, features, cpuid_type); + } + + set_cpubind(topology, orig_cpuset, 0); + hwloc_bitmap_free(set); + hwloc_bitmap_free(orig_cpuset); + + if (!data->apicid_unique) + fulldiscovery = 0; + summarize(backend, infos, fulldiscovery); + return fulldiscovery; /* success, but objects added only if fulldiscovery */ +} + +#if defined HWLOC_FREEBSD_SYS && defined HAVE_CPUSET_SETID +#include +#include +typedef cpusetid_t hwloc_x86_os_state_t; +static void hwloc_x86_os_state_save(hwloc_x86_os_state_t *state) +{ + /* temporary make all cpus available during discovery */ + cpuset_getid(CPU_LEVEL_CPUSET, CPU_WHICH_PID, -1, state); + cpuset_setid(CPU_WHICH_PID, -1, 0); +} +static void hwloc_x86_os_state_restore(hwloc_x86_os_state_t *state) +{ + /* restore initial cpuset */ + cpuset_setid(CPU_WHICH_PID, -1, *state); +} +#else /* !defined HWLOC_FREEBSD_SYS || !defined HAVE_CPUSET_SETID */ +typedef void * hwloc_x86_os_state_t; +static void hwloc_x86_os_state_save(hwloc_x86_os_state_t *state __hwloc_attribute_unused) { } +static void hwloc_x86_os_state_restore(hwloc_x86_os_state_t *state __hwloc_attribute_unused) { } +#endif /* !defined HWLOC_FREEBSD_SYS || !defined HAVE_CPUSET_SETID */ + + +#define INTEL_EBX ('G' | ('e'<<8) | ('n'<<16) | ('u'<<24)) +#define INTEL_EDX ('i' | ('n'<<8) | ('e'<<16) | ('I'<<24)) +#define INTEL_ECX ('n' | ('t'<<8) | ('e'<<16) | ('l'<<24)) + +#define AMD_EBX ('A' | ('u'<<8) | ('t'<<16) | ('h'<<24)) +#define AMD_EDX ('e' | ('n'<<8) | ('t'<<16) | ('i'<<24)) +#define AMD_ECX ('c' | ('A'<<8) | ('M'<<16) | ('D'<<24)) + +/* fake cpubind for when nbprocs=1 and no binding support */ +static int fake_get_cpubind(hwloc_topology_t topology __hwloc_attribute_unused, + hwloc_cpuset_t set __hwloc_attribute_unused, + int flags __hwloc_attribute_unused) +{ + return 0; +} +static int fake_set_cpubind(hwloc_topology_t topology __hwloc_attribute_unused, + hwloc_const_cpuset_t set __hwloc_attribute_unused, + int flags __hwloc_attribute_unused) +{ + return 0; +} + +static +int hwloc_look_x86(struct hwloc_backend *backend, int fulldiscovery) +{ + struct hwloc_x86_backend_data_s *data = backend->private_data; + unsigned nbprocs = data->nbprocs; + unsigned eax, ebx, ecx = 0, edx; + unsigned i; + unsigned highest_cpuid; + unsigned highest_ext_cpuid; + /* This stores cpuid features with the same indexing as Linux */ + unsigned features[10] = { 0 }; + struct procinfo *infos = NULL; + enum cpuid_type cpuid_type = unknown; + hwloc_x86_os_state_t os_state; + struct hwloc_binding_hooks hooks; + struct hwloc_topology_support support; + struct hwloc_topology_membind_support memsupport __hwloc_attribute_unused; + int (*get_cpubind)(hwloc_topology_t topology, hwloc_cpuset_t set, int flags); + int (*set_cpubind)(hwloc_topology_t topology, hwloc_const_cpuset_t set, int flags); + int ret = -1; + + /* check if binding works */ + memset(&hooks, 0, sizeof(hooks)); + support.membind = &memsupport; + hwloc_set_native_binding_hooks(&hooks, &support); + if (hooks.get_thisproc_cpubind && hooks.set_thisproc_cpubind) { + get_cpubind = hooks.get_thisproc_cpubind; + set_cpubind = hooks.set_thisproc_cpubind; + } else if (hooks.get_thisthread_cpubind && hooks.set_thisthread_cpubind) { + get_cpubind = hooks.get_thisthread_cpubind; + set_cpubind = hooks.set_thisthread_cpubind; + } else { + /* we need binding support if there are multiple PUs */ + if (nbprocs > 1) + goto out; + get_cpubind = fake_get_cpubind; + set_cpubind = fake_set_cpubind; + } + + if (!hwloc_have_x86_cpuid()) + goto out; + + infos = calloc(nbprocs, sizeof(struct procinfo)); + if (NULL == infos) + goto out; + for (i = 0; i < nbprocs; i++) { + infos[i].nodeid = (unsigned) -1; + infos[i].packageid = (unsigned) -1; + infos[i].unitid = (unsigned) -1; + infos[i].coreid = (unsigned) -1; + infos[i].threadid = (unsigned) -1; + } + + eax = 0x00; + hwloc_x86_cpuid(&eax, &ebx, &ecx, &edx); + highest_cpuid = eax; + if (ebx == INTEL_EBX && ecx == INTEL_ECX && edx == INTEL_EDX) + cpuid_type = intel; + if (ebx == AMD_EBX && ecx == AMD_ECX && edx == AMD_EDX) + cpuid_type = amd; + + hwloc_debug("highest cpuid %x, cpuid type %u\n", highest_cpuid, cpuid_type); + if (highest_cpuid < 0x01) { + goto out_with_infos; + } + + eax = 0x01; + hwloc_x86_cpuid(&eax, &ebx, &ecx, &edx); + features[0] = edx; + features[4] = ecx; + + eax = 0x80000000; + hwloc_x86_cpuid(&eax, &ebx, &ecx, &edx); + highest_ext_cpuid = eax; + + hwloc_debug("highest extended cpuid %x\n", highest_ext_cpuid); + + if (highest_cpuid >= 0x7) { + eax = 0x7; + hwloc_x86_cpuid(&eax, &ebx, &ecx, &edx); + features[9] = ebx; + } + + if (cpuid_type != intel && highest_ext_cpuid >= 0x80000001) { + eax = 0x80000001; + hwloc_x86_cpuid(&eax, &ebx, &ecx, &edx); + features[1] = edx; + features[6] = ecx; + } + + hwloc_x86_os_state_save(&os_state); + + ret = look_procs(backend, infos, fulldiscovery, + highest_cpuid, highest_ext_cpuid, features, cpuid_type, + get_cpubind, set_cpubind); + if (ret >= 0) + /* success, we're done */ + goto out_with_os_state; + + if (nbprocs == 1) { + /* only one processor, no need to bind */ + look_proc(backend, &infos[0], highest_cpuid, highest_ext_cpuid, features, cpuid_type); + summarize(backend, infos, fulldiscovery); + ret = fulldiscovery; + } + +out_with_os_state: + hwloc_x86_os_state_restore(&os_state); + +out_with_infos: + if (NULL != infos) { + free(infos); + } + +out: + return ret; +} + +static int +hwloc_x86_discover(struct hwloc_backend *backend) +{ + struct hwloc_x86_backend_data_s *data = backend->private_data; + struct hwloc_topology *topology = backend->topology; + int alreadypus = 0; + int ret; + + data->nbprocs = hwloc_fallback_nbprocessors(topology); + + if (!topology->is_thissystem) { + hwloc_debug("%s", "\nno x86 detection (not thissystem)\n"); + return 0; + } + + if (topology->levels[0][0]->cpuset) { + /* somebody else discovered things */ + if (topology->nb_levels == 2 && topology->level_nbobjects[1] == data->nbprocs) { + /* only PUs were discovered, as much as we would, complete the topology with everything else */ + alreadypus = 1; + goto fulldiscovery; + } + + /* several object types were added, we can't easily complete, just annotate a bit */ + ret = hwloc_look_x86(backend, 0); + if (ret) + hwloc_obj_add_info(topology->levels[0][0], "Backend", "x86"); + return 0; + } else { + /* topology is empty, initialize it */ + hwloc_alloc_obj_cpusets(topology->levels[0][0]); + } + +fulldiscovery: + hwloc_look_x86(backend, 1); + /* if failed, just continue and create PUs */ + + if (!alreadypus) + hwloc_setup_pu_level(topology, data->nbprocs); + + hwloc_obj_add_info(topology->levels[0][0], "Backend", "x86"); + +#ifdef HAVE_UNAME + hwloc_add_uname_info(topology, NULL); /* we already know is_thissystem() is true */ +#else + /* uname isn't available, manually setup the "Architecture" info */ +#ifdef HWLOC_X86_64_ARCH + hwloc_obj_add_info(topology->levels[0][0], "Architecture", "x86_64"); +#else + hwloc_obj_add_info(topology->levels[0][0], "Architecture", "x86"); +#endif +#endif + return 1; +} + +static void +hwloc_x86_backend_disable(struct hwloc_backend *backend) +{ + struct hwloc_x86_backend_data_s *data = backend->private_data; + hwloc_bitmap_free(data->apicid_set); + free(data); +} + +static struct hwloc_backend * +hwloc_x86_component_instantiate(struct hwloc_disc_component *component, + const void *_data1 __hwloc_attribute_unused, + const void *_data2 __hwloc_attribute_unused, + const void *_data3 __hwloc_attribute_unused) +{ + struct hwloc_backend *backend; + struct hwloc_x86_backend_data_s *data; + + backend = hwloc_backend_alloc(component); + if (!backend) + goto out; + + data = malloc(sizeof(*data)); + if (!data) { + errno = ENOMEM; + goto out_with_backend; + } + + backend->private_data = data; + backend->flags = HWLOC_BACKEND_FLAG_NEED_LEVELS; + backend->discover = hwloc_x86_discover; + backend->disable = hwloc_x86_backend_disable; + + /* default values */ + data->apicid_set = hwloc_bitmap_alloc(); + data->apicid_unique = 1; + + return backend; + + out_with_backend: + free(backend); + out: + return NULL; +} + +static struct hwloc_disc_component hwloc_x86_disc_component = { + HWLOC_DISC_COMPONENT_TYPE_CPU, + "x86", + HWLOC_DISC_COMPONENT_TYPE_GLOBAL, + hwloc_x86_component_instantiate, + 45, /* between native and no_os */ + NULL +}; + +const struct hwloc_component hwloc_x86_component = { + HWLOC_COMPONENT_ABI, + NULL, NULL, + HWLOC_COMPONENT_TYPE_DISC, + 0, + &hwloc_x86_disc_component +}; diff --git a/opal/mca/hwloc/hwloc1110/hwloc/src/topology-xml-libxml.c b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-xml-libxml.c new file mode 100644 index 0000000000..ce3250c285 --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-xml-libxml.c @@ -0,0 +1,543 @@ +/* + * Copyright © 2009 CNRS + * Copyright © 2009-2014 Inria. All rights reserved. + * Copyright © 2009-2011 Université Bordeaux + * Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved. + * See COPYING in top-level directory. + */ + +#include +#include +#include + +/* private headers allowed because this plugin is built within hwloc */ +#include +#include + +#include +#include + +/******************* + * Common routines * + *******************/ + +static void hwloc_libxml2_error_callback(void * ctx __hwloc_attribute_unused, const char * msg __hwloc_attribute_unused, ...) { /* do nothing */ } + +static void +hwloc_libxml2_disable_stderrwarnings(void) +{ + static int first = 1; + if (first) { + xmlSetGenericErrorFunc(NULL, hwloc__xml_verbose() ? xmlGenericError : hwloc_libxml2_error_callback); + first = 0; + } +} + +/******************* + * Import routines * + *******************/ + +typedef struct hwloc__libxml_import_state_data_s { + xmlNode *node; /* current libxml node, always valid */ + xmlNode *child; /* last processed child, or NULL if none yet */ + xmlAttr *attr; /* last processed attribute, or NULL if none yet */ +} __hwloc_attribute_may_alias * hwloc__libxml_import_state_data_t; + +static int +hwloc__libxml_import_next_attr(hwloc__xml_import_state_t state, char **namep, char **valuep) +{ + hwloc__libxml_import_state_data_t lstate = (void*) state->data; + + xmlAttr *attr; + if (lstate->attr) + attr = lstate->attr->next; + else + attr = lstate->node->properties; + for (; attr; attr = attr->next) + if (attr->type == XML_ATTRIBUTE_NODE) { + /* use the first valid attribute content */ + xmlNode *subnode; + for (subnode = attr->children; subnode; subnode = subnode->next) { + if (subnode->type == XML_TEXT_NODE) { + if (subnode->content && subnode->content[0] != '\0' && subnode->content[0] != '\n') { + *namep = (char *) attr->name; + *valuep = (char *) subnode->content; + lstate->attr = attr; + return 0; + } + } else { + if (hwloc__xml_verbose()) + fprintf(stderr, "ignoring unexpected xml attr node type %u\n", subnode->type); + } + } + } else { + if (hwloc__xml_verbose()) + fprintf(stderr, "ignoring unexpected xml attr type %u\n", attr->type); + } + return -1; +} + +static int +hwloc__libxml_import_find_child(hwloc__xml_import_state_t state, + hwloc__xml_import_state_t childstate, + char **tagp) +{ + hwloc__libxml_import_state_data_t lstate = (void*) state->data; + hwloc__libxml_import_state_data_t lchildstate = (void*) childstate->data; + xmlNode *child; + childstate->parent = state; + childstate->global = state->global; + if (!lstate->child) + return 0; + child = lstate->child->next; + for (; child; child = child->next) + if (child->type == XML_ELEMENT_NODE) { + lstate->child = lchildstate->node = child; + lchildstate->child = child->children; + lchildstate->attr = NULL; + *tagp = (char*) child->name; + return 1; + } else if (child->type == XML_TEXT_NODE) { + if (child->content && child->content[0] != '\0' && child->content[0] != '\n') + if (hwloc__xml_verbose()) + fprintf(stderr, "ignoring object text content %s\n", (const char*) child->content); + } else if (child->type != XML_COMMENT_NODE) { + if (hwloc__xml_verbose()) + fprintf(stderr, "ignoring unexpected xml node type %u\n", child->type); + } + + return 0; +} + +static int +hwloc__libxml_import_close_tag(hwloc__xml_import_state_t state __hwloc_attribute_unused) +{ + return 0; +} + +static void +hwloc__libxml_import_close_child(hwloc__xml_import_state_t state __hwloc_attribute_unused) +{ + /* nothing to do */ +} + +static int +hwloc__libxml_import_get_content(hwloc__xml_import_state_t state, + char **beginp, size_t expected_length) +{ + hwloc__libxml_import_state_data_t lstate = (void*) state->data; + xmlNode *child; + size_t length; + + child = lstate->node->children; + if (!child) + return 0; + if (child->type != XML_TEXT_NODE) + return 0; + + length = strlen((char *) child->content); + if (length != expected_length) + return -1; + *beginp = (char *) child->content; + return 1; +} + +static void +hwloc__libxml_import_close_content(hwloc__xml_import_state_t state __hwloc_attribute_unused) +{ + /* nothing to do */ +} + +static int +hwloc_libxml_look_init(struct hwloc_xml_backend_data_s *bdata, + struct hwloc__xml_import_state_s *state) +{ + hwloc__libxml_import_state_data_t lstate = (void*) state->data; + xmlNode* root_node; + xmlDtd *dtd; + + assert(sizeof(*lstate) <= sizeof(state->data)); + + dtd = xmlGetIntSubset((xmlDoc*) bdata->data); + if (!dtd) { + if (hwloc__xml_verbose()) + fprintf(stderr, "Loading XML topology without DTD\n"); + } else if (strcmp((char *) dtd->SystemID, "hwloc.dtd")) { + if (hwloc__xml_verbose()) + fprintf(stderr, "Loading XML topology with wrong DTD SystemID (%s instead of %s)\n", + (char *) dtd->SystemID, "hwloc.dtd"); + } + + root_node = xmlDocGetRootElement((xmlDoc*) bdata->data); + + if (strcmp((const char *) root_node->name, "topology") && strcmp((const char *) root_node->name, "root")) { + /* root node should be in "topology" class (or "root" if importing from < 1.0) */ + if (hwloc__xml_verbose()) + fprintf(stderr, "ignoring object of class `%s' not at the top the xml hierarchy\n", (const char *) root_node->name); + goto failed; + } + + state->global->next_attr = hwloc__libxml_import_next_attr; + state->global->find_child = hwloc__libxml_import_find_child; + state->global->close_tag = hwloc__libxml_import_close_tag; + state->global->close_child = hwloc__libxml_import_close_child; + state->global->get_content = hwloc__libxml_import_get_content; + state->global->close_content = hwloc__libxml_import_close_content; + state->parent = NULL; + lstate->node = root_node; + lstate->child = root_node->children; + lstate->attr = NULL; + return 0; /* success */ + + failed: + return -1; /* failed */ +} + +static int +hwloc_libxml_import_diff(struct hwloc__xml_import_state_s *state, const char *xmlpath, const char *xmlbuffer, int xmlbuflen, hwloc_topology_diff_t *firstdiffp, char **refnamep) +{ + hwloc__libxml_import_state_data_t lstate = (void*) state->data; + char *refname = NULL; + xmlDoc *doc = NULL; + xmlNode* root_node; + xmlDtd *dtd; + int ret; + + assert(sizeof(*lstate) <= sizeof(state->data)); + + LIBXML_TEST_VERSION; + hwloc_libxml2_disable_stderrwarnings(); + + errno = 0; /* set to 0 so that we know if libxml2 changed it */ + + if (xmlpath) + doc = xmlReadFile(xmlpath, NULL, 0); + else if (xmlbuffer) + doc = xmlReadMemory(xmlbuffer, xmlbuflen, "", NULL, 0); + + if (!doc) { + if (!errno) + /* libxml2 read the file fine, but it got an error during parsing */ + errno = EINVAL; + goto out; + } + + dtd = xmlGetIntSubset(doc); + if (!dtd) { + if (hwloc__xml_verbose()) + fprintf(stderr, "Loading XML topologydiff without DTD\n"); + } else if (strcmp((char *) dtd->SystemID, "hwloc.dtd")) { + if (hwloc__xml_verbose()) + fprintf(stderr, "Loading XML topologydiff with wrong DTD SystemID (%s instead of %s)\n", + (char *) dtd->SystemID, "hwloc.dtd"); + } + + root_node = xmlDocGetRootElement(doc); + + if (strcmp((const char *) root_node->name, "topologydiff")) { + /* root node should be in "topologydiff" class */ + if (hwloc__xml_verbose()) + fprintf(stderr, "ignoring object of class `%s' not at the top the xml hierarchy\n", (const char *) root_node->name); + goto out_with_doc; + } + + state->global->next_attr = hwloc__libxml_import_next_attr; + state->global->find_child = hwloc__libxml_import_find_child; + state->global->close_tag = hwloc__libxml_import_close_tag; + state->global->close_child = hwloc__libxml_import_close_child; + state->global->get_content = hwloc__libxml_import_get_content; + state->global->close_content = hwloc__libxml_import_close_content; + state->parent = NULL; + lstate->node = root_node; + lstate->child = root_node->children; + lstate->attr = NULL; + + while (1) { + char *attrname, *attrvalue; + if (state->global->next_attr(state, &attrname, &attrvalue) < 0) + break; + if (!strcmp(attrname, "refname")) { + free(refname); + refname = strdup(attrvalue); + } else + goto out_with_doc; + } + + ret = hwloc__xml_import_diff(state, firstdiffp); + if (refnamep && !ret) + *refnamep = refname; + else + free(refname); + + xmlFreeDoc(doc); + return ret; + +out_with_doc: + xmlFreeDoc(doc); +out: + return -1; /* failed */ +} + +/******************** + * Backend routines * + ********************/ + +static void +hwloc_libxml_backend_exit(struct hwloc_xml_backend_data_s *bdata) +{ + xmlFreeDoc((xmlDoc*)bdata->data); +} + +static int +hwloc_libxml_backend_init(struct hwloc_xml_backend_data_s *bdata, + const char *xmlpath, const char *xmlbuffer, int xmlbuflen) +{ + xmlDoc *doc = NULL; + + LIBXML_TEST_VERSION; + hwloc_libxml2_disable_stderrwarnings(); + + errno = 0; /* set to 0 so that we know if libxml2 changed it */ + + if (xmlpath) + doc = xmlReadFile(xmlpath, NULL, 0); + else if (xmlbuffer) + doc = xmlReadMemory(xmlbuffer, xmlbuflen, "", NULL, 0); + + if (!doc) { + if (!errno) + /* libxml2 read the file fine, but it got an error during parsing */ + errno = EINVAL; + return -1; + } + + bdata->look_init = hwloc_libxml_look_init; + bdata->look_failed = NULL; + bdata->backend_exit = hwloc_libxml_backend_exit; + bdata->data = doc; + return 0; +} + +/******************* + * Export routines * + *******************/ + +typedef struct hwloc__libxml_export_state_data_s { + xmlNodePtr current_node; /* current node to output */ +} __hwloc_attribute_may_alias * hwloc__libxml_export_state_data_t; + +static void +hwloc__libxml_export_new_child(hwloc__xml_export_state_t parentstate, + hwloc__xml_export_state_t state, + const char *name) +{ + hwloc__libxml_export_state_data_t lpdata = (void *) parentstate->data; + hwloc__libxml_export_state_data_t ldata = (void *) state->data; + + state->parent = parentstate; + state->new_child = parentstate->new_child; + state->new_prop = parentstate->new_prop; + state->add_content = parentstate->add_content; + state->end_object = parentstate->end_object; + + ldata->current_node = xmlNewChild(lpdata->current_node, NULL, BAD_CAST name, NULL); +} + +static void +hwloc__libxml_export_new_prop(hwloc__xml_export_state_t state, const char *name, const char *value) +{ + hwloc__libxml_export_state_data_t ldata = (void *) state->data; + xmlNewProp(ldata->current_node, BAD_CAST name, BAD_CAST value); +} + +static void +hwloc__libxml_export_end_object(hwloc__xml_export_state_t state __hwloc_attribute_unused, const char *name __hwloc_attribute_unused) +{ + /* nothing to do */ +} + +static void +hwloc__libxml_export_add_content(hwloc__xml_export_state_t state, const char *buffer, size_t length) +{ + hwloc__libxml_export_state_data_t ldata = (void *) state->data; + xmlNodeAddContentLen(ldata->current_node, BAD_CAST buffer, length); +} + +static xmlDocPtr +hwloc__libxml2_prepare_export(hwloc_topology_t topology) +{ + struct hwloc__xml_export_state_s state; + hwloc__libxml_export_state_data_t data = (void *) state.data; + xmlDocPtr doc = NULL; /* document pointer */ + xmlNodePtr root_node = NULL; /* root pointer */ + + assert(sizeof(*data) <= sizeof(state.data)); + + LIBXML_TEST_VERSION; + hwloc_libxml2_disable_stderrwarnings(); + + /* Creates a new document, a node and set it as a root node. */ + doc = xmlNewDoc(BAD_CAST "1.0"); + root_node = xmlNewNode(NULL, BAD_CAST "topology"); + xmlDocSetRootElement(doc, root_node); + + /* Creates a DTD declaration. Isn't mandatory. */ + (void) xmlCreateIntSubset(doc, BAD_CAST "topology", NULL, BAD_CAST "hwloc.dtd"); + + state.new_child = hwloc__libxml_export_new_child; + state.new_prop = hwloc__libxml_export_new_prop; + state.add_content = hwloc__libxml_export_add_content; + state.end_object = hwloc__libxml_export_end_object; + + data->current_node = root_node; + + hwloc__xml_export_object (&state, topology, hwloc_get_root_obj(topology)); + + return doc; +} + +static int +hwloc_libxml_export_file(hwloc_topology_t topology, const char *filename) +{ + xmlDocPtr doc; + int ret; + + errno = 0; /* set to 0 so that we know if libxml2 changed it */ + + doc = hwloc__libxml2_prepare_export(topology); + ret = xmlSaveFormatFileEnc(filename, doc, "UTF-8", 1); + xmlFreeDoc(doc); + + if (ret < 0) { + if (!errno) + /* libxml2 likely got an error before doing I/O */ + errno = EINVAL; + return ret; + } + return 0; +} + +static int +hwloc_libxml_export_buffer(hwloc_topology_t topology, char **xmlbuffer, int *buflen) +{ + xmlDocPtr doc; + + doc = hwloc__libxml2_prepare_export(topology); + xmlDocDumpFormatMemoryEnc(doc, (xmlChar **)xmlbuffer, buflen, "UTF-8", 1); + xmlFreeDoc(doc); + return 0; +} + +static xmlDocPtr +hwloc__libxml2_prepare_export_diff(hwloc_topology_diff_t diff, const char *refname) +{ + struct hwloc__xml_export_state_s state; + hwloc__libxml_export_state_data_t data = (void *) state.data; + xmlDocPtr doc = NULL; /* document pointer */ + xmlNodePtr root_node = NULL; /* root pointer */ + + assert(sizeof(*data) <= sizeof(state.data)); + + LIBXML_TEST_VERSION; + hwloc_libxml2_disable_stderrwarnings(); + + /* Creates a new document, a node and set it as a root node. */ + doc = xmlNewDoc(BAD_CAST "1.0"); + root_node = xmlNewNode(NULL, BAD_CAST "topologydiff"); + if (refname) + xmlNewProp(root_node, BAD_CAST "refname", BAD_CAST refname); + xmlDocSetRootElement(doc, root_node); + + /* Creates a DTD declaration. Isn't mandatory. */ + (void) xmlCreateIntSubset(doc, BAD_CAST "topologydiff", NULL, BAD_CAST "hwloc.dtd"); + + state.new_child = hwloc__libxml_export_new_child; + state.new_prop = hwloc__libxml_export_new_prop; + state.add_content = hwloc__libxml_export_add_content; + state.end_object = hwloc__libxml_export_end_object; + + data->current_node = root_node; + + hwloc__xml_export_diff (&state, diff); + + return doc; +} + +static int +hwloc_libxml_export_diff_file(hwloc_topology_diff_t diff, const char *refname, const char *filename) +{ + xmlDocPtr doc; + int ret; + + errno = 0; /* set to 0 so that we know if libxml2 changed it */ + + doc = hwloc__libxml2_prepare_export_diff(diff, refname); + ret = xmlSaveFormatFileEnc(filename, doc, "UTF-8", 1); + xmlFreeDoc(doc); + + if (ret < 0) { + if (!errno) + /* libxml2 likely got an error before doing I/O */ + errno = EINVAL; + return ret; + } + return 0; +} + +static int +hwloc_libxml_export_diff_buffer(hwloc_topology_diff_t diff, const char *refname, char **xmlbuffer, int *buflen) +{ + xmlDocPtr doc; + + doc = hwloc__libxml2_prepare_export_diff(diff, refname); + xmlDocDumpFormatMemoryEnc(doc, (xmlChar **)xmlbuffer, buflen, "UTF-8", 1); + xmlFreeDoc(doc); + return 0; +} + +static void +hwloc_libxml_free_buffer(void *xmlbuffer) +{ + xmlFree(BAD_CAST xmlbuffer); +} + +/************* + * Callbacks * + *************/ + +static struct hwloc_xml_callbacks hwloc_xml_libxml_callbacks = { + hwloc_libxml_backend_init, + hwloc_libxml_export_file, + hwloc_libxml_export_buffer, + hwloc_libxml_free_buffer, + hwloc_libxml_import_diff, + hwloc_libxml_export_diff_file, + hwloc_libxml_export_diff_buffer +}; + +static struct hwloc_xml_component hwloc_libxml_xml_component = { + NULL, + &hwloc_xml_libxml_callbacks +}; + +static int +hwloc_xml_libxml_component_init(unsigned long flags) +{ + if (flags) + return -1; + if (hwloc_plugin_check_namespace("xml_libxml", "hwloc__xml_verbose") < 0) + return -1; + return 0; +} + +#ifdef HWLOC_INSIDE_PLUGIN +HWLOC_DECLSPEC extern const struct hwloc_component hwloc_xml_libxml_component; +#endif + +const struct hwloc_component hwloc_xml_libxml_component = { + HWLOC_COMPONENT_ABI, + hwloc_xml_libxml_component_init, NULL, + HWLOC_COMPONENT_TYPE_XML, + 0, + &hwloc_libxml_xml_component +}; diff --git a/opal/mca/hwloc/hwloc1110/hwloc/src/topology-xml-nolibxml.c b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-xml-nolibxml.c new file mode 100644 index 0000000000..a93d9d4955 --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-xml-nolibxml.c @@ -0,0 +1,850 @@ +/* + * Copyright © 2009 CNRS + * Copyright © 2009-2014 Inria. All rights reserved. + * Copyright © 2009-2011 Université Bordeaux + * Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved. + * See COPYING in top-level directory. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +/******************* + * Import routines * + *******************/ + +struct hwloc__nolibxml_backend_data_s { + size_t buflen; /* size of both buffer and copy buffers, set during backend_init() */ + char *buffer; /* allocated and filled during backend_init() */ + char *copy; /* allocated during backend_init(), used later during actual parsing */ +}; + +typedef struct hwloc__nolibxml_import_state_data_s { + char *tagbuffer; /* buffer containing the next tag */ + char *attrbuffer; /* buffer containing the next attribute of the current node */ + char *tagname; /* tag name of the current node */ + int closed; /* set if the current node is auto-closing */ +} __hwloc_attribute_may_alias * hwloc__nolibxml_import_state_data_t; + +static char * +hwloc__nolibxml_import_ignore_spaces(char *buffer) +{ + return buffer + strspn(buffer, " \t\n"); +} + +static int +hwloc__nolibxml_import_next_attr(hwloc__xml_import_state_t state, char **namep, char **valuep) +{ + hwloc__nolibxml_import_state_data_t nstate = (void*) state->data; + int namelen; + size_t len, escaped; + char *buffer, *value, *end; + + if (!nstate->attrbuffer) + return -1; + + /* find the beginning of an attribute */ + buffer = hwloc__nolibxml_import_ignore_spaces(nstate->attrbuffer); + namelen = strspn(buffer, "abcdefghijklmnopqrstuvwxyz_"); + if (buffer[namelen] != '=' || buffer[namelen+1] != '\"') + return -1; + buffer[namelen] = '\0'; + *namep = buffer; + + /* find the beginning of its value, and unescape it */ + *valuep = value = buffer+namelen+2; + len = 0; escaped = 0; + while (value[len+escaped] != '\"') { + if (value[len+escaped] == '&') { + if (!strncmp(&value[1+len+escaped], "#10;", 4)) { + escaped += 4; + value[len] = '\n'; + } else if (!strncmp(&value[1+len+escaped], "#13;", 4)) { + escaped += 4; + value[len] = '\r'; + } else if (!strncmp(&value[1+len+escaped], "#9;", 3)) { + escaped += 3; + value[len] = '\t'; + } else if (!strncmp(&value[1+len+escaped], "quot;", 5)) { + escaped += 5; + value[len] = '\"'; + } else if (!strncmp(&value[1+len+escaped], "lt;", 3)) { + escaped += 3; + value[len] = '<'; + } else if (!strncmp(&value[1+len+escaped], "gt;", 3)) { + escaped += 3; + value[len] = '>'; + } else if (!strncmp(&value[1+len+escaped], "amp;", 4)) { + escaped += 4; + value[len] = '&'; + } else { + return -1; + } + } else { + value[len] = value[len+escaped]; + } + len++; + if (value[len+escaped] == '\0') + return -1; + } + value[len] = '\0'; + + /* find next attribute */ + end = &value[len+escaped+1]; /* skip the ending " */ + nstate->attrbuffer = hwloc__nolibxml_import_ignore_spaces(end); + return 0; +} + +static int +hwloc__nolibxml_import_find_child(hwloc__xml_import_state_t state, + hwloc__xml_import_state_t childstate, + char **tagp) +{ + hwloc__nolibxml_import_state_data_t nstate = (void*) state->data; + hwloc__nolibxml_import_state_data_t nchildstate = (void*) childstate->data; + char *buffer = nstate->tagbuffer; + char *end; + int namelen; + + childstate->parent = state; + childstate->global = state->global; + + /* auto-closed tags have no children */ + if (nstate->closed) + return 0; + + /* find the beginning of the tag */ + buffer = hwloc__nolibxml_import_ignore_spaces(buffer); + if (buffer[0] != '<') + return -1; + buffer++; + + /* if closing tag, return nothing and do not advance */ + if (buffer[0] == '/') + return 0; + + /* normal tag */ + *tagp = nchildstate->tagname = buffer; + + /* find the end, mark it and return it */ + end = strchr(buffer, '>'); + if (!end) + return -1; + end[0] = '\0'; + nchildstate->tagbuffer = end+1; + + /* handle auto-closing tags */ + if (end[-1] == '/') { + nchildstate->closed = 1; + end[-1] = '\0'; + } else + nchildstate->closed = 0; + + /* find attributes */ + namelen = strspn(buffer, "abcdefghijklmnopqrstuvwxyz_"); + + if (buffer[namelen] == '\0') { + /* no attributes */ + nchildstate->attrbuffer = NULL; + return 1; + } + + if (buffer[namelen] != ' ') + return -1; + + /* found a space, likely starting attributes */ + buffer[namelen] = '\0'; + nchildstate->attrbuffer = buffer+namelen+1; + return 1; +} + +static int +hwloc__nolibxml_import_close_tag(hwloc__xml_import_state_t state) +{ + hwloc__nolibxml_import_state_data_t nstate = (void*) state->data; + char *buffer = nstate->tagbuffer; + char *end; + + /* auto-closed tags need nothing */ + if (nstate->closed) + return 0; + + /* find the beginning of the tag */ + buffer = hwloc__nolibxml_import_ignore_spaces(buffer); + if (buffer[0] != '<') + return -1; + buffer++; + + /* find the end, mark it and return it to the parent */ + end = strchr(buffer, '>'); + if (!end) + return -1; + end[0] = '\0'; + nstate->tagbuffer = end+1; + + /* if closing tag, return nothing */ + if (buffer[0] != '/' || strcmp(buffer+1, nstate->tagname) ) + return -1; + return 0; +} + +static void +hwloc__nolibxml_import_close_child(hwloc__xml_import_state_t state) +{ + hwloc__nolibxml_import_state_data_t nstate = (void*) state->data; + hwloc__nolibxml_import_state_data_t nparent = (void*) state->parent->data; + nparent->tagbuffer = nstate->tagbuffer; +} + +static int +hwloc__nolibxml_import_get_content(hwloc__xml_import_state_t state, + char **beginp, size_t expected_length) +{ + hwloc__nolibxml_import_state_data_t nstate = (void*) state->data; + char *buffer = nstate->tagbuffer; + size_t length; + char *end; + + /* auto-closed tags have no content */ + if (nstate->closed) + return 0; + + /* find the next tag, where the content ends */ + end = strchr(buffer, '<'); + if (!end) + return -1; + + length = (size_t) (end-buffer); + if (length != expected_length) + return -1; + nstate->tagbuffer = end; + *end = '\0'; /* mark as 0-terminated for now */ + *beginp = buffer; + return 1; +} + +static void +hwloc__nolibxml_import_close_content(hwloc__xml_import_state_t state) +{ + /* put back the '<' that we overwrote to 0-terminate the content */ + hwloc__nolibxml_import_state_data_t nstate = (void*) state->data; + *nstate->tagbuffer = '<'; +} + +static int +hwloc_nolibxml_look_init(struct hwloc_xml_backend_data_s *bdata, + struct hwloc__xml_import_state_s *state) +{ + hwloc__nolibxml_import_state_data_t nstate = (void*) state->data; + struct hwloc__nolibxml_backend_data_s *nbdata = bdata->data; + char *buffer; + + assert(sizeof(*nstate) <= sizeof(state->data)); + + /* use a copy in the temporary buffer, we may modify during parsing */ + buffer = nbdata->copy; + memcpy(buffer, nbdata->buffer, nbdata->buflen); + + /* skip headers */ + while (!strncmp(buffer, "", 10)) + goto failed; + + state->global->next_attr = hwloc__nolibxml_import_next_attr; + state->global->find_child = hwloc__nolibxml_import_find_child; + state->global->close_tag = hwloc__nolibxml_import_close_tag; + state->global->close_child = hwloc__nolibxml_import_close_child; + state->global->get_content = hwloc__nolibxml_import_get_content; + state->global->close_content = hwloc__nolibxml_import_close_content; + state->parent = NULL; + nstate->closed = 0; + nstate->tagbuffer = buffer+10; + nstate->tagname = (char *) "topology"; + nstate->attrbuffer = NULL; + return 0; /* success */ + + failed: + return -1; /* failed */ +} + +static void +hwloc_nolibxml_look_failed(struct hwloc_xml_backend_data_s *bdata __hwloc_attribute_unused) +{ + /* not only when verbose */ + fprintf(stderr, "Failed to parse XML input with the minimalistic parser. If it was not\n" + "generated by hwloc, try enabling full XML support with libxml2.\n"); +} + +/******************** + * Backend routines * + ********************/ + +static void +hwloc_nolibxml_backend_exit(struct hwloc_xml_backend_data_s *bdata) +{ + struct hwloc__nolibxml_backend_data_s *nbdata = bdata->data; + free(nbdata->buffer); + free(nbdata->copy); + free(nbdata); +} + +static int +hwloc_nolibxml_read_file(const char *xmlpath, char **bufferp, size_t *buflenp) +{ + FILE * file; + size_t buflen, offset, readlen; + struct stat statbuf; + char *buffer; + size_t ret; + + if (!strcmp(xmlpath, "-")) + xmlpath = "/dev/stdin"; + + file = fopen(xmlpath, "r"); + if (!file) + goto out; + + /* find the required buffer size for regular files, or use 4k when unknown, we'll realloc later if needed */ + buflen = 4096; + if (!stat(xmlpath, &statbuf)) + if (S_ISREG(statbuf.st_mode)) + buflen = statbuf.st_size+1; /* one additional byte so that the first fread() gets EOF too */ + + buffer = malloc(buflen+1); /* one more byte for the ending \0 */ + if (!buffer) + goto out_with_file; + + offset = 0; readlen = buflen; + while (1) { + ret = fread(buffer+offset, 1, readlen, file); + + offset += ret; + buffer[offset] = 0; + + if (ret != readlen) + break; + + buflen *= 2; + buffer = realloc(buffer, buflen+1); + if (!buffer) + goto out_with_file; + readlen = buflen/2; + } + + fclose(file); + *bufferp = buffer; + *buflenp = offset+1; + return 0; + + out_with_file: + fclose(file); + out: + return -1; +} + +static int +hwloc_nolibxml_backend_init(struct hwloc_xml_backend_data_s *bdata, + const char *xmlpath, const char *xmlbuffer, int xmlbuflen) +{ + struct hwloc__nolibxml_backend_data_s *nbdata = malloc(sizeof(*nbdata)); + + if (!nbdata) + goto out; + bdata->data = nbdata; + + if (xmlbuffer) { + nbdata->buffer = malloc(xmlbuflen); + if (!nbdata->buffer) + goto out_with_nbdata; + nbdata->buflen = xmlbuflen; + memcpy(nbdata->buffer, xmlbuffer, xmlbuflen); + + } else { + int err = hwloc_nolibxml_read_file(xmlpath, &nbdata->buffer, &nbdata->buflen); + if (err < 0) + goto out_with_nbdata; + } + + /* allocate a temporary copy buffer that we may modify during parsing */ + nbdata->copy = malloc(nbdata->buflen); + if (!nbdata->copy) + goto out_with_buffer; + + bdata->look_init = hwloc_nolibxml_look_init; + bdata->look_failed = hwloc_nolibxml_look_failed; + bdata->backend_exit = hwloc_nolibxml_backend_exit; + return 0; + +out_with_buffer: + free(nbdata->buffer); +out_with_nbdata: + free(nbdata); +out: + return -1; +} + +static int +hwloc_nolibxml_import_diff(struct hwloc__xml_import_state_s *state, + const char *xmlpath, const char *xmlbuffer, int xmlbuflen, + hwloc_topology_diff_t *firstdiffp, char **refnamep) +{ + hwloc__nolibxml_import_state_data_t nstate = (void*) state->data; + struct hwloc__xml_import_state_s childstate; + char *refname = NULL; + char *buffer, *tmp, *tag; + size_t buflen; + int ret; + + assert(sizeof(*nstate) <= sizeof(state->data)); + + if (xmlbuffer) { + buffer = malloc(xmlbuflen); + if (!buffer) + goto out; + memcpy(buffer, xmlbuffer, xmlbuflen); + buflen = xmlbuflen; + + } else { + ret = hwloc_nolibxml_read_file(xmlpath, &buffer, &buflen); + if (ret < 0) + goto out; + } + + /* skip headers */ + tmp = buffer; + while (!strncmp(tmp, "global->next_attr = hwloc__nolibxml_import_next_attr; + state->global->find_child = hwloc__nolibxml_import_find_child; + state->global->close_tag = hwloc__nolibxml_import_close_tag; + state->global->close_child = hwloc__nolibxml_import_close_child; + state->global->get_content = hwloc__nolibxml_import_get_content; + state->global->close_content = hwloc__nolibxml_import_close_content; + state->parent = NULL; + nstate->closed = 0; + nstate->tagbuffer = tmp; + nstate->tagname = NULL; + nstate->attrbuffer = NULL; + + /* find root */ + ret = hwloc__nolibxml_import_find_child(state, &childstate, &tag); + if (ret < 0) + goto out_with_buffer; + if (strcmp(tag, "topologydiff")) + goto out_with_buffer; + + while (1) { + char *attrname, *attrvalue; + if (hwloc__nolibxml_import_next_attr(&childstate, &attrname, &attrvalue) < 0) + break; + if (!strcmp(attrname, "refname")) { + free(refname); + refname = strdup(attrvalue); + } else + goto out_with_buffer; + } + + ret = hwloc__xml_import_diff(&childstate, firstdiffp); + if (refnamep && !ret) + *refnamep = refname; + else + free(refname); + + free(buffer); + return ret; + +out_with_buffer: + free(buffer); +out: + return -1; +} + +/******************* + * Export routines * + *******************/ + +typedef struct hwloc__nolibxml_export_state_data_s { + char *buffer; /* (moving) buffer where to write */ + size_t written; /* how many bytes were written (or would have be written if not truncated) */ + size_t remaining; /* how many bytes are still available in the buffer */ + unsigned indent; /* indentation level for the next line */ + unsigned nr_children; + unsigned has_content; +} __hwloc_attribute_may_alias * hwloc__nolibxml_export_state_data_t; + +static void +hwloc__nolibxml_export_update_buffer(hwloc__nolibxml_export_state_data_t ndata, int res) +{ + if (res >= 0) { + ndata->written += res; + if (res >= (int) ndata->remaining) + res = ndata->remaining>0 ? ndata->remaining-1 : 0; + ndata->buffer += res; + ndata->remaining -= res; + } +} + +static char * +hwloc__nolibxml_export_escape_string(const char *src) +{ + int fulllen, sublen; + char *escaped, *dst; + + fulllen = strlen(src); + + sublen = strcspn(src, "\n\r\t\"<>&"); + if (sublen == fulllen) + return NULL; /* nothing to escape */ + + escaped = malloc(fulllen*6+1); /* escaped chars are replaced by at most 6 char */ + dst = escaped; + + memcpy(dst, src, sublen); + src += sublen; + dst += sublen; + + while (*src) { + int replen; + switch (*src) { + case '\n': strcpy(dst, " "); replen=5; break; + case '\r': strcpy(dst, " "); replen=5; break; + case '\t': strcpy(dst, " "); replen=4; break; + case '\"': strcpy(dst, """); replen=6; break; + case '<': strcpy(dst, "<"); replen=4; break; + case '>': strcpy(dst, ">"); replen=4; break; + case '&': strcpy(dst, "&"); replen=5; break; + default: replen=0; break; + } + dst+=replen; src++; + + sublen = strcspn(src, "\n\r\t\"<>&"); + memcpy(dst, src, sublen); + src += sublen; + dst += sublen; + } + + *dst = 0; + return escaped; +} + +static void +hwloc__nolibxml_export_new_child(hwloc__xml_export_state_t parentstate, + hwloc__xml_export_state_t state, + const char *name) +{ + hwloc__nolibxml_export_state_data_t npdata = (void *) parentstate->data; + hwloc__nolibxml_export_state_data_t ndata = (void *) state->data; + int res; + + assert(!npdata->has_content); + if (!npdata->nr_children) { + res = hwloc_snprintf(npdata->buffer, npdata->remaining, ">\n"); + hwloc__nolibxml_export_update_buffer(npdata, res); + } + npdata->nr_children++; + + state->parent = parentstate; + state->new_child = parentstate->new_child; + state->new_prop = parentstate->new_prop; + state->add_content = parentstate->add_content; + state->end_object = parentstate->end_object; + + ndata->buffer = npdata->buffer; + ndata->written = npdata->written; + ndata->remaining = npdata->remaining; + ndata->indent = npdata->indent + 2; + + ndata->nr_children = 0; + ndata->has_content = 0; + + res = hwloc_snprintf(ndata->buffer, ndata->remaining, "%*s<%s", npdata->indent, "", name); + hwloc__nolibxml_export_update_buffer(ndata, res); +} + +static void +hwloc__nolibxml_export_new_prop(hwloc__xml_export_state_t state, const char *name, const char *value) +{ + hwloc__nolibxml_export_state_data_t ndata = (void *) state->data; + char *escaped = hwloc__nolibxml_export_escape_string(value); + int res = hwloc_snprintf(ndata->buffer, ndata->remaining, " %s=\"%s\"", name, escaped ? (const char *) escaped : value); + hwloc__nolibxml_export_update_buffer(ndata, res); + free(escaped); +} + +static void +hwloc__nolibxml_export_end_object(hwloc__xml_export_state_t state, const char *name) +{ + hwloc__nolibxml_export_state_data_t ndata = (void *) state->data; + hwloc__nolibxml_export_state_data_t npdata = (void *) state->parent->data; + int res; + + assert (!(ndata->has_content && ndata->nr_children)); + if (ndata->has_content) { + res = hwloc_snprintf(ndata->buffer, ndata->remaining, "\n", name); + } else if (ndata->nr_children) { + res = hwloc_snprintf(ndata->buffer, ndata->remaining, "%*s\n", npdata->indent, "", name); + } else { + res = hwloc_snprintf(ndata->buffer, ndata->remaining, "/>\n"); + } + hwloc__nolibxml_export_update_buffer(ndata, res); + + npdata->buffer = ndata->buffer; + npdata->written = ndata->written; + npdata->remaining = ndata->remaining; +} + +static void +hwloc__nolibxml_export_add_content(hwloc__xml_export_state_t state, const char *buffer, size_t length) +{ + hwloc__nolibxml_export_state_data_t ndata = (void *) state->data; + int res; + + assert(!ndata->nr_children); + if (!ndata->has_content) { + res = hwloc_snprintf(ndata->buffer, ndata->remaining, ">"); + hwloc__nolibxml_export_update_buffer(ndata, res); + } + ndata->has_content = 1; + + res = hwloc_snprintf(ndata->buffer, ndata->remaining, buffer, length); + hwloc__nolibxml_export_update_buffer(ndata, res); +} + +static size_t +hwloc___nolibxml_prepare_export(hwloc_topology_t topology, char *xmlbuffer, int buflen) +{ + struct hwloc__xml_export_state_s state, childstate; + hwloc__nolibxml_export_state_data_t ndata = (void *) &state.data; + int res; + + assert(sizeof(*ndata) <= sizeof(state.data)); + + state.new_child = hwloc__nolibxml_export_new_child; + state.new_prop = hwloc__nolibxml_export_new_prop; + state.add_content = hwloc__nolibxml_export_add_content; + state.end_object = hwloc__nolibxml_export_end_object; + + ndata->indent = 0; + ndata->written = 0; + ndata->buffer = xmlbuffer; + ndata->remaining = buflen; + + ndata->nr_children = 1; /* don't close a non-existing previous tag when opening the topology tag */ + ndata->has_content = 0; + + res = hwloc_snprintf(ndata->buffer, ndata->remaining, + "\n" + "\n"); + hwloc__nolibxml_export_update_buffer(ndata, res); + hwloc__nolibxml_export_new_child(&state, &childstate, "topology"); + hwloc__xml_export_object (&childstate, topology, hwloc_get_root_obj(topology)); + hwloc__nolibxml_export_end_object(&childstate, "topology"); + + return ndata->written+1; +} + +static int +hwloc_nolibxml_export_buffer(hwloc_topology_t topology, char **bufferp, int *buflenp) +{ + char *buffer; + size_t bufferlen, res; + + bufferlen = 16384; /* random guess for large enough default */ + buffer = malloc(bufferlen); + res = hwloc___nolibxml_prepare_export(topology, buffer, bufferlen); + + if (res > bufferlen) { + buffer = realloc(buffer, res); + hwloc___nolibxml_prepare_export(topology, buffer, res); + } + + *bufferp = buffer; + *buflenp = res; + return 0; +} + +static int +hwloc_nolibxml_export_file(hwloc_topology_t topology, const char *filename) +{ + FILE *file; + char *buffer; + int bufferlen; + int ret; + + ret = hwloc_nolibxml_export_buffer(topology, &buffer, &bufferlen); + if (ret < 0) + return -1; + + if (!strcmp(filename, "-")) { + file = stdout; + } else { + file = fopen(filename, "w"); + if (!file) { + free(buffer); + return -1; + } + } + + ret = fwrite(buffer, 1, bufferlen-1 /* don't write the ending \0 */, file); + if (ret == bufferlen-1) { + ret = 0; + } else { + errno = ferror(file); + ret = -1; + } + + free(buffer); + + if (file != stdout) + fclose(file); + return ret; +} + +static size_t +hwloc___nolibxml_prepare_export_diff(hwloc_topology_diff_t diff, const char *refname, char *xmlbuffer, int buflen) +{ + struct hwloc__xml_export_state_s state, childstate; + hwloc__nolibxml_export_state_data_t ndata = (void *) &state.data; + int res; + + assert(sizeof(*ndata) <= sizeof(state.data)); + + state.new_child = hwloc__nolibxml_export_new_child; + state.new_prop = hwloc__nolibxml_export_new_prop; + state.add_content = hwloc__nolibxml_export_add_content; + state.end_object = hwloc__nolibxml_export_end_object; + + ndata->indent = 0; + ndata->written = 0; + ndata->buffer = xmlbuffer; + ndata->remaining = buflen; + + ndata->nr_children = 1; /* don't close a non-existing previous tag when opening the topology tag */ + ndata->has_content = 0; + + res = hwloc_snprintf(ndata->buffer, ndata->remaining, + "\n" + "\n"); + hwloc__nolibxml_export_update_buffer(ndata, res); + hwloc__nolibxml_export_new_child(&state, &childstate, "topologydiff"); + if (refname) + hwloc__nolibxml_export_new_prop(&childstate, "refname", refname); + hwloc__xml_export_diff (&childstate, diff); + hwloc__nolibxml_export_end_object(&childstate, "topologydiff"); + + return ndata->written+1; +} + +static int +hwloc_nolibxml_export_diff_buffer(hwloc_topology_diff_t diff, const char *refname, char **bufferp, int *buflenp) +{ + char *buffer; + size_t bufferlen, res; + + bufferlen = 16384; /* random guess for large enough default */ + buffer = malloc(bufferlen); + res = hwloc___nolibxml_prepare_export_diff(diff, refname, buffer, bufferlen); + + if (res > bufferlen) { + buffer = realloc(buffer, res); + hwloc___nolibxml_prepare_export_diff(diff, refname, buffer, res); + } + + *bufferp = buffer; + *buflenp = res; + return 0; +} + +static int +hwloc_nolibxml_export_diff_file(hwloc_topology_diff_t diff, const char *refname, const char *filename) +{ + FILE *file; + char *buffer; + int bufferlen; + int ret; + + ret = hwloc_nolibxml_export_diff_buffer(diff, refname, &buffer, &bufferlen); + if (ret < 0) + return -1; + + if (!strcmp(filename, "-")) { + file = stdout; + } else { + file = fopen(filename, "w"); + if (!file) { + free(buffer); + return -1; + } + } + + ret = fwrite(buffer, 1, bufferlen-1 /* don't write the ending \0 */, file); + if (ret == bufferlen-1) { + ret = 0; + } else { + errno = ferror(file); + ret = -1; + } + + free(buffer); + + if (file != stdout) + fclose(file); + return ret; +} + +static void +hwloc_nolibxml_free_buffer(void *xmlbuffer) +{ + free(xmlbuffer); +} + +/************* + * Callbacks * + *************/ + +static struct hwloc_xml_callbacks hwloc_xml_nolibxml_callbacks = { + hwloc_nolibxml_backend_init, + hwloc_nolibxml_export_file, + hwloc_nolibxml_export_buffer, + hwloc_nolibxml_free_buffer, + hwloc_nolibxml_import_diff, + hwloc_nolibxml_export_diff_file, + hwloc_nolibxml_export_diff_buffer +}; + +static struct hwloc_xml_component hwloc_nolibxml_xml_component = { + &hwloc_xml_nolibxml_callbacks, + NULL +}; + +const struct hwloc_component hwloc_xml_nolibxml_component = { + HWLOC_COMPONENT_ABI, + NULL, NULL, + HWLOC_COMPONENT_TYPE_XML, + 0, + &hwloc_nolibxml_xml_component +}; diff --git a/opal/mca/hwloc/hwloc1110/hwloc/src/topology-xml.c b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-xml.c new file mode 100644 index 0000000000..d9e2e46447 --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/src/topology-xml.c @@ -0,0 +1,1675 @@ +/* + * Copyright © 2009 CNRS + * Copyright © 2009-2015 Inria. All rights reserved. + * Copyright © 2009-2011 Université Bordeaux + * Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved. + * See COPYING in top-level directory. + */ + +#include +#include +#include +#include +#include +#include + +int +hwloc__xml_verbose(void) +{ + static int first = 1; + static int verbose = 0; + if (first) { + const char *env = getenv("HWLOC_XML_VERBOSE"); + if (env) + verbose = atoi(env); + first = 0; + } + return verbose; +} + +static int +hwloc_nolibxml_import(void) +{ + static int first = 1; + static int nolibxml = 0; + if (first) { + const char *env = getenv("HWLOC_NO_LIBXML_IMPORT"); + if (env) + nolibxml = atoi(env); + first = 0; + } + return nolibxml; +} + +static int +hwloc_nolibxml_export(void) +{ + static int first = 1; + static int nolibxml = 0; + if (first) { + const char *env = getenv("HWLOC_NO_LIBXML_EXPORT"); + if (env) + nolibxml = atoi(env); + first = 0; + } + return nolibxml; +} + +/********************************* + ********* XML callbacks ********* + *********************************/ + +/* set when registering nolibxml and libxml components. + * modifications protected by the components mutex. + * read by the common XML code in topology-xml.c to jump to the right XML backend. + */ +static struct hwloc_xml_callbacks *hwloc_nolibxml_callbacks = NULL, *hwloc_libxml_callbacks = NULL; + +void +hwloc_xml_callbacks_register(struct hwloc_xml_component *comp) +{ + if (!hwloc_nolibxml_callbacks) + hwloc_nolibxml_callbacks = comp->nolibxml_callbacks; + if (!hwloc_libxml_callbacks) + hwloc_libxml_callbacks = comp->libxml_callbacks; +} + +void +hwloc_xml_callbacks_reset(void) +{ + hwloc_nolibxml_callbacks = NULL; + hwloc_libxml_callbacks = NULL; +} + +/************************************************ + ********* XML import (common routines) ********* + ************************************************/ + +static void +hwloc__xml_import_object_attr(struct hwloc_topology *topology __hwloc_attribute_unused, struct hwloc_obj *obj, + const char *name, const char *value, + hwloc__xml_import_state_t state) +{ + if (!strcmp(name, "type")) { + /* already handled */ + return; + } + + else if (!strcmp(name, "os_level")) + obj->os_level = strtoul(value, NULL, 10); + else if (!strcmp(name, "os_index")) + obj->os_index = strtoul(value, NULL, 10); + else if (!strcmp(name, "cpuset")) { + obj->cpuset = hwloc_bitmap_alloc(); + hwloc_bitmap_sscanf(obj->cpuset, value); + } else if (!strcmp(name, "complete_cpuset")) { + obj->complete_cpuset = hwloc_bitmap_alloc(); + hwloc_bitmap_sscanf(obj->complete_cpuset,value); + } else if (!strcmp(name, "online_cpuset")) { + obj->online_cpuset = hwloc_bitmap_alloc(); + hwloc_bitmap_sscanf(obj->online_cpuset, value); + } else if (!strcmp(name, "allowed_cpuset")) { + obj->allowed_cpuset = hwloc_bitmap_alloc(); + hwloc_bitmap_sscanf(obj->allowed_cpuset, value); + } else if (!strcmp(name, "nodeset")) { + obj->nodeset = hwloc_bitmap_alloc(); + hwloc_bitmap_sscanf(obj->nodeset, value); + } else if (!strcmp(name, "complete_nodeset")) { + obj->complete_nodeset = hwloc_bitmap_alloc(); + hwloc_bitmap_sscanf(obj->complete_nodeset, value); + } else if (!strcmp(name, "allowed_nodeset")) { + obj->allowed_nodeset = hwloc_bitmap_alloc(); + hwloc_bitmap_sscanf(obj->allowed_nodeset, value); + } else if (!strcmp(name, "name")) + obj->name = strdup(value); + + else if (!strcmp(name, "cache_size")) { + unsigned long long lvalue = strtoull(value, NULL, 10); + if (obj->type == HWLOC_OBJ_CACHE) + obj->attr->cache.size = lvalue; + else if (hwloc__xml_verbose()) + fprintf(stderr, "%s: ignoring cache_size attribute for non-cache object type\n", + state->global->msgprefix); + } + + else if (!strcmp(name, "cache_linesize")) { + unsigned long lvalue = strtoul(value, NULL, 10); + if (obj->type == HWLOC_OBJ_CACHE) + obj->attr->cache.linesize = lvalue; + else if (hwloc__xml_verbose()) + fprintf(stderr, "%s: ignoring cache_linesize attribute for non-cache object type\n", + state->global->msgprefix); + } + + else if (!strcmp(name, "cache_associativity")) { + unsigned long lvalue = strtoul(value, NULL, 10); + if (obj->type == HWLOC_OBJ_CACHE) + obj->attr->cache.associativity = lvalue; + else if (hwloc__xml_verbose()) + fprintf(stderr, "%s: ignoring cache_associativity attribute for non-cache object type\n", + state->global->msgprefix); + } + + else if (!strcmp(name, "cache_type")) { + unsigned long lvalue = strtoul(value, NULL, 10); + if (obj->type == HWLOC_OBJ_CACHE) { + if (lvalue == HWLOC_OBJ_CACHE_UNIFIED + || lvalue == HWLOC_OBJ_CACHE_DATA + || lvalue == HWLOC_OBJ_CACHE_INSTRUCTION) + obj->attr->cache.type = (hwloc_obj_cache_type_t) lvalue; + else + fprintf(stderr, "%s: ignoring invalid cache_type attribute %ld\n", + state->global->msgprefix, lvalue); + } else if (hwloc__xml_verbose()) + fprintf(stderr, "%s: ignoring cache_type attribute for non-cache object type\n", + state->global->msgprefix); + } + + else if (!strcmp(name, "local_memory")) + obj->memory.local_memory = strtoull(value, NULL, 10); + + else if (!strcmp(name, "depth")) { + unsigned long lvalue = strtoul(value, NULL, 10); + switch (obj->type) { + case HWLOC_OBJ_CACHE: + obj->attr->cache.depth = lvalue; + break; + case HWLOC_OBJ_GROUP: + obj->attr->group.depth = lvalue; + break; + case HWLOC_OBJ_BRIDGE: + obj->attr->bridge.depth = lvalue; + break; + default: + if (hwloc__xml_verbose()) + fprintf(stderr, "%s: ignoring depth attribute for object type without depth\n", + state->global->msgprefix); + break; + } + } + + else if (!strcmp(name, "pci_busid")) { + switch (obj->type) { + case HWLOC_OBJ_PCI_DEVICE: + case HWLOC_OBJ_BRIDGE: { + unsigned domain, bus, dev, func; + if (sscanf(value, "%04x:%02x:%02x.%01x", + &domain, &bus, &dev, &func) != 4) { + if (hwloc__xml_verbose()) + fprintf(stderr, "%s: ignoring invalid pci_busid format string %s\n", + state->global->msgprefix, value); + } else { + obj->attr->pcidev.domain = domain; + obj->attr->pcidev.bus = bus; + obj->attr->pcidev.dev = dev; + obj->attr->pcidev.func = func; + } + break; + } + default: + if (hwloc__xml_verbose()) + fprintf(stderr, "%s: ignoring pci_busid attribute for non-PCI object\n", + state->global->msgprefix); + break; + } + } + + else if (!strcmp(name, "pci_type")) { + switch (obj->type) { + case HWLOC_OBJ_PCI_DEVICE: + case HWLOC_OBJ_BRIDGE: { + unsigned classid, vendor, device, subvendor, subdevice, revision; + if (sscanf(value, "%04x [%04x:%04x] [%04x:%04x] %02x", + &classid, &vendor, &device, &subvendor, &subdevice, &revision) != 6) { + if (hwloc__xml_verbose()) + fprintf(stderr, "%s: ignoring invalid pci_type format string %s\n", + state->global->msgprefix, value); + } else { + obj->attr->pcidev.class_id = classid; + obj->attr->pcidev.vendor_id = vendor; + obj->attr->pcidev.device_id = device; + obj->attr->pcidev.subvendor_id = subvendor; + obj->attr->pcidev.subdevice_id = subdevice; + obj->attr->pcidev.revision = revision; + } + break; + } + default: + if (hwloc__xml_verbose()) + fprintf(stderr, "%s: ignoring pci_type attribute for non-PCI object\n", + state->global->msgprefix); + break; + } + } + + else if (!strcmp(name, "pci_link_speed")) { + switch (obj->type) { + case HWLOC_OBJ_PCI_DEVICE: + case HWLOC_OBJ_BRIDGE: { + obj->attr->pcidev.linkspeed = (float) atof(value); + break; + } + default: + if (hwloc__xml_verbose()) + fprintf(stderr, "%s: ignoring pci_link_speed attribute for non-PCI object\n", + state->global->msgprefix); + break; + } + } + + else if (!strcmp(name, "bridge_type")) { + switch (obj->type) { + case HWLOC_OBJ_BRIDGE: { + unsigned upstream_type, downstream_type; + if (sscanf(value, "%u-%u", &upstream_type, &downstream_type) != 2) { + if (hwloc__xml_verbose()) + fprintf(stderr, "%s: ignoring invalid bridge_type format string %s\n", + state->global->msgprefix, value); + } else { + obj->attr->bridge.upstream_type = (hwloc_obj_bridge_type_t) upstream_type; + obj->attr->bridge.downstream_type = (hwloc_obj_bridge_type_t) downstream_type; + }; + break; + } + default: + if (hwloc__xml_verbose()) + fprintf(stderr, "%s: ignoring bridge_type attribute for non-bridge object\n", + state->global->msgprefix); + break; + } + } + + else if (!strcmp(name, "bridge_pci")) { + switch (obj->type) { + case HWLOC_OBJ_BRIDGE: { + unsigned domain, secbus, subbus; + if (sscanf(value, "%04x:[%02x-%02x]", + &domain, &secbus, &subbus) != 3) { + if (hwloc__xml_verbose()) + fprintf(stderr, "%s: ignoring invalid bridge_pci format string %s\n", + state->global->msgprefix, value); + } else { + obj->attr->bridge.downstream.pci.domain = domain; + obj->attr->bridge.downstream.pci.secondary_bus = secbus; + obj->attr->bridge.downstream.pci.subordinate_bus = subbus; + } + break; + } + default: + if (hwloc__xml_verbose()) + fprintf(stderr, "%s: ignoring bridge_pci attribute for non-bridge object\n", + state->global->msgprefix); + break; + } + } + + else if (!strcmp(name, "osdev_type")) { + switch (obj->type) { + case HWLOC_OBJ_OS_DEVICE: { + unsigned osdev_type; + if (sscanf(value, "%u", &osdev_type) != 1) { + if (hwloc__xml_verbose()) + fprintf(stderr, "%s: ignoring invalid osdev_type format string %s\n", + state->global->msgprefix, value); + } else + obj->attr->osdev.type = (hwloc_obj_osdev_type_t) osdev_type; + break; + } + default: + if (hwloc__xml_verbose()) + fprintf(stderr, "%s: ignoring osdev_type attribute for non-osdev object\n", + state->global->msgprefix); + break; + } + } + + + + + /************************* + * deprecated (from 1.0) + */ + else if (!strcmp(name, "dmi_board_vendor")) { + hwloc_obj_add_info(obj, "DMIBoardVendor", value); + } + else if (!strcmp(name, "dmi_board_name")) { + hwloc_obj_add_info(obj, "DMIBoardName", value); + } + + /************************* + * deprecated (from 0.9) + */ + else if (!strcmp(name, "memory_kB")) { + unsigned long long lvalue = strtoull(value, NULL, 10); + switch (obj->type) { + case HWLOC_OBJ_CACHE: + obj->attr->cache.size = lvalue << 10; + break; + case HWLOC_OBJ_NUMANODE: + case HWLOC_OBJ_MACHINE: + case HWLOC_OBJ_SYSTEM: + obj->memory.local_memory = lvalue << 10; + break; + default: + if (hwloc__xml_verbose()) + fprintf(stderr, "%s: ignoring memory_kB attribute for object type without memory\n", + state->global->msgprefix); + break; + } + } + else if (!strcmp(name, "huge_page_size_kB")) { + unsigned long lvalue = strtoul(value, NULL, 10); + switch (obj->type) { + case HWLOC_OBJ_NUMANODE: + case HWLOC_OBJ_MACHINE: + case HWLOC_OBJ_SYSTEM: + if (!obj->memory.page_types) { + obj->memory.page_types = malloc(sizeof(*obj->memory.page_types)); + obj->memory.page_types_len = 1; + } + obj->memory.page_types[0].size = lvalue << 10; + break; + default: + if (hwloc__xml_verbose()) + fprintf(stderr, "%s: ignoring huge_page_size_kB attribute for object type without huge pages\n", + state->global->msgprefix); + break; + } + } + else if (!strcmp(name, "huge_page_free")) { + unsigned long lvalue = strtoul(value, NULL, 10); + switch (obj->type) { + case HWLOC_OBJ_NUMANODE: + case HWLOC_OBJ_MACHINE: + case HWLOC_OBJ_SYSTEM: + if (!obj->memory.page_types) { + obj->memory.page_types = malloc(sizeof(*obj->memory.page_types)); + obj->memory.page_types_len = 1; + } + obj->memory.page_types[0].count = lvalue; + break; + default: + if (hwloc__xml_verbose()) + fprintf(stderr, "%s: ignoring huge_page_free attribute for object type without huge pages\n", + state->global->msgprefix); + break; + } + } + /* + * end of deprecated (from 0.9) + *******************************/ + + + + else if (hwloc__xml_verbose()) + fprintf(stderr, "%s: ignoring unknown object attribute %s\n", + state->global->msgprefix, name); +} + + +static int +hwloc__xml_import_info(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_obj_t obj, + hwloc__xml_import_state_t state) +{ + char *infoname = NULL; + char *infovalue = NULL; + + while (1) { + char *attrname, *attrvalue; + if (state->global->next_attr(state, &attrname, &attrvalue) < 0) + break; + if (!strcmp(attrname, "name")) + infoname = attrvalue; + else if (!strcmp(attrname, "value")) + infovalue = attrvalue; + else + return -1; + } + + if (infoname) + /* empty strings are ignored by libxml */ + hwloc_obj_add_info(obj, infoname, infovalue ? infovalue : ""); + + return state->global->close_tag(state); +} + +static int +hwloc__xml_import_pagetype(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_obj_t obj, + hwloc__xml_import_state_t state) +{ + uint64_t size = 0, count = 0; + + while (1) { + char *attrname, *attrvalue; + if (state->global->next_attr(state, &attrname, &attrvalue) < 0) + break; + if (!strcmp(attrname, "size")) + size = strtoull(attrvalue, NULL, 10); + else if (!strcmp(attrname, "count")) + count = strtoull(attrvalue, NULL, 10); + else + return -1; + } + + if (size) { + int idx = obj->memory.page_types_len; + obj->memory.page_types = realloc(obj->memory.page_types, (idx+1)*sizeof(*obj->memory.page_types)); + obj->memory.page_types_len = idx+1; + obj->memory.page_types[idx].size = size; + obj->memory.page_types[idx].count = count; + } + + return state->global->close_tag(state); +} + +static int +hwloc__xml_import_distances(struct hwloc_xml_backend_data_s *data, + hwloc_obj_t obj, + hwloc__xml_import_state_t state) +{ + unsigned long reldepth = 0, nbobjs = 0; + float latbase = 0; + char *tag; + int ret; + + while (1) { + char *attrname, *attrvalue; + if (state->global->next_attr(state, &attrname, &attrvalue) < 0) + break; + if (!strcmp(attrname, "nbobjs")) + nbobjs = strtoul(attrvalue, NULL, 10); + else if (!strcmp(attrname, "relative_depth")) + reldepth = strtoul(attrvalue, NULL, 10); + else if (!strcmp(attrname, "latency_base")) + latbase = (float) atof(attrvalue); + else + return -1; + } + + if (nbobjs && reldepth && latbase) { + unsigned i; + float *matrix, latmax = 0; + struct hwloc_xml_imported_distances_s *distances; + + distances = malloc(sizeof(*distances)); + distances->root = obj; + distances->distances.relative_depth = reldepth; + distances->distances.nbobjs = nbobjs; + distances->distances.latency = matrix = malloc(nbobjs*nbobjs*sizeof(float)); + distances->distances.latency_base = latbase; + + for(i=0; iglobal->find_child(state, &childstate, &tag); + if (ret <= 0 || strcmp(tag, "latency")) { + /* a latency child is needed */ + free(distances->distances.latency); + free(distances); + return -1; + } + + ret = state->global->next_attr(&childstate, &attrname, &attrvalue); + if (ret < 0 || strcmp(attrname, "value")) { + free(distances->distances.latency); + free(distances); + return -1; + } + + val = (float) atof((char *) attrvalue); + matrix[i] = val; + if (val > latmax) + latmax = val; + + ret = state->global->close_tag(&childstate); + if (ret < 0) + return -1; + + state->global->close_child(&childstate); + } + + distances->distances.latency_max = latmax; + + if (data->last_distances) + data->last_distances->next = distances; + else + data->first_distances = distances; + distances->prev = data->last_distances; + distances->next = NULL; + } + + return state->global->close_tag(state); +} + +static int +hwloc__xml_import_userdata(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_obj_t obj, + hwloc__xml_import_state_t state) +{ + size_t length = 0; + int encoded = 0; + char *name = NULL; /* optional */ + + while (1) { + char *attrname, *attrvalue; + if (state->global->next_attr(state, &attrname, &attrvalue) < 0) + break; + if (!strcmp(attrname, "length")) + length = strtoul(attrvalue, NULL, 10); + else if (!strcmp(attrname, "encoding")) + encoded = !strcmp(attrvalue, "base64"); + else if (!strcmp(attrname, "name")) + name = attrvalue; + else + return -1; + } + + if (length && topology->userdata_import_cb) { + int ret; + + if (encoded) { + char *encoded_buffer; + size_t encoded_length = 4*((length+2)/3); + ret = state->global->get_content(state, &encoded_buffer, encoded_length); + if (ret < 0) + return -1; + if (ret) { + char *decoded_buffer = malloc(length+1); + if (!decoded_buffer) + return -1; + assert(encoded_buffer[encoded_length] == 0); + ret = hwloc_decode_from_base64(encoded_buffer, decoded_buffer, length+1); + if (ret != (int) length) + return -1; + topology->userdata_import_cb(topology, obj, name, decoded_buffer, length); + free(decoded_buffer); + } + } else { + char *buffer; + ret = state->global->get_content(state, &buffer, length); + if (ret < 0) + return -1; + topology->userdata_import_cb(topology, obj, name, buffer, length); + } + state->global->close_content(state); + } + return state->global->close_tag(state); +} + +static int +hwloc__xml_import_object(hwloc_topology_t topology, + struct hwloc_xml_backend_data_s *data, + hwloc_obj_t obj, + hwloc__xml_import_state_t state) +{ + hwloc_obj_t parent = obj->parent; + + /* process attributes */ + while (1) { + char *attrname, *attrvalue; + if (state->global->next_attr(state, &attrname, &attrvalue) < 0) + break; + if (!strcmp(attrname, "type")) { + if (hwloc_obj_type_sscanf(attrvalue, &obj->type, NULL, NULL, 0) < 0) + goto error; + } else { + /* type needed first */ + if (obj->type == (hwloc_obj_type_t)-1) + goto error; + hwloc__xml_import_object_attr(topology, obj, attrname, attrvalue, state); + } + } + + if (parent) { + /* root->parent is NULL, and root is already inserted */ + + /* warn if inserting out-of-order */ + if (parent->cpuset) { /* don't compare children if multinode parent */ + hwloc_obj_t *current; + for (current = &parent->first_child; *current; current = &(*current)->next_sibling) { + hwloc_bitmap_t curcpuset = (*current)->cpuset; + if (obj->cpuset && (!curcpuset || hwloc__object_cpusets_compare_first(obj, *current) < 0)) { + static int reported = 0; + if (!reported && !hwloc_hide_errors()) { + char *progname = hwloc_progname(topology); + const char *origversion = hwloc_obj_get_info_by_name(topology->levels[0][0], "hwlocVersion"); + const char *origprogname = hwloc_obj_get_info_by_name(topology->levels[0][0], "ProcessName"); + char *c1, *cc1, t1[64]; + char *c2 = NULL, *cc2 = NULL, t2[64]; + hwloc_bitmap_asprintf(&c1, obj->cpuset); + hwloc_bitmap_asprintf(&cc1, obj->complete_cpuset); + hwloc_obj_type_snprintf(t1, sizeof(t1), obj, 0); + if (curcpuset) + hwloc_bitmap_asprintf(&c2, curcpuset); + if ((*current)->complete_cpuset) + hwloc_bitmap_asprintf(&cc2, (*current)->complete_cpuset); + hwloc_obj_type_snprintf(t2, sizeof(t2), *current, 0); + fprintf(stderr, "****************************************************************************\n"); + fprintf(stderr, "* hwloc has encountered an out-of-order XML topology load.\n"); + fprintf(stderr, "* Object %s cpuset %s complete %s\n", + t1, c1, cc1); + fprintf(stderr, "* was inserted after object %s with %s and %s.\n", + t2, c2 ? c2 : "none", cc2 ? cc2 : "none"); + fprintf(stderr, "* The error occured in hwloc %s inside process `%s', while\n", + HWLOC_VERSION, + progname ? progname : ""); + if (origversion || origprogname) + fprintf(stderr, "* the input XML was generated by hwloc %s inside process `%s'.\n", + origversion ? origversion : "(unknown version)", + origprogname ? origprogname : ""); + else + fprintf(stderr, "* the input XML was generated by an unspecified ancient hwloc release.\n"); + fprintf(stderr, "* Please check that your input topology XML file is valid.\n"); + fprintf(stderr, "****************************************************************************\n"); + free(c1); + free(cc1); + if (c2) + free(c2); + if (cc2) + free(cc2); + free(progname); + reported = 1; + } + } + } + } + + hwloc_insert_object_by_parent(topology, obj->parent /* filled by the caller */, obj); + /* insert_object_by_parent() doesn't merge during insert, so obj is still valid */ + } + + /* process subnodes */ + while (1) { + struct hwloc__xml_import_state_s childstate; + char *tag; + int ret; + + ret = state->global->find_child(state, &childstate, &tag); + if (ret < 0) + goto error; + if (!ret) + break; + + if (!strcmp(tag, "object")) { + hwloc_obj_t childobj = hwloc_alloc_setup_object(HWLOC_OBJ_TYPE_MAX, -1); + childobj->parent = obj; /* store the parent pointer for use in insert() below */ + ret = hwloc__xml_import_object(topology, data, childobj, &childstate); + } else if (!strcmp(tag, "page_type")) { + ret = hwloc__xml_import_pagetype(topology, obj, &childstate); + } else if (!strcmp(tag, "info")) { + ret = hwloc__xml_import_info(topology, obj, &childstate); + } else if (!strcmp(tag, "distances")) { + ret = hwloc__xml_import_distances(data, obj, &childstate); + } else if (!strcmp(tag, "userdata")) { + ret = hwloc__xml_import_userdata(topology, obj, &childstate); + } else + ret = -1; + + if (ret < 0) + goto error; + + state->global->close_child(&childstate); + } + + return state->global->close_tag(state); + + error: + hwloc_free_unlinked_object(obj); + return -1; +} + +static int +hwloc__xml_import_diff_one(hwloc__xml_import_state_t state, + hwloc_topology_diff_t *firstdiffp, + hwloc_topology_diff_t *lastdiffp) +{ + char *type_s = NULL; + char *obj_depth_s = NULL; + char *obj_index_s = NULL; + char *obj_attr_type_s = NULL; +/* char *obj_attr_index_s = NULL; unused for now */ + char *obj_attr_name_s = NULL; + char *obj_attr_oldvalue_s = NULL; + char *obj_attr_newvalue_s = NULL; + + while (1) { + char *attrname, *attrvalue; + if (state->global->next_attr(state, &attrname, &attrvalue) < 0) + break; + if (!strcmp(attrname, "type")) + type_s = attrvalue; + else if (!strcmp(attrname, "obj_depth")) + obj_depth_s = attrvalue; + else if (!strcmp(attrname, "obj_index")) + obj_index_s = attrvalue; + else if (!strcmp(attrname, "obj_attr_type")) + obj_attr_type_s = attrvalue; + else if (!strcmp(attrname, "obj_attr_index")) + { /* obj_attr_index_s = attrvalue; unused for now */ } + else if (!strcmp(attrname, "obj_attr_name")) + obj_attr_name_s = attrvalue; + else if (!strcmp(attrname, "obj_attr_oldvalue")) + obj_attr_oldvalue_s = attrvalue; + else if (!strcmp(attrname, "obj_attr_newvalue")) + obj_attr_newvalue_s = attrvalue; + else { + if (hwloc__xml_verbose()) + fprintf(stderr, "%s: ignoring unknown diff attribute %s\n", + state->global->msgprefix, attrname); + return -1; + } + } + + if (type_s) { + switch (atoi(type_s)) { + default: + break; + case HWLOC_TOPOLOGY_DIFF_OBJ_ATTR: { + /* object attribute diff */ + hwloc_topology_diff_obj_attr_type_t obj_attr_type; + hwloc_topology_diff_t diff; + + /* obj_attr mandatory generic attributes */ + if (!obj_depth_s || !obj_index_s || !obj_attr_type_s) { + if (hwloc__xml_verbose()) + fprintf(stderr, "%s: missing mandatory obj attr generic attributes\n", + state->global->msgprefix); + break; + } + + /* obj_attr mandatory attributes common to all subtypes */ + if (!obj_attr_oldvalue_s || !obj_attr_newvalue_s) { + if (hwloc__xml_verbose()) + fprintf(stderr, "%s: missing mandatory obj attr value attributes\n", + state->global->msgprefix); + break; + } + + /* mandatory attributes for obj_attr_info subtype */ + obj_attr_type = atoi(obj_attr_type_s); + if (obj_attr_type == HWLOC_TOPOLOGY_DIFF_OBJ_ATTR_INFO && !obj_attr_name_s) { + if (hwloc__xml_verbose()) + fprintf(stderr, "%s: missing mandatory obj attr info name attribute\n", + state->global->msgprefix); + break; + } + + /* now we know we have everything we need */ + diff = malloc(sizeof(*diff)); + if (!diff) + return -1; + diff->obj_attr.type = HWLOC_TOPOLOGY_DIFF_OBJ_ATTR; + diff->obj_attr.obj_depth = atoi(obj_depth_s); + diff->obj_attr.obj_index = atoi(obj_index_s); + memset(&diff->obj_attr.diff, 0, sizeof(diff->obj_attr.diff)); + diff->obj_attr.diff.generic.type = obj_attr_type; + + switch (atoi(obj_attr_type_s)) { + case HWLOC_TOPOLOGY_DIFF_OBJ_ATTR_SIZE: + diff->obj_attr.diff.uint64.oldvalue = strtoull(obj_attr_oldvalue_s, NULL, 0); + diff->obj_attr.diff.uint64.newvalue = strtoull(obj_attr_newvalue_s, NULL, 0); + break; + case HWLOC_TOPOLOGY_DIFF_OBJ_ATTR_INFO: + diff->obj_attr.diff.string.name = strdup(obj_attr_name_s); + /* fallthrough */ + case HWLOC_TOPOLOGY_DIFF_OBJ_ATTR_NAME: + diff->obj_attr.diff.string.oldvalue = strdup(obj_attr_oldvalue_s); + diff->obj_attr.diff.string.newvalue = strdup(obj_attr_newvalue_s); + break; + } + + if (*firstdiffp) + (*lastdiffp)->generic.next = diff; + else + *firstdiffp = diff; + *lastdiffp = diff; + diff->generic.next = NULL; + } + } + } + + return state->global->close_tag(state); +} + +int +hwloc__xml_import_diff(hwloc__xml_import_state_t state, + hwloc_topology_diff_t *firstdiffp) +{ + hwloc_topology_diff_t firstdiff = NULL, lastdiff = NULL; + *firstdiffp = NULL; + + while (1) { + struct hwloc__xml_import_state_s childstate; + char *tag; + int ret; + + ret = state->global->find_child(state, &childstate, &tag); + if (ret < 0) + return -1; + if (!ret) + break; + + if (!strcmp(tag, "diff")) { + ret = hwloc__xml_import_diff_one(&childstate, &firstdiff, &lastdiff); + } else + ret = -1; + + if (ret < 0) + return ret; + + state->global->close_child(&childstate); + } + + *firstdiffp = firstdiff; + return 0; +} + +/*********************************** + ********* main XML import ********* + ***********************************/ + +static int +hwloc_xml__handle_distances(struct hwloc_topology *topology, + struct hwloc_xml_backend_data_s *data, + const char *msgprefix) +{ + struct hwloc_xml_imported_distances_s *xmldist, *next = data->first_distances; + + if (!next) + return 0; + + /* connect things now because we need levels to check/build, they'll be reconnected properly later anyway */ + hwloc_connect_children(topology->levels[0][0]); + if (hwloc_connect_levels(topology) < 0) + return -1; + + while ((xmldist = next) != NULL) { + hwloc_obj_t root = xmldist->root; + unsigned depth = root->depth + xmldist->distances.relative_depth; + unsigned nbobjs = hwloc_get_nbobjs_inside_cpuset_by_depth(topology, root->cpuset, depth); + if (nbobjs != xmldist->distances.nbobjs) { + /* distances invalid, drop */ + if (hwloc__xml_verbose()) + fprintf(stderr, "%s: ignoring invalid distance matrix with %u objs instead of %u\n", + msgprefix, xmldist->distances.nbobjs, nbobjs); + free(xmldist->distances.latency); + } else { + /* distances valid, add it to the internal OS distances list for grouping */ + unsigned *indexes = malloc(nbobjs * sizeof(unsigned)); + hwloc_obj_t child, *objs = malloc(nbobjs * sizeof(hwloc_obj_t)); + unsigned j; + for(j=0, child = hwloc_get_next_obj_inside_cpuset_by_depth(topology, root->cpuset, depth, NULL); + jcpuset, depth, child)) { + indexes[j] = child->os_index; + objs[j] = child; + } + for(j=0; jdistances.latency[j] *= xmldist->distances.latency_base; + hwloc_distances_set(topology, objs[0]->type, nbobjs, indexes, objs, xmldist->distances.latency, 0 /* XML cannot force */); + } + + next = xmldist->next; + free(xmldist); + } + + return 0; +} + +/* this canNOT be the first XML call */ +static int +hwloc_look_xml(struct hwloc_backend *backend) +{ + struct hwloc_topology *topology = backend->topology; + struct hwloc_xml_backend_data_s *data = backend->private_data; + struct hwloc__xml_import_state_s state, childstate; + char *tag; + hwloc_localeswitch_declare; + int ret; + + state.global = data; + + assert(!topology->levels[0][0]->cpuset); + + hwloc_localeswitch_init(); + + data->first_distances = data->last_distances = NULL; + + ret = data->look_init(data, &state); + if (ret < 0) + goto failed; + + /* find root object tag and import it */ + ret = state.global->find_child(&state, &childstate, &tag); + if (ret < 0 || !ret || strcmp(tag, "object")) + goto failed; + ret = hwloc__xml_import_object(topology, data, topology->levels[0][0], &childstate); + if (ret < 0) + goto failed; + state.global->close_child(&childstate); + + /* find end of topology tag */ + state.global->close_tag(&state); + + /* keep the "Backend" information intact */ + /* we could add "BackendSource=XML" to notify that XML was used between the actual backend and here */ + + /* if we added some distances, we must check them, and make them groupable */ + if (hwloc_xml__handle_distances(topology, data, data->msgprefix) < 0) + goto err; + data->first_distances = data->last_distances = NULL; + topology->support.discovery->pu = 1; + + hwloc_localeswitch_fini(); + return 1; + + failed: + if (data->look_failed) + data->look_failed(data); + if (hwloc__xml_verbose()) + fprintf(stderr, "%s: XML component discovery failed.\n", + data->msgprefix); + err: + hwloc_localeswitch_fini(); + return -1; +} + +/* this can be the first XML call */ +int +hwloc_topology_diff_load_xml(hwloc_topology_t topology __hwloc_attribute_unused, + const char *xmlpath, + hwloc_topology_diff_t *firstdiffp, char **refnamep) +{ + struct hwloc__xml_import_state_s state; + struct hwloc_xml_backend_data_s fakedata; /* only for storing global info during parsing */ + hwloc_localeswitch_declare; + const char *basename; + int force_nolibxml; + int ret; + + state.global = &fakedata; + + basename = strrchr(xmlpath, '/'); + if (basename) + basename++; + else + basename = xmlpath; + fakedata.msgprefix = strdup(basename); + + if (!hwloc_libxml_callbacks && !hwloc_nolibxml_callbacks) { + errno = ENOSYS; + return -1; + } + + hwloc_localeswitch_init(); + + *firstdiffp = NULL; + + force_nolibxml = hwloc_nolibxml_import(); +retry: + if (!hwloc_libxml_callbacks || (hwloc_nolibxml_callbacks && force_nolibxml)) + ret = hwloc_nolibxml_callbacks->import_diff(&state, xmlpath, NULL, 0, firstdiffp, refnamep); + else { + ret = hwloc_libxml_callbacks->import_diff(&state, xmlpath, NULL, 0, firstdiffp, refnamep); + if (ret < 0 && errno == ENOSYS) { + hwloc_libxml_callbacks = NULL; + goto retry; + } + } + + hwloc_localeswitch_fini(); + + free(fakedata.msgprefix); + return ret; +} + +/* this can be the first XML call */ +int +hwloc_topology_diff_load_xmlbuffer(hwloc_topology_t topology __hwloc_attribute_unused, + const char *xmlbuffer, int buflen, + hwloc_topology_diff_t *firstdiffp, char **refnamep) +{ + struct hwloc__xml_import_state_s state; + struct hwloc_xml_backend_data_s fakedata; /* only for storing global info during parsing */ + hwloc_localeswitch_declare; + int force_nolibxml; + int ret; + + state.global = &fakedata; + fakedata.msgprefix = "xmldiffbuffer"; + + if (!hwloc_libxml_callbacks && !hwloc_nolibxml_callbacks) { + errno = ENOSYS; + return -1; + } + + hwloc_localeswitch_init(); + + *firstdiffp = NULL; + + force_nolibxml = hwloc_nolibxml_import(); + retry: + if (!hwloc_libxml_callbacks || (hwloc_nolibxml_callbacks && force_nolibxml)) + ret = hwloc_nolibxml_callbacks->import_diff(&state, NULL, xmlbuffer, buflen, firstdiffp, refnamep); + else { + ret = hwloc_libxml_callbacks->import_diff(&state, NULL, xmlbuffer, buflen, firstdiffp, refnamep); + if (ret < 0 && errno == ENOSYS) { + hwloc_libxml_callbacks = NULL; + goto retry; + } + } + + hwloc_localeswitch_fini(); + return ret; +} + +/************************************************ + ********* XML export (common routines) ********* + ************************************************/ + +#define HWLOC_XML_CHAR_VALID(c) (((c) >= 32 && (c) <= 126) || (c) == '\t' || (c) == '\n' || (c) == '\r') + +static int +hwloc__xml_export_check_buffer(const char *buf, size_t length) +{ + unsigned i; + for(i=0; inew_child(parentstate, &state, "object"); + + state.new_prop(&state, "type", hwloc_obj_type_string(obj->type)); + if (obj->os_level != -1) { + sprintf(tmp, "%d", obj->os_level); + state.new_prop(&state, "os_level", tmp); + } + if (obj->os_index != (unsigned) -1) { + sprintf(tmp, "%u", obj->os_index); + state.new_prop(&state, "os_index", tmp); + } + if (obj->cpuset) { + hwloc_bitmap_asprintf(&cpuset, obj->cpuset); + state.new_prop(&state, "cpuset", cpuset); + free(cpuset); + } + if (obj->complete_cpuset) { + hwloc_bitmap_asprintf(&cpuset, obj->complete_cpuset); + state.new_prop(&state, "complete_cpuset", cpuset); + free(cpuset); + } + if (obj->online_cpuset) { + hwloc_bitmap_asprintf(&cpuset, obj->online_cpuset); + state.new_prop(&state, "online_cpuset", cpuset); + free(cpuset); + } + if (obj->allowed_cpuset) { + hwloc_bitmap_asprintf(&cpuset, obj->allowed_cpuset); + state.new_prop(&state, "allowed_cpuset", cpuset); + free(cpuset); + } + if (obj->nodeset && !hwloc_bitmap_isfull(obj->nodeset)) { + hwloc_bitmap_asprintf(&cpuset, obj->nodeset); + state.new_prop(&state, "nodeset", cpuset); + free(cpuset); + } + if (obj->complete_nodeset && !hwloc_bitmap_isfull(obj->complete_nodeset)) { + hwloc_bitmap_asprintf(&cpuset, obj->complete_nodeset); + state.new_prop(&state, "complete_nodeset", cpuset); + free(cpuset); + } + if (obj->allowed_nodeset && !hwloc_bitmap_isfull(obj->allowed_nodeset)) { + hwloc_bitmap_asprintf(&cpuset, obj->allowed_nodeset); + state.new_prop(&state, "allowed_nodeset", cpuset); + free(cpuset); + } + + if (obj->name) { + char *name = hwloc__xml_export_safestrdup(obj->name); + state.new_prop(&state, "name", name); + free(name); + } + + switch (obj->type) { + case HWLOC_OBJ_CACHE: + sprintf(tmp, "%llu", (unsigned long long) obj->attr->cache.size); + state.new_prop(&state, "cache_size", tmp); + sprintf(tmp, "%u", obj->attr->cache.depth); + state.new_prop(&state, "depth", tmp); + sprintf(tmp, "%u", (unsigned) obj->attr->cache.linesize); + state.new_prop(&state, "cache_linesize", tmp); + sprintf(tmp, "%d", (unsigned) obj->attr->cache.associativity); + state.new_prop(&state, "cache_associativity", tmp); + sprintf(tmp, "%d", (unsigned) obj->attr->cache.type); + state.new_prop(&state, "cache_type", tmp); + break; + case HWLOC_OBJ_GROUP: + sprintf(tmp, "%u", obj->attr->group.depth); + state.new_prop(&state, "depth", tmp); + break; + case HWLOC_OBJ_BRIDGE: + sprintf(tmp, "%u-%u", obj->attr->bridge.upstream_type, obj->attr->bridge.downstream_type); + state.new_prop(&state, "bridge_type", tmp); + sprintf(tmp, "%u", obj->attr->bridge.depth); + state.new_prop(&state, "depth", tmp); + if (obj->attr->bridge.downstream_type == HWLOC_OBJ_BRIDGE_PCI) { + sprintf(tmp, "%04x:[%02x-%02x]", + (unsigned) obj->attr->bridge.downstream.pci.domain, + (unsigned) obj->attr->bridge.downstream.pci.secondary_bus, + (unsigned) obj->attr->bridge.downstream.pci.subordinate_bus); + state.new_prop(&state, "bridge_pci", tmp); + } + if (obj->attr->bridge.upstream_type != HWLOC_OBJ_BRIDGE_PCI) + break; + /* fallthrough */ + case HWLOC_OBJ_PCI_DEVICE: + sprintf(tmp, "%04x:%02x:%02x.%01x", + (unsigned) obj->attr->pcidev.domain, + (unsigned) obj->attr->pcidev.bus, + (unsigned) obj->attr->pcidev.dev, + (unsigned) obj->attr->pcidev.func); + state.new_prop(&state, "pci_busid", tmp); + sprintf(tmp, "%04x [%04x:%04x] [%04x:%04x] %02x", + (unsigned) obj->attr->pcidev.class_id, + (unsigned) obj->attr->pcidev.vendor_id, (unsigned) obj->attr->pcidev.device_id, + (unsigned) obj->attr->pcidev.subvendor_id, (unsigned) obj->attr->pcidev.subdevice_id, + (unsigned) obj->attr->pcidev.revision); + state.new_prop(&state, "pci_type", tmp); + sprintf(tmp, "%f", obj->attr->pcidev.linkspeed); + state.new_prop(&state, "pci_link_speed", tmp); + break; + case HWLOC_OBJ_OS_DEVICE: + sprintf(tmp, "%u", obj->attr->osdev.type); + state.new_prop(&state, "osdev_type", tmp); + break; + default: + break; + } + + if (obj->memory.local_memory) { + sprintf(tmp, "%llu", (unsigned long long) obj->memory.local_memory); + state.new_prop(&state, "local_memory", tmp); + } + + for(i=0; imemory.page_types_len; i++) { + struct hwloc__xml_export_state_s childstate; + state.new_child(&state, &childstate, "page_type"); + sprintf(tmp, "%llu", (unsigned long long) obj->memory.page_types[i].size); + childstate.new_prop(&childstate, "size", tmp); + sprintf(tmp, "%llu", (unsigned long long) obj->memory.page_types[i].count); + childstate.new_prop(&childstate, "count", tmp); + childstate.end_object(&childstate, "page_type"); + } + + for(i=0; iinfos_count; i++) { + char *name = hwloc__xml_export_safestrdup(obj->infos[i].name); + char *value = hwloc__xml_export_safestrdup(obj->infos[i].value); + struct hwloc__xml_export_state_s childstate; + state.new_child(&state, &childstate, "info"); + childstate.new_prop(&childstate, "name", name); + childstate.new_prop(&childstate, "value", value); + childstate.end_object(&childstate, "info"); + free(name); + free(value); + } + + for(i=0; idistances_count; i++) { + unsigned nbobjs = obj->distances[i]->nbobjs; + unsigned j; + struct hwloc__xml_export_state_s childstate; + state.new_child(&state, &childstate, "distances"); + sprintf(tmp, "%u", nbobjs); + childstate.new_prop(&childstate, "nbobjs", tmp); + sprintf(tmp, "%u", obj->distances[i]->relative_depth); + childstate.new_prop(&childstate, "relative_depth", tmp); + sprintf(tmp, "%f", obj->distances[i]->latency_base); + childstate.new_prop(&childstate, "latency_base", tmp); + for(j=0; jdistances[i]->latency[j]); + greatchildstate.new_prop(&greatchildstate, "value", tmp); + greatchildstate.end_object(&greatchildstate, "latency"); + } + childstate.end_object(&childstate, "distances"); + } + + if (obj->userdata && topology->userdata_export_cb) + topology->userdata_export_cb((void*) &state, topology, obj); + + if (obj->arity) { + unsigned x; + for (x=0; xarity; x++) + hwloc__xml_export_object (&state, topology, obj->children[x]); + } + + state.end_object(&state, "object"); +} + +void +hwloc__xml_export_diff(hwloc__xml_export_state_t parentstate, hwloc_topology_diff_t diff) +{ + while (diff) { + struct hwloc__xml_export_state_s state; + char tmp[255]; + + parentstate->new_child(parentstate, &state, "diff"); + + sprintf(tmp, "%u", diff->generic.type); + state.new_prop(&state, "type", tmp); + + switch (diff->generic.type) { + case HWLOC_TOPOLOGY_DIFF_OBJ_ATTR: + sprintf(tmp, "%d", diff->obj_attr.obj_depth); + state.new_prop(&state, "obj_depth", tmp); + sprintf(tmp, "%u", diff->obj_attr.obj_index); + state.new_prop(&state, "obj_index", tmp); + + sprintf(tmp, "%u", diff->obj_attr.diff.generic.type); + state.new_prop(&state, "obj_attr_type", tmp); + + switch (diff->obj_attr.diff.generic.type) { + case HWLOC_TOPOLOGY_DIFF_OBJ_ATTR_SIZE: + sprintf(tmp, "%llu", (unsigned long long) diff->obj_attr.diff.uint64.index); + state.new_prop(&state, "obj_attr_index", tmp); + sprintf(tmp, "%llu", (unsigned long long) diff->obj_attr.diff.uint64.oldvalue); + state.new_prop(&state, "obj_attr_oldvalue", tmp); + sprintf(tmp, "%llu", (unsigned long long) diff->obj_attr.diff.uint64.newvalue); + state.new_prop(&state, "obj_attr_newvalue", tmp); + break; + case HWLOC_TOPOLOGY_DIFF_OBJ_ATTR_NAME: + case HWLOC_TOPOLOGY_DIFF_OBJ_ATTR_INFO: + if (diff->obj_attr.diff.string.name) + state.new_prop(&state, "obj_attr_name", diff->obj_attr.diff.string.name); + state.new_prop(&state, "obj_attr_oldvalue", diff->obj_attr.diff.string.oldvalue); + state.new_prop(&state, "obj_attr_newvalue", diff->obj_attr.diff.string.newvalue); + break; + } + + break; + default: + assert(0); + } + state.end_object(&state, "diff"); + + diff = diff->generic.next; + } +} + +/********************************** + ********* main XML export ******** + **********************************/ + +/* this can be the first XML call */ +int hwloc_topology_export_xml(hwloc_topology_t topology, const char *filename) +{ + hwloc_localeswitch_declare; + int force_nolibxml; + int ret; + + if (!hwloc_libxml_callbacks && !hwloc_nolibxml_callbacks) { + errno = ENOSYS; + return -1; + } + + hwloc_localeswitch_init(); + + force_nolibxml = hwloc_nolibxml_export(); +retry: + if (!hwloc_libxml_callbacks || (hwloc_nolibxml_callbacks && force_nolibxml)) + ret = hwloc_nolibxml_callbacks->export_file(topology, filename); + else { + ret = hwloc_libxml_callbacks->export_file(topology, filename); + if (ret < 0 && errno == ENOSYS) { + hwloc_libxml_callbacks = NULL; + goto retry; + } + } + + hwloc_localeswitch_fini(); + return ret; +} + +/* this can be the first XML call */ +int hwloc_topology_export_xmlbuffer(hwloc_topology_t topology, char **xmlbuffer, int *buflen) +{ + hwloc_localeswitch_declare; + int force_nolibxml; + int ret; + + if (!hwloc_libxml_callbacks && !hwloc_nolibxml_callbacks) { + errno = ENOSYS; + return -1; + } + + hwloc_localeswitch_init(); + + force_nolibxml = hwloc_nolibxml_export(); +retry: + if (!hwloc_libxml_callbacks || (hwloc_nolibxml_callbacks && force_nolibxml)) + ret = hwloc_nolibxml_callbacks->export_buffer(topology, xmlbuffer, buflen); + else { + ret = hwloc_libxml_callbacks->export_buffer(topology, xmlbuffer, buflen); + if (ret < 0 && errno == ENOSYS) { + hwloc_libxml_callbacks = NULL; + goto retry; + } + } + + hwloc_localeswitch_fini(); + return ret; +} + +/* this can be the first XML call */ +int +hwloc_topology_diff_export_xml(hwloc_topology_t topology __hwloc_attribute_unused, + hwloc_topology_diff_t diff, const char *refname, + const char *filename) +{ + hwloc_localeswitch_declare; + hwloc_topology_diff_t tmpdiff; + int force_nolibxml; + int ret; + + if (!hwloc_libxml_callbacks && !hwloc_nolibxml_callbacks) { + errno = ENOSYS; + return -1; + } + + tmpdiff = diff; + while (tmpdiff) { + if (tmpdiff->generic.type == HWLOC_TOPOLOGY_DIFF_TOO_COMPLEX) { + errno = EINVAL; + return -1; + } + tmpdiff = tmpdiff->generic.next; + } + + hwloc_localeswitch_init(); + + force_nolibxml = hwloc_nolibxml_export(); +retry: + if (!hwloc_libxml_callbacks || (hwloc_nolibxml_callbacks && force_nolibxml)) + ret = hwloc_nolibxml_callbacks->export_diff_file(diff, refname, filename); + else { + ret = hwloc_libxml_callbacks->export_diff_file(diff, refname, filename); + if (ret < 0 && errno == ENOSYS) { + hwloc_libxml_callbacks = NULL; + goto retry; + } + } + + hwloc_localeswitch_fini(); + return ret; +} + +/* this can be the first XML call */ +int +hwloc_topology_diff_export_xmlbuffer(hwloc_topology_t topology __hwloc_attribute_unused, + hwloc_topology_diff_t diff, const char *refname, + char **xmlbuffer, int *buflen) +{ + hwloc_localeswitch_declare; + hwloc_topology_diff_t tmpdiff; + int force_nolibxml; + int ret; + + if (!hwloc_libxml_callbacks && !hwloc_nolibxml_callbacks) { + errno = ENOSYS; + return -1; + } + + tmpdiff = diff; + while (tmpdiff) { + if (tmpdiff->generic.type == HWLOC_TOPOLOGY_DIFF_TOO_COMPLEX) { + errno = EINVAL; + return -1; + } + tmpdiff = tmpdiff->generic.next; + } + + hwloc_localeswitch_init(); + + force_nolibxml = hwloc_nolibxml_export(); +retry: + if (!hwloc_libxml_callbacks || (hwloc_nolibxml_callbacks && force_nolibxml)) + ret = hwloc_nolibxml_callbacks->export_diff_buffer(diff, refname, xmlbuffer, buflen); + else { + ret = hwloc_libxml_callbacks->export_diff_buffer(diff, refname, xmlbuffer, buflen); + if (ret < 0 && errno == ENOSYS) { + hwloc_libxml_callbacks = NULL; + goto retry; + } + } + + hwloc_localeswitch_fini(); + return ret; +} + +void hwloc_free_xmlbuffer(hwloc_topology_t topology __hwloc_attribute_unused, char *xmlbuffer) +{ + int force_nolibxml; + + if (!hwloc_libxml_callbacks && !hwloc_nolibxml_callbacks) { + errno = ENOSYS; + return ; + } + + force_nolibxml = hwloc_nolibxml_export(); + if (!hwloc_libxml_callbacks || (hwloc_nolibxml_callbacks && force_nolibxml)) + hwloc_nolibxml_callbacks->free_buffer(xmlbuffer); + else + hwloc_libxml_callbacks->free_buffer(xmlbuffer); +} + +void +hwloc_topology_set_userdata_export_callback(hwloc_topology_t topology, + void (*export)(void *reserved, struct hwloc_topology *topology, struct hwloc_obj *obj)) +{ + topology->userdata_export_cb = export; +} + +static void +hwloc__export_obj_userdata(hwloc__xml_export_state_t parentstate, int encoded, + const char *name, size_t length, const void *buffer, size_t encoded_length) +{ + struct hwloc__xml_export_state_s state; + char tmp[255]; + parentstate->new_child(parentstate, &state, "userdata"); + if (name) + state.new_prop(&state, "name", name); + sprintf(tmp, "%lu", (unsigned long) length); + state.new_prop(&state, "length", tmp); + if (encoded) + state.new_prop(&state, "encoding", "base64"); + state.add_content(&state, buffer, encoded ? encoded_length : length); + state.end_object(&state, "userdata"); +} + +int +hwloc_export_obj_userdata(void *reserved, + struct hwloc_topology *topology __hwloc_attribute_unused, struct hwloc_obj *obj __hwloc_attribute_unused, + const char *name, const void *buffer, size_t length) +{ + hwloc__xml_export_state_t state = reserved; + + if ((name && hwloc__xml_export_check_buffer(name, strlen(name)) < 0) + || hwloc__xml_export_check_buffer(buffer, length) < 0) { + errno = EINVAL; + return -1; + } + + hwloc__export_obj_userdata(state, 0, name, length, buffer, length); + return 0; +} + +int +hwloc_export_obj_userdata_base64(void *reserved, + struct hwloc_topology *topology __hwloc_attribute_unused, struct hwloc_obj *obj __hwloc_attribute_unused, + const char *name, const void *buffer, size_t length) +{ + hwloc__xml_export_state_t state = reserved; + size_t encoded_length; + char *encoded_buffer; + int ret __hwloc_attribute_unused; + + if (name && hwloc__xml_export_check_buffer(name, strlen(name)) < 0) { + errno = EINVAL; + return -1; + } + + encoded_length = 4*((length+2)/3); + encoded_buffer = malloc(encoded_length+1); + if (!encoded_buffer) { + errno = ENOMEM; + return -1; + } + + ret = hwloc_encode_to_base64(buffer, length, encoded_buffer, encoded_length+1); + assert(ret == (int) encoded_length); + + hwloc__export_obj_userdata(state, 1, name, length, encoded_buffer, encoded_length); + + free(encoded_buffer); + return 0; +} + +void +hwloc_topology_set_userdata_import_callback(hwloc_topology_t topology, + void (*import)(struct hwloc_topology *topology, struct hwloc_obj *obj, const char *name, const void *buffer, size_t length)) +{ + topology->userdata_import_cb = import; +} + +/*************************************** + ************ XML component ************ + ***************************************/ + +static void +hwloc_xml_backend_disable(struct hwloc_backend *backend) +{ + struct hwloc_xml_backend_data_s *data = backend->private_data; + data->backend_exit(data); + free(data->msgprefix); + free(data); +} + +static struct hwloc_backend * +hwloc_xml_component_instantiate(struct hwloc_disc_component *component, + const void *_data1, + const void *_data2, + const void *_data3) +{ + struct hwloc_xml_backend_data_s *data; + struct hwloc_backend *backend; + int force_nolibxml; + const char * xmlpath = (const char *) _data1; + const char * xmlbuffer = (const char *) _data2; + int xmlbuflen = (int)(uintptr_t) _data3; + const char *basename; + int err; + + if (!hwloc_libxml_callbacks && !hwloc_nolibxml_callbacks) { + errno = ENOSYS; + goto out; + } + + if (!xmlpath && !xmlbuffer) { + errno = EINVAL; + goto out; + } + + backend = hwloc_backend_alloc(component); + if (!backend) + goto out; + + data = malloc(sizeof(*data)); + if (!data) { + errno = ENOMEM; + goto out_with_backend; + } + + backend->private_data = data; + backend->discover = hwloc_look_xml; + backend->disable = hwloc_xml_backend_disable; + backend->is_thissystem = 0; + + if (xmlpath) { + basename = strrchr(xmlpath, '/'); + if (basename) + basename++; + else + basename = xmlpath; + } else { + basename = "xmlbuffer"; + } + data->msgprefix = strdup(basename); + + force_nolibxml = hwloc_nolibxml_import(); +retry: + if (!hwloc_libxml_callbacks || (hwloc_nolibxml_callbacks && force_nolibxml)) + err = hwloc_nolibxml_callbacks->backend_init(data, xmlpath, xmlbuffer, xmlbuflen); + else { + err = hwloc_libxml_callbacks->backend_init(data, xmlpath, xmlbuffer, xmlbuflen); + if (err < 0 && errno == ENOSYS) { + hwloc_libxml_callbacks = NULL; + goto retry; + } + } + if (err < 0) + goto out_with_data; + + return backend; + + out_with_data: + free(data->msgprefix); + free(data); + out_with_backend: + free(backend); + out: + return NULL; +} + +static struct hwloc_disc_component hwloc_xml_disc_component = { + HWLOC_DISC_COMPONENT_TYPE_GLOBAL, + "xml", + ~0, + hwloc_xml_component_instantiate, + 30, + NULL +}; + +const struct hwloc_component hwloc_xml_component = { + HWLOC_COMPONENT_ABI, + NULL, NULL, + HWLOC_COMPONENT_TYPE_DISC, + 0, + &hwloc_xml_disc_component +}; diff --git a/opal/mca/hwloc/hwloc1110/hwloc/src/topology.c b/opal/mca/hwloc/hwloc1110/hwloc/src/topology.c new file mode 100644 index 0000000000..8d129d0705 --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/src/topology.c @@ -0,0 +1,3236 @@ +/* + * Copyright © 2009 CNRS + * Copyright © 2009-2015 Inria. All rights reserved. + * Copyright © 2009-2012 Université Bordeaux + * Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved. + * See COPYING in top-level directory. + */ + +#include + +#define _ATFILE_SOURCE +#include +#include +#ifdef HAVE_DIRENT_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef HAVE_MACH_MACH_INIT_H +#include +#endif +#ifdef HAVE_MACH_MACH_HOST_H +#include +#endif + +#ifdef HAVE_SYS_PARAM_H +#include +#endif + +#ifdef HAVE_SYS_SYSCTL_H +#include +#endif + +#ifdef HWLOC_WIN_SYS +#include +#endif + +unsigned hwloc_get_api_version(void) +{ + return HWLOC_API_VERSION; +} + +int hwloc_hide_errors(void) +{ + static int hide = 0; + static int checked = 0; + if (!checked) { + const char *envvar = getenv("HWLOC_HIDE_ERRORS"); + if (envvar) + hide = atoi(envvar); + checked = 1; + } + return hide; +} + +void hwloc_report_os_error(const char *msg, int line) +{ + static int reported = 0; + + if (!reported && !hwloc_hide_errors()) { + fprintf(stderr, "****************************************************************************\n"); + fprintf(stderr, "* hwloc %s has encountered what looks like an error from the operating system.\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, "* 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, "* Otherwise please report this error message to the hwloc user's mailing list,\n"); +#ifdef HWLOC_LINUX_SYS + fprintf(stderr, "* along with the output+tarball generated by the hwloc-gather-topology script.\n"); +#else + fprintf(stderr, "* along with any relevant topology information from your platform.\n"); +#endif + fprintf(stderr, "****************************************************************************\n"); + reported = 1; + } +} + +#if defined(HAVE_SYSCTLBYNAME) +int hwloc_get_sysctlbyname(const char *name, int64_t *ret) +{ + union { + int32_t i32; + int64_t i64; + } n; + size_t size = sizeof(n); + if (sysctlbyname(name, &n, &size, NULL, 0)) + return -1; + switch (size) { + case sizeof(n.i32): + *ret = n.i32; + break; + case sizeof(n.i64): + *ret = n.i64; + break; + default: + return -1; + } + return 0; +} +#endif + +#if defined(HAVE_SYSCTL) +int hwloc_get_sysctl(int name[], unsigned namelen, int *ret) +{ + int n; + size_t size = sizeof(n); + if (sysctl(name, namelen, &n, &size, NULL, 0)) + return -1; + if (size != sizeof(n)) + return -1; + *ret = n; + return 0; +} +#endif + +/* Return the OS-provided number of processors. Unlike other methods such as + reading sysfs on Linux, this method is not virtualizable; thus it's only + used as a fall-back method, allowing `hwloc_set_fsroot ()' to + have the desired effect. */ +unsigned +hwloc_fallback_nbprocessors(struct hwloc_topology *topology) { + int n; +#if HAVE_DECL__SC_NPROCESSORS_ONLN + n = sysconf(_SC_NPROCESSORS_ONLN); +#elif HAVE_DECL__SC_NPROC_ONLN + n = sysconf(_SC_NPROC_ONLN); +#elif HAVE_DECL__SC_NPROCESSORS_CONF + n = sysconf(_SC_NPROCESSORS_CONF); +#elif HAVE_DECL__SC_NPROC_CONF + n = sysconf(_SC_NPROC_CONF); +#elif defined(HAVE_HOST_INFO) && HAVE_HOST_INFO + struct host_basic_info info; + mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT; + host_info(mach_host_self(), HOST_BASIC_INFO, (integer_t*) &info, &count); + n = info.avail_cpus; +#elif defined(HAVE_SYSCTLBYNAME) + int64_t nn; + if (hwloc_get_sysctlbyname("hw.ncpu", &nn)) + nn = -1; + n = nn; +#elif defined(HAVE_SYSCTL) && HAVE_DECL_CTL_HW && HAVE_DECL_HW_NCPU + static int name[2] = {CTL_HW, HW_NPCU}; + if (hwloc_get_sysctl(name, sizeof(name)/sizeof(*name)), &n) + n = -1; +#elif defined(HWLOC_WIN_SYS) + SYSTEM_INFO sysinfo; + GetSystemInfo(&sysinfo); + n = sysinfo.dwNumberOfProcessors; +#else +#ifdef __GNUC__ +#warning No known way to discover number of available processors on this system +#warning hwloc_fallback_nbprocessors will default to 1 +#endif + n = -1; +#endif + if (n >= 1) + topology->support.discovery->pu = 1; + else + n = 1; + return n; +} + +/* + * Use the given number of processors and the optional online cpuset if given + * to set a PU level. + */ +void +hwloc_setup_pu_level(struct hwloc_topology *topology, + unsigned nb_pus) +{ + struct hwloc_obj *obj; + unsigned oscpu,cpu; + + hwloc_debug("%s", "\n\n * CPU cpusets *\n\n"); + for (cpu=0,oscpu=0; cpucpuset = hwloc_bitmap_alloc(); + hwloc_bitmap_only(obj->cpuset, oscpu); + + hwloc_debug_2args_bitmap("cpu %u (os %u) has cpuset %s\n", + cpu, oscpu, obj->cpuset); + hwloc_insert_object_by_cpuset(topology, obj); + + cpu++; + } +} + +#ifdef HWLOC_DEBUG +/* Just for debugging. */ +static void +hwloc_debug_print_object(int indent __hwloc_attribute_unused, hwloc_obj_t obj) +{ + char type[64], idx[10], attr[1024], *cpuset = NULL; + hwloc_debug("%*s", 2*indent, ""); + hwloc_obj_type_snprintf(type, sizeof(type), obj, 1); + if (obj->os_index != (unsigned) -1) + snprintf(idx, sizeof(idx), "#%u", obj->os_index); + else + *idx = '\0'; + hwloc_obj_attr_snprintf(attr, sizeof(attr), obj, " ", 1); + hwloc_debug("%s%s%s%s%s", type, idx, *attr ? "(" : "", attr, *attr ? ")" : ""); + if (obj->name) + hwloc_debug(" name %s", obj->name); + if (obj->cpuset) { + hwloc_bitmap_asprintf(&cpuset, obj->cpuset); + hwloc_debug(" cpuset %s", cpuset); + free(cpuset); + } + if (obj->complete_cpuset) { + hwloc_bitmap_asprintf(&cpuset, obj->complete_cpuset); + hwloc_debug(" complete %s", cpuset); + free(cpuset); + } + if (obj->online_cpuset) { + hwloc_bitmap_asprintf(&cpuset, obj->online_cpuset); + hwloc_debug(" online %s", cpuset); + free(cpuset); + } + if (obj->allowed_cpuset) { + hwloc_bitmap_asprintf(&cpuset, obj->allowed_cpuset); + hwloc_debug(" allowed %s", cpuset); + free(cpuset); + } + if (obj->nodeset) { + hwloc_bitmap_asprintf(&cpuset, obj->nodeset); + hwloc_debug(" nodeset %s", cpuset); + free(cpuset); + } + if (obj->complete_nodeset) { + hwloc_bitmap_asprintf(&cpuset, obj->complete_nodeset); + hwloc_debug(" completeN %s", cpuset); + free(cpuset); + } + if (obj->allowed_nodeset) { + hwloc_bitmap_asprintf(&cpuset, obj->allowed_nodeset); + hwloc_debug(" allowedN %s", cpuset); + free(cpuset); + } + if (obj->arity) + hwloc_debug(" arity %u", obj->arity); + hwloc_debug("%s", "\n"); +} + +static void +hwloc_debug_print_objects(int indent __hwloc_attribute_unused, hwloc_obj_t obj) +{ + hwloc_debug_print_object(indent, obj); + for (obj = obj->first_child; obj; obj = obj->next_sibling) + hwloc_debug_print_objects(indent + 1, obj); +} +#else /* !HWLOC_DEBUG */ +#define hwloc_debug_print_object(indent, obj) do { /* nothing */ } while (0) +#define hwloc_debug_print_objects(indent, obj) do { /* nothing */ } while (0) +#endif /* !HWLOC_DEBUG */ + +void hwloc__free_infos(struct hwloc_obj_info_s *infos, unsigned count) +{ + unsigned i; + for(i=0; iinfos, &obj->infos_count, name, value); +} + +void hwloc_obj_add_info_nodup(hwloc_obj_t obj, const char *name, const char *value, int nodup) +{ + if (nodup && hwloc_obj_get_info_by_name(obj, name)) + return; + hwloc__add_info(&obj->infos, &obj->infos_count, name, value); +} + +/* Traverse children of a parent in a safe way: reread the next pointer as + * appropriate to prevent crash on child deletion: */ +#define for_each_child_safe(child, parent, pchild) \ + for (pchild = &(parent)->first_child, child = *pchild; \ + child; \ + /* Check whether the current child was not dropped. */ \ + (*pchild == child ? pchild = &(child->next_sibling) : NULL), \ + /* Get pointer to next childect. */ \ + child = *pchild) + +/* Free an object and all its content. */ +void +hwloc_free_unlinked_object(hwloc_obj_t obj) +{ + switch (obj->type) { + default: + break; + } + hwloc__free_infos(obj->infos, obj->infos_count); + hwloc_clear_object_distances(obj); + free(obj->memory.page_types); + free(obj->attr); + free(obj->children); + free(obj->name); + hwloc_bitmap_free(obj->cpuset); + hwloc_bitmap_free(obj->complete_cpuset); + hwloc_bitmap_free(obj->online_cpuset); + hwloc_bitmap_free(obj->allowed_cpuset); + hwloc_bitmap_free(obj->nodeset); + hwloc_bitmap_free(obj->complete_nodeset); + hwloc_bitmap_free(obj->allowed_nodeset); + free(obj); +} + +/* insert the (non-empty) list of sibling starting at firstnew as new children of newparent, + * and return the address of the pointer to the next one + */ +static hwloc_obj_t * +insert_siblings_list(hwloc_obj_t *firstp, hwloc_obj_t firstnew, hwloc_obj_t newparent) +{ + hwloc_obj_t tmp; + assert(firstnew); + *firstp = tmp = firstnew; + tmp->parent = newparent; + while (tmp->next_sibling) { + tmp = tmp->next_sibling; + } + return &tmp->next_sibling; +} + +/* Remove an object from its parent and free it. + * Only updates next_sibling/first_child pointers, + * so may only be used during early discovery. + * Children are inserted where the object was. + */ +static void +unlink_and_free_single_object(hwloc_obj_t *pparent) +{ + hwloc_obj_t old = *pparent; + hwloc_obj_t *lastp; + + if (old->first_child) + /* insert old object children as new siblings below parent instead of old */ + lastp = insert_siblings_list(pparent, old->first_child, old->parent); + else + lastp = pparent; + /* append old siblings back */ + *lastp = old->next_sibling; + + hwloc_free_unlinked_object(old); +} + +/* Remove an object and its children from its parent and free them. + * Only updates next_sibling/first_child pointers, + * so may only be used during early discovery. + */ +static void +unlink_and_free_object_and_children(hwloc_obj_t *pobj) +{ + hwloc_obj_t obj = *pobj, child, *pchild; + + for_each_child_safe(child, obj, pchild) + unlink_and_free_object_and_children(pchild); + + *pobj = obj->next_sibling; + hwloc_free_unlinked_object(obj); +} + +static void +hwloc__duplicate_object(struct hwloc_obj *newobj, + struct hwloc_obj *src) +{ + size_t len; + unsigned i; + + newobj->type = src->type; + newobj->os_index = src->os_index; + + if (src->name) + newobj->name = strdup(src->name); + newobj->userdata = src->userdata; + + memcpy(&newobj->memory, &src->memory, sizeof(struct hwloc_obj_memory_s)); + if (src->memory.page_types_len) { + len = src->memory.page_types_len * sizeof(struct hwloc_obj_memory_page_type_s); + newobj->memory.page_types = malloc(len); + memcpy(newobj->memory.page_types, src->memory.page_types, len); + } + + memcpy(newobj->attr, src->attr, sizeof(*newobj->attr)); + + newobj->cpuset = hwloc_bitmap_dup(src->cpuset); + newobj->complete_cpuset = hwloc_bitmap_dup(src->complete_cpuset); + newobj->allowed_cpuset = hwloc_bitmap_dup(src->allowed_cpuset); + newobj->online_cpuset = hwloc_bitmap_dup(src->online_cpuset); + newobj->nodeset = hwloc_bitmap_dup(src->nodeset); + newobj->complete_nodeset = hwloc_bitmap_dup(src->complete_nodeset); + newobj->allowed_nodeset = hwloc_bitmap_dup(src->allowed_nodeset); + + /* don't duplicate distances, they'll be recreated at the end of the topology build */ + + for(i=0; iinfos_count; i++) + hwloc__add_info(&newobj->infos, &newobj->infos_count, src->infos[i].name, src->infos[i].value); +} + +void +hwloc__duplicate_objects(struct hwloc_topology *newtopology, + struct hwloc_obj *newparent, + struct hwloc_obj *src) +{ + hwloc_obj_t newobj; + hwloc_obj_t child; + + newobj = hwloc_alloc_setup_object(src->type, src->os_index); + hwloc__duplicate_object(newobj, src); + + child = NULL; + while ((child = hwloc_get_next_child(newtopology, src, child)) != NULL) + hwloc__duplicate_objects(newtopology, newobj, child); + + /* no need to check the children order here, the source topology + * is supposed to be OK already, and we have debug asserts. + */ + hwloc_insert_object_by_parent(newtopology, newparent, newobj); +} + +int +hwloc_topology_dup(hwloc_topology_t *newp, + hwloc_topology_t old) +{ + hwloc_topology_t new; + hwloc_obj_t newroot; + hwloc_obj_t oldroot = hwloc_get_root_obj(old); + unsigned i; + + if (!old->is_loaded) { + errno = -EINVAL; + return -1; + } + + hwloc_topology_init(&new); + + new->flags = old->flags; + memcpy(new->ignored_types, old->ignored_types, sizeof(old->ignored_types)); + new->is_thissystem = old->is_thissystem; + new->is_loaded = 1; + new->pid = old->pid; + + memcpy(&new->binding_hooks, &old->binding_hooks, sizeof(old->binding_hooks)); + + 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.membind, old->support.membind, sizeof(*old->support.membind)); + + new->userdata_export_cb = old->userdata_export_cb; + new->userdata_import_cb = old->userdata_import_cb; + + newroot = hwloc_get_root_obj(new); + hwloc__duplicate_object(newroot, oldroot); + for(i=0; iarity; i++) + hwloc__duplicate_objects(new, newroot, oldroot->children[i]); + + if (old->first_osdist) { + struct hwloc_os_distances_s *olddist = old->first_osdist; + while (olddist) { + struct hwloc_os_distances_s *newdist = malloc(sizeof(*newdist)); + newdist->type = olddist->type; + newdist->nbobjs = olddist->nbobjs; + newdist->indexes = malloc(newdist->nbobjs * sizeof(*newdist->indexes)); + memcpy(newdist->indexes, olddist->indexes, newdist->nbobjs * sizeof(*newdist->indexes)); + newdist->objs = NULL; /* will be recomputed when needed */ + newdist->distances = malloc(newdist->nbobjs * newdist->nbobjs * sizeof(*newdist->distances)); + memcpy(newdist->distances, olddist->distances, newdist->nbobjs * newdist->nbobjs * sizeof(*newdist->distances)); + + newdist->forced = olddist->forced; + if (new->first_osdist) { + new->last_osdist->next = newdist; + newdist->prev = new->last_osdist; + } else { + new->first_osdist = newdist; + newdist->prev = NULL; + } + new->last_osdist = newdist; + newdist->next = NULL; + + olddist = olddist->next; + } + } else + new->first_osdist = old->last_osdist = NULL; + + /* no need to duplicate backends, topology is already loaded */ + new->backends = NULL; + + hwloc_connect_children(new->levels[0][0]); + if (hwloc_connect_levels(new) < 0) + goto out; + + hwloc_distances_finalize_os(new); + hwloc_distances_finalize_logical(new); + +#ifndef HWLOC_DEBUG + if (getenv("HWLOC_DEBUG_CHECK")) +#endif + hwloc_topology_check(new); + + *newp = new; + return 0; + + out: + hwloc_topology_clear(new); + hwloc_distances_destroy(new); + hwloc_topology_setup_defaults(new); + return -1; +} + +/* + * How to compare objects based on types. + * + * Note that HIGHER/LOWER is only a (consistent) heuristic, used to sort + * objects with same cpuset consistently. + * Only EQUAL / not EQUAL can be relied upon. + */ + +enum hwloc_type_cmp_e { + HWLOC_TYPE_HIGHER, + HWLOC_TYPE_DEEPER, + HWLOC_TYPE_EQUAL +}; + +/* WARNING: The indexes of this array MUST match the ordering that of + the obj_order_type[] array, below. Specifically, the values must + be laid out such that: + + obj_order_type[obj_type_order[N]] = N + + for all HWLOC_OBJ_* values of N. Put differently: + + obj_type_order[A] = B + + where the A values are in order of the hwloc_obj_type_t enum, and + the B values are the corresponding indexes of obj_order_type. + + We can't use C99 syntax to initialize this in a little safer manner + -- bummer. :-( + + ************************************************************* + *** DO NOT CHANGE THE ORDERING OF THIS ARRAY WITHOUT TRIPLE + *** CHECKING ITS CORRECTNESS! + ************************************************************* + */ +static const unsigned obj_type_order[] = { + /* first entry is HWLOC_OBJ_SYSTEM */ 0, + /* next entry is HWLOC_OBJ_MACHINE */ 1, + /* next entry is HWLOC_OBJ_NUMANODE */ 3, + /* next entry is HWLOC_OBJ_PACKAGE */ 4, + /* next entry is HWLOC_OBJ_CACHE */ 5, + /* next entry is HWLOC_OBJ_CORE */ 6, + /* next entry is HWLOC_OBJ_PU */ 10, + /* next entry is HWLOC_OBJ_GROUP */ 2, + /* next entry is HWLOC_OBJ_MISC */ 11, + /* next entry is HWLOC_OBJ_BRIDGE */ 7, + /* next entry is HWLOC_OBJ_PCI_DEVICE */ 8, + /* next entry is HWLOC_OBJ_OS_DEVICE */ 9 +}; + +static const hwloc_obj_type_t obj_order_type[] = { + HWLOC_OBJ_SYSTEM, + HWLOC_OBJ_MACHINE, + HWLOC_OBJ_GROUP, + HWLOC_OBJ_NUMANODE, + HWLOC_OBJ_PACKAGE, + HWLOC_OBJ_CACHE, + HWLOC_OBJ_CORE, + HWLOC_OBJ_BRIDGE, + HWLOC_OBJ_PCI_DEVICE, + HWLOC_OBJ_OS_DEVICE, + HWLOC_OBJ_PU, + HWLOC_OBJ_MISC, +}; + +/* priority to be used when merging identical parent/children object + * (in merge_useless_child), keep the highest priority one. + * + * Always keep Machine/PU/PCIDev/OSDev + * then System/Node + * then Core + * then Package + * then Cache + * then always drop Group/Misc/Bridge. + * + * Some type won't actually ever be involved in such merging. + */ +static const int obj_type_priority[] = { + /* first entry is HWLOC_OBJ_SYSTEM */ 80, + /* next entry is HWLOC_OBJ_MACHINE */ 100, + /* next entry is HWLOC_OBJ_NUMANODE */ 80, + /* next entry is HWLOC_OBJ_PACKAGE */ 40, + /* next entry is HWLOC_OBJ_CACHE */ 20, + /* next entry is HWLOC_OBJ_CORE */ 60, + /* next entry is HWLOC_OBJ_PU */ 100, + /* next entry is HWLOC_OBJ_GROUP */ 0, + /* next entry is HWLOC_OBJ_MISC */ 0, + /* next entry is HWLOC_OBJ_BRIDGE */ 0, + /* next entry is HWLOC_OBJ_PCI_DEVICE */ 100, + /* next entry is HWLOC_OBJ_OS_DEVICE */ 100 +}; + +static unsigned __hwloc_attribute_const +hwloc_get_type_order(hwloc_obj_type_t type) +{ + return obj_type_order[type]; +} + +#if !defined(NDEBUG) +static hwloc_obj_type_t hwloc_get_order_type(int order) +{ + return obj_order_type[order]; +} +#endif + +static int hwloc_obj_type_is_io (hwloc_obj_type_t type) +{ + return type == HWLOC_OBJ_BRIDGE || type == HWLOC_OBJ_PCI_DEVICE || type == HWLOC_OBJ_OS_DEVICE; +} + +int hwloc_compare_types (hwloc_obj_type_t type1, hwloc_obj_type_t type2) +{ + unsigned order1 = hwloc_get_type_order(type1); + unsigned order2 = hwloc_get_type_order(type2); + + /* bridge and devices are only comparable with each others and with machine and system */ + if (hwloc_obj_type_is_io(type1) + && !hwloc_obj_type_is_io(type2) && type2 != HWLOC_OBJ_SYSTEM && type2 != HWLOC_OBJ_MACHINE) + return HWLOC_TYPE_UNORDERED; + if (hwloc_obj_type_is_io(type2) + && !hwloc_obj_type_is_io(type1) && type1 != HWLOC_OBJ_SYSTEM && type1 != HWLOC_OBJ_MACHINE) + return HWLOC_TYPE_UNORDERED; + + return order1 - order2; +} + +static enum hwloc_type_cmp_e +hwloc_type_cmp(hwloc_obj_t obj1, hwloc_obj_t obj2) +{ + hwloc_obj_type_t type1 = obj1->type; + hwloc_obj_type_t type2 = obj2->type; + int compare; + + compare = hwloc_compare_types(type1, type2); + if (compare == HWLOC_TYPE_UNORDERED) + return HWLOC_TYPE_EQUAL; /* we cannot do better */ + if (compare > 0) + return HWLOC_TYPE_DEEPER; + if (compare < 0) + return HWLOC_TYPE_HIGHER; + + /* Caches have the same types but can have different depths. */ + if (type1 == HWLOC_OBJ_CACHE) { + if (obj1->attr->cache.depth < obj2->attr->cache.depth) + return HWLOC_TYPE_DEEPER; + else if (obj1->attr->cache.depth > obj2->attr->cache.depth) + return HWLOC_TYPE_HIGHER; + else if (obj1->attr->cache.type > obj2->attr->cache.type) + /* consider icache deeper than dcache and dcache deeper than unified */ + return HWLOC_TYPE_DEEPER; + else if (obj1->attr->cache.type < obj2->attr->cache.type) + /* consider icache deeper than dcache and dcache deeper than unified */ + return HWLOC_TYPE_HIGHER; + } + + /* Group objects have the same types but can have different depths. */ + if (type1 == HWLOC_OBJ_GROUP) { + if (obj1->attr->group.depth == (unsigned) -1 + || obj2->attr->group.depth == (unsigned) -1) + return HWLOC_TYPE_EQUAL; + if (obj1->attr->group.depth < obj2->attr->group.depth) + return HWLOC_TYPE_DEEPER; + else if (obj1->attr->group.depth > obj2->attr->group.depth) + return HWLOC_TYPE_HIGHER; + } + + /* Bridges objects have the same types but can have different depths. */ + if (type1 == HWLOC_OBJ_BRIDGE) { + if (obj1->attr->bridge.depth < obj2->attr->bridge.depth) + return HWLOC_TYPE_DEEPER; + else if (obj1->attr->bridge.depth > obj2->attr->bridge.depth) + return HWLOC_TYPE_HIGHER; + } + + return HWLOC_TYPE_EQUAL; +} + +/* + * How to compare objects based on cpusets. + */ + +enum hwloc_obj_cmp_e { + HWLOC_OBJ_EQUAL = HWLOC_BITMAP_EQUAL, /**< \brief Equal */ + HWLOC_OBJ_INCLUDED = HWLOC_BITMAP_INCLUDED, /**< \brief Strictly included into */ + HWLOC_OBJ_CONTAINS = HWLOC_BITMAP_CONTAINS, /**< \brief Strictly contains */ + HWLOC_OBJ_INTERSECTS = HWLOC_BITMAP_INTERSECTS, /**< \brief Intersects, but no inclusion! */ + HWLOC_OBJ_DIFFERENT = HWLOC_BITMAP_DIFFERENT /**< \brief No intersection */ +}; + +static int +hwloc_obj_cmp_sets(hwloc_obj_t obj1, hwloc_obj_t obj2) +{ + hwloc_bitmap_t set1, set2; + + /* compare cpusets if possible, or fallback to nodeset, or return */ + if (obj1->cpuset && !hwloc_bitmap_iszero(obj1->cpuset) + && obj2->cpuset && !hwloc_bitmap_iszero(obj2->cpuset)) { + set1 = obj1->cpuset; + set2 = obj2->cpuset; + } else if (obj1->nodeset && !hwloc_bitmap_iszero(obj1->nodeset) + && obj2->nodeset && !hwloc_bitmap_iszero(obj2->nodeset)) { + set1 = obj1->nodeset; + set2 = obj2->nodeset; + } else { + return HWLOC_OBJ_DIFFERENT; + } + + return hwloc_bitmap_compare_inclusion(set1, set2); +} + +static int +hwloc_obj_cmp_types(hwloc_obj_t obj1, hwloc_obj_t obj2) +{ + /* Same sets, subsort by type to have a consistent ordering. */ + int typeres = hwloc_type_cmp(obj1, obj2); + if (typeres == HWLOC_TYPE_DEEPER) + return HWLOC_OBJ_INCLUDED; + if (typeres == HWLOC_TYPE_HIGHER) + return HWLOC_OBJ_CONTAINS; + + /* HWLOC_TYPE_EQUAL */ + + if (obj1->type == HWLOC_OBJ_MISC) { + /* Misc objects may vary by name */ + int res = strcmp(obj1->name, obj2->name); + if (res < 0) + return HWLOC_OBJ_INCLUDED; + if (res > 0) + return HWLOC_OBJ_CONTAINS; + if (res == 0) + return HWLOC_OBJ_EQUAL; + } + /* Same sets and types! Let's hope it's coherent. */ + return HWLOC_OBJ_EQUAL; +} + +/* Compare object cpusets based on complete_cpuset if defined (always correctly ordered), + * or fallback to the main cpusets (only correctly ordered during early insert before disallowed/offline bits are cleared). + * + * This is the sane way to compare object among a horizontal level. + */ +int +hwloc__object_cpusets_compare_first(hwloc_obj_t obj1, hwloc_obj_t obj2) +{ + if (obj1->complete_cpuset && obj2->complete_cpuset) + return hwloc_bitmap_compare_first(obj1->complete_cpuset, obj2->complete_cpuset); + else + return hwloc_bitmap_compare_first(obj1->cpuset, obj2->cpuset); +} + +/* 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; + hwloc_obj_type_snprintf(typestr, sizeof(typestr), obj, 0); + hwloc_bitmap_asprintf(&cpusetstr, obj->cpuset); + if (obj->os_index != (unsigned) -1) + snprintf(buf, buflen, "%s (P#%u cpuset %s)", + typestr, obj->os_index, cpusetstr); + else + snprintf(buf, buflen, "%s (cpuset %s)", + typestr, cpusetstr); + free(cpusetstr); +} + +/* + * How to insert objects into the topology. + * + * Note: during detection, only the first_child and next_sibling pointers are + * kept up to date. Others are computed only once topology detection is + * complete. + */ + +#define merge_index(new, old, field, type) \ + if ((old)->field == (type) -1) \ + (old)->field = (new)->field; +#define merge_sizes(new, old, field) \ + if (!(old)->field) \ + (old)->field = (new)->field; +#ifdef HWLOC_DEBUG +#define check_sizes(new, old, field) \ + if ((new)->field) \ + assert((old)->field == (new)->field) +#else +#define check_sizes(new, old, field) +#endif + +static void +merge_insert_equal(hwloc_obj_t new, hwloc_obj_t old) +{ + merge_index(new, old, os_index, unsigned); + + if (new->distances_count) { + if (old->distances_count) { + old->distances_count += new->distances_count; + old->distances = realloc(old->distances, old->distances_count * sizeof(*old->distances)); + memcpy(old->distances + new->distances_count, new->distances, new->distances_count * sizeof(*old->distances)); + free(new->distances); + } else { + old->distances_count = new->distances_count; + old->distances = new->distances; + } + new->distances_count = 0; + new->distances = NULL; + } + + if (new->infos_count) { + hwloc__move_infos(&old->infos, &old->infos_count, + &new->infos, &new->infos_count); + } + + if (new->name) { + if (old->name) + free(old->name); + old->name = new->name; + new->name = NULL; + } + + assert(!new->userdata); /* user could not set userdata here (we're before load() */ + + switch(new->type) { + case HWLOC_OBJ_NUMANODE: + /* Do not check these, it may change between calls */ + merge_sizes(new, old, memory.local_memory); + merge_sizes(new, old, memory.total_memory); + /* if both newects have a page_types array, just keep the biggest one for now */ + if (new->memory.page_types_len && old->memory.page_types_len) + hwloc_debug("%s", "merging page_types by keeping the biggest one only\n"); + if (new->memory.page_types_len < old->memory.page_types_len) { + free(new->memory.page_types); + } else { + free(old->memory.page_types); + old->memory.page_types_len = new->memory.page_types_len; + old->memory.page_types = new->memory.page_types; + new->memory.page_types = NULL; + new->memory.page_types_len = 0; + } + break; + case HWLOC_OBJ_CACHE: + merge_sizes(new, old, attr->cache.size); + check_sizes(new, old, attr->cache.size); + merge_sizes(new, old, attr->cache.linesize); + check_sizes(new, old, attr->cache.linesize); + break; + default: + break; + } +} + +/* Try to insert OBJ in CUR, recurse if needed. + * Returns the object if it was inserted, + * the remaining object it was merged, + * NULL if failed to insert. + */ +static struct hwloc_obj * +hwloc___insert_object_by_cpuset(struct hwloc_topology *topology, hwloc_obj_t cur, hwloc_obj_t obj, + hwloc_report_error_t report_error) +{ + hwloc_obj_t child, next_child = NULL; + /* These will always point to the pointer to their next last child. */ + hwloc_obj_t *cur_children = &cur->first_child; + hwloc_obj_t *obj_children = &obj->first_child; + /* Pointer where OBJ should be put */ + hwloc_obj_t *putp = NULL; /* OBJ position isn't found yet */ + + /* Make sure we haven't gone too deep. */ + if (!hwloc_bitmap_isincluded(obj->cpuset, cur->cpuset)) { + fprintf(stderr,"recursion has gone too deep?!\n"); + return NULL; + } + + /* Iteration with prefetching to be completely safe against CHILD removal. + * The list is already sorted by cpuset, and there's no intersection between siblings. + */ + for (child = cur->first_child, child ? next_child = child->next_sibling : NULL; + child; + child = next_child, child ? next_child = child->next_sibling : NULL) { + + int res = hwloc_obj_cmp_sets(obj, child); + + if (res == HWLOC_OBJ_EQUAL) { + if (obj->type == HWLOC_OBJ_GROUP) { + /* Group are ignored keep_structure. ignored always are handled earlier. Non-ignored Groups isn't possible. */ + assert(topology->ignored_types[HWLOC_OBJ_GROUP] == HWLOC_IGNORE_TYPE_KEEP_STRUCTURE); + /* Remove the Group now. The normal ignore code path wouldn't tell us whether the Group was removed or not. + * + * Keep EQUAL so that the Group gets merged. + */ + } else { + /* otherwise compare actual types to decide of the inclusion */ + res = hwloc_obj_cmp_types(obj, child); + } + } + + switch (res) { + case HWLOC_OBJ_EQUAL: + merge_index(obj, child, os_level, signed); + if (obj->os_level != child->os_level) { + static int reported = 0; + if (!reported && !hwloc_hide_errors()) { + fprintf(stderr, "Cannot merge similar %s objects with different OS levels %u and %u\n", + hwloc_obj_type_string(obj->type), child->os_level, obj->os_level); + reported = 1; + } + return NULL; + } + /* Can be two objects with same type. Or one Group and anything else. */ + if (obj->type == child->type + && (obj->type == HWLOC_OBJ_PU || obj->type == HWLOC_OBJ_NUMANODE) + && obj->os_index != child->os_index) { + static int reported = 0; + if (!reported && !hwloc_hide_errors()) { + fprintf(stderr, "Cannot merge similar %s objects with different OS indexes %u and %u\n", + hwloc_obj_type_string(obj->type), child->os_index, obj->os_index); + reported = 1; + } + return NULL; + } + merge_insert_equal(obj, child); + /* Already present, no need to insert. */ + return child; + + case HWLOC_OBJ_INCLUDED: + /* OBJ is strictly contained is some child of CUR, go deeper. */ + return hwloc___insert_object_by_cpuset(topology, child, obj, report_error); + + case HWLOC_OBJ_INTERSECTS: + if (report_error) { + char childstr[512]; + char objstr[512]; + char msg[1024]; + 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; + + case HWLOC_OBJ_DIFFERENT: + /* OBJ should be a child of CUR before CHILD, mark its position if not found yet. */ + if (!putp && (!child->cpuset || hwloc__object_cpusets_compare_first(obj, child) < 0)) + /* Don't insert yet, there could be intersect errors later */ + putp = cur_children; + /* Advance cur_children. */ + cur_children = &child->next_sibling; + break; + + case HWLOC_OBJ_CONTAINS: + /* OBJ contains CHILD, remove CHILD from CUR */ + *cur_children = child->next_sibling; + child->next_sibling = NULL; + /* Put CHILD in OBJ */ + *obj_children = child; + obj_children = &child->next_sibling; + break; + } + } + /* cur/obj_children points to last CUR/OBJ child next_sibling pointer, which must be NULL. */ + assert(!*obj_children); + assert(!*cur_children); + + /* Put OBJ where it belongs, or in last in CUR's children. */ + if (!putp) + putp = cur_children; + obj->next_sibling = *putp; + *putp = obj; + + return obj; + + putback: + /* Put-back OBJ children in CUR and return an error. */ + if (putp) + cur_children = putp; /* No need to try to insert before where OBJ was supposed to go */ + else + cur_children = &cur->first_child; /* Start from the beginning */ + /* We can insert in order, but there can be holes in the middle. */ + while ((child = obj->first_child) != NULL) { + /* Remove from OBJ */ + obj->first_child = child->next_sibling; + /* Find child position in CUR, and insert. */ + while (*cur_children && (*cur_children)->cpuset && hwloc__object_cpusets_compare_first(*cur_children, child) < 0) + cur_children = &(*cur_children)->next_sibling; + child->next_sibling = *cur_children; + *cur_children = child; + } + return NULL; +} + +/* insertion routine that lets you change the error reporting callback */ +struct hwloc_obj * +hwloc__insert_object_by_cpuset(struct hwloc_topology *topology, hwloc_obj_t obj, + hwloc_report_error_t report_error) +{ + struct hwloc_obj *result; + /* Start at the top. */ + result = hwloc___insert_object_by_cpuset(topology, topology->levels[0][0], obj, report_error); + if (result != obj) { + /* either failed to insert, or got merged, free the original object */ + hwloc_free_unlinked_object(obj); + } else { + /* Add the cpuset to the top */ + hwloc_bitmap_or(topology->levels[0][0]->complete_cpuset, topology->levels[0][0]->complete_cpuset, obj->cpuset); + if (obj->nodeset) + hwloc_bitmap_or(topology->levels[0][0]->complete_nodeset, topology->levels[0][0]->complete_nodeset, obj->nodeset); + } + return result; +} + +/* the default insertion routine warns in case of error. + * 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, obj, hwloc_report_os_error); +} + +void +hwloc_insert_object_by_parent(struct hwloc_topology *topology, hwloc_obj_t parent, hwloc_obj_t obj) +{ + hwloc_obj_t child, next_child = obj->first_child; + hwloc_obj_t *current; + + /* Append to the end of the list. + * The caller takes care of inserting children in the right cpuset order. + * XML checks the order. + * Duplicating doesn't need to check the order since the source topology is supposed to be OK already. + * Other callers just insert random objects such as I/O or Misc. + */ + for (current = &parent->first_child; *current; current = &(*current)->next_sibling); + *current = obj; + obj->next_sibling = NULL; + obj->first_child = NULL; + + /* Use the new object to insert children */ + parent = obj; + + /* Recursively insert children below */ + while (next_child) { + child = next_child; + next_child = child->next_sibling; + hwloc_insert_object_by_parent(topology, parent, child); + } + + if (obj->type == HWLOC_OBJ_MISC) { + /* misc objects go in no level (needed here because level building doesn't see Misc objects inside I/O trees) */ + obj->depth = (unsigned) HWLOC_TYPE_DEPTH_UNKNOWN; + } +} + +/* Adds a misc object _after_ detection, and thus has to reconnect all the pointers */ +hwloc_obj_t +hwloc_topology_insert_misc_object_by_cpuset(struct hwloc_topology *topology, hwloc_const_bitmap_t cpuset, const char *name) +{ + hwloc_obj_t obj, child; + + if (!topology->is_loaded) { + errno = EINVAL; + return NULL; + } + + if (hwloc_bitmap_iszero(cpuset)) + return NULL; + if (!hwloc_bitmap_isincluded(cpuset, hwloc_topology_get_topology_cpuset(topology))) + return NULL; + + obj = hwloc_alloc_setup_object(HWLOC_OBJ_MISC, -1); + if (name) + obj->name = strdup(name); + + /* misc objects go in no level */ + obj->depth = (unsigned) HWLOC_TYPE_DEPTH_UNKNOWN; + + obj->cpuset = hwloc_bitmap_dup(cpuset); + /* initialize default cpusets, we'll adjust them later */ + obj->complete_cpuset = hwloc_bitmap_dup(cpuset); + obj->allowed_cpuset = hwloc_bitmap_dup(cpuset); + obj->online_cpuset = hwloc_bitmap_dup(cpuset); + + obj = hwloc__insert_object_by_cpuset(topology, obj, NULL /* do not show errors on stdout */); + if (!obj) + return NULL; + + hwloc_connect_children(topology->levels[0][0]); + + if ((child = obj->first_child) != NULL && child->cpuset) { + /* keep the main cpuset untouched, but update other cpusets and nodesets from children */ + obj->nodeset = hwloc_bitmap_alloc(); + obj->complete_nodeset = hwloc_bitmap_alloc(); + obj->allowed_nodeset = hwloc_bitmap_alloc(); + while (child) { + if (child->complete_cpuset) + hwloc_bitmap_or(obj->complete_cpuset, obj->complete_cpuset, child->complete_cpuset); + if (child->allowed_cpuset) + hwloc_bitmap_or(obj->allowed_cpuset, obj->allowed_cpuset, child->allowed_cpuset); + if (child->online_cpuset) + hwloc_bitmap_or(obj->online_cpuset, obj->online_cpuset, child->online_cpuset); + if (child->nodeset) + hwloc_bitmap_or(obj->nodeset, obj->nodeset, child->nodeset); + if (child->complete_nodeset) + hwloc_bitmap_or(obj->complete_nodeset, obj->complete_nodeset, child->complete_nodeset); + if (child->allowed_nodeset) + hwloc_bitmap_or(obj->allowed_nodeset, obj->allowed_nodeset, child->allowed_nodeset); + child = child->next_sibling; + } + } else { + /* copy the parent nodesets */ + obj->nodeset = hwloc_bitmap_dup(obj->parent->nodeset); + obj->complete_nodeset = hwloc_bitmap_dup(obj->parent->complete_nodeset); + obj->allowed_nodeset = hwloc_bitmap_dup(obj->parent->allowed_nodeset); + } + + return obj; +} + +hwloc_obj_t +hwloc_topology_insert_misc_object_by_parent(struct hwloc_topology *topology, hwloc_obj_t parent, const char *name) +{ + hwloc_obj_t obj = hwloc_alloc_setup_object(HWLOC_OBJ_MISC, -1); + if (name) + obj->name = strdup(name); + + if (!topology->is_loaded) { + hwloc_free_unlinked_object(obj); + errno = EINVAL; + return NULL; + } + + hwloc_insert_object_by_parent(topology, parent, obj); + + hwloc_connect_children(topology->levels[0][0]); + /* no need to hwloc_connect_levels() since misc object are not in levels */ + + return obj; +} + +/* Append I/O devices below this object to their list */ +static void +append_iodevs(hwloc_topology_t topology, hwloc_obj_t obj) +{ + hwloc_obj_t child, *temp; + + /* make sure we don't have remaining stale pointers from a previous load */ + obj->next_cousin = NULL; + obj->prev_cousin = NULL; + + if (obj->type == HWLOC_OBJ_BRIDGE) { + obj->depth = HWLOC_TYPE_DEPTH_BRIDGE; + /* Insert in the main bridge list */ + if (topology->first_bridge) { + obj->prev_cousin = topology->last_bridge; + obj->prev_cousin->next_cousin = obj; + topology->last_bridge = obj; + } else { + topology->first_bridge = topology->last_bridge = obj; + } + } else if (obj->type == HWLOC_OBJ_PCI_DEVICE) { + obj->depth = HWLOC_TYPE_DEPTH_PCI_DEVICE; + /* Insert in the main pcidev list */ + if (topology->first_pcidev) { + obj->prev_cousin = topology->last_pcidev; + obj->prev_cousin->next_cousin = obj; + topology->last_pcidev = obj; + } else { + topology->first_pcidev = topology->last_pcidev = obj; + } + } else if (obj->type == HWLOC_OBJ_OS_DEVICE) { + obj->depth = HWLOC_TYPE_DEPTH_OS_DEVICE; + /* Insert in the main osdev list */ + if (topology->first_osdev) { + obj->prev_cousin = topology->last_osdev; + obj->prev_cousin->next_cousin = obj; + topology->last_osdev = obj; + } else { + topology->first_osdev = topology->last_osdev = obj; + } + } + + for_each_child_safe(child, obj, temp) + append_iodevs(topology, child); +} + +static int hwloc_memory_page_type_compare(const void *_a, const void *_b) +{ + const struct hwloc_obj_memory_page_type_s *a = _a; + const struct hwloc_obj_memory_page_type_s *b = _b; + /* consider 0 as larger so that 0-size page_type go to the end */ + if (!b->size) + return -1; + /* don't cast a-b in int since those are ullongs */ + if (b->size == a->size) + return 0; + return a->size < b->size ? -1 : 1; +} + +/* Propagate memory counts */ +static void +propagate_total_memory(hwloc_obj_t obj) +{ + hwloc_obj_t *temp, child; + unsigned i; + + /* reset total before counting local and children memory */ + obj->memory.total_memory = 0; + + /* Propagate memory up */ + for_each_child_safe(child, obj, temp) { + propagate_total_memory(child); + obj->memory.total_memory += child->memory.total_memory; + } + obj->memory.total_memory += obj->memory.local_memory; + + /* By the way, sort the page_type array. + * Cannot do it on insert since some backends (e.g. XML) add page_types after inserting the object. + */ + qsort(obj->memory.page_types, obj->memory.page_types_len, sizeof(*obj->memory.page_types), hwloc_memory_page_type_compare); + /* Ignore 0-size page_types, they are at the end */ + for(i=obj->memory.page_types_len; i>=1; i--) + if (obj->memory.page_types[i-1].size) + break; + obj->memory.page_types_len = i; +} + +/* Collect the cpuset of all the PU objects. */ +static void +collect_proc_cpuset(hwloc_obj_t obj, hwloc_obj_t sys) +{ + hwloc_obj_t child, *temp; + + if (sys) { + /* We are already given a pointer to a system object */ + if (obj->type == HWLOC_OBJ_PU) + hwloc_bitmap_or(sys->cpuset, sys->cpuset, obj->cpuset); + } else { + if (obj->cpuset) { + /* This object is the root of a machine */ + sys = obj; + /* Assume no PU for now */ + hwloc_bitmap_zero(obj->cpuset); + } + } + + for_each_child_safe(child, obj, temp) + collect_proc_cpuset(child, sys); +} + +/* While traversing down and up, propagate the offline/disallowed cpus by + * and'ing them to and from the first object that has a cpuset */ +static void +propagate_unused_cpuset(hwloc_obj_t obj, hwloc_obj_t sys) +{ + hwloc_obj_t child, *temp; + + if (obj->cpuset) { + if (sys) { + /* We are already given a pointer to an system object, update it and update ourselves */ + hwloc_bitmap_t mask = hwloc_bitmap_alloc(); + + /* Apply the topology cpuset */ + hwloc_bitmap_and(obj->cpuset, obj->cpuset, sys->cpuset); + + /* Update complete cpuset down */ + if (obj->complete_cpuset) { + hwloc_bitmap_and(obj->complete_cpuset, obj->complete_cpuset, sys->complete_cpuset); + } else { + obj->complete_cpuset = hwloc_bitmap_dup(sys->complete_cpuset); + hwloc_bitmap_and(obj->complete_cpuset, obj->complete_cpuset, obj->cpuset); + } + + /* Update online cpusets */ + if (obj->online_cpuset) { + /* Update ours */ + hwloc_bitmap_and(obj->online_cpuset, obj->online_cpuset, sys->online_cpuset); + + /* Update the given cpuset, but only what we know */ + hwloc_bitmap_copy(mask, obj->cpuset); + hwloc_bitmap_not(mask, mask); + hwloc_bitmap_or(mask, mask, obj->online_cpuset); + hwloc_bitmap_and(sys->online_cpuset, sys->online_cpuset, mask); + } else { + /* Just take it as such */ + obj->online_cpuset = hwloc_bitmap_dup(sys->online_cpuset); + hwloc_bitmap_and(obj->online_cpuset, obj->online_cpuset, obj->cpuset); + } + + /* Update allowed cpusets */ + if (obj->allowed_cpuset) { + /* Update ours */ + hwloc_bitmap_and(obj->allowed_cpuset, obj->allowed_cpuset, sys->allowed_cpuset); + + /* Update the given cpuset, but only what we know */ + hwloc_bitmap_copy(mask, obj->cpuset); + hwloc_bitmap_not(mask, mask); + hwloc_bitmap_or(mask, mask, obj->allowed_cpuset); + hwloc_bitmap_and(sys->allowed_cpuset, sys->allowed_cpuset, mask); + } else { + /* Just take it as such */ + obj->allowed_cpuset = hwloc_bitmap_dup(sys->allowed_cpuset); + hwloc_bitmap_and(obj->allowed_cpuset, obj->allowed_cpuset, obj->cpuset); + } + + hwloc_bitmap_free(mask); + } else { + /* This object is the root of a machine */ + sys = obj; + /* Apply complete cpuset to cpuset, online_cpuset and allowed_cpuset, it + * will automatically be applied below */ + if (obj->complete_cpuset) + hwloc_bitmap_and(obj->cpuset, obj->cpuset, obj->complete_cpuset); + else + obj->complete_cpuset = hwloc_bitmap_dup(obj->cpuset); + if (obj->online_cpuset) + hwloc_bitmap_and(obj->online_cpuset, obj->online_cpuset, obj->complete_cpuset); + else + obj->online_cpuset = hwloc_bitmap_dup(obj->complete_cpuset); + if (obj->allowed_cpuset) + hwloc_bitmap_and(obj->allowed_cpuset, obj->allowed_cpuset, obj->complete_cpuset); + else + obj->allowed_cpuset = hwloc_bitmap_dup(obj->complete_cpuset); + } + } + + for_each_child_safe(child, obj, temp) + propagate_unused_cpuset(child, sys); +} + +/* Force full nodeset for non-NUMA machines */ +static void +add_default_object_sets(hwloc_obj_t obj, int parent_has_sets) +{ + hwloc_obj_t child, *temp; + + /* I/O devices (and their children) have no sets */ + if (hwloc_obj_type_is_io(obj->type)) + return; + + if (parent_has_sets && obj->type != HWLOC_OBJ_MISC) { + /* non-MISC object must have cpuset if parent has one. */ + assert(obj->cpuset); + } + + /* other sets must be consistent with main cpuset: + * check cpusets and add nodesets if needed. + * + * MISC may have no sets at all (if added by parent), or usual ones (if added by cpuset), + * but that's not easy to detect, so just make sure sets are consistent as usual. + */ + if (obj->cpuset) { + assert(obj->online_cpuset); + assert(obj->complete_cpuset); + assert(obj->allowed_cpuset); + if (!obj->nodeset) + obj->nodeset = hwloc_bitmap_alloc_full(); + if (!obj->complete_nodeset) + obj->complete_nodeset = hwloc_bitmap_alloc_full(); + if (!obj->allowed_nodeset) + obj->allowed_nodeset = hwloc_bitmap_alloc_full(); + } else { + assert(!obj->online_cpuset); + assert(!obj->complete_cpuset); + assert(!obj->allowed_cpuset); + assert(!obj->nodeset); + assert(!obj->complete_nodeset); + assert(!obj->allowed_nodeset); + } + + for_each_child_safe(child, obj, temp) + add_default_object_sets(child, obj->cpuset != NULL); +} + +/* Setup object cpusets/nodesets by OR'ing its children. */ +HWLOC_DECLSPEC int +hwloc_fill_object_sets(hwloc_obj_t obj) +{ + hwloc_obj_t child; + assert(obj->cpuset != NULL); + child = obj->first_child; + while (child) { + assert(child->cpuset != NULL); + if (child->complete_cpuset) { + if (!obj->complete_cpuset) + obj->complete_cpuset = hwloc_bitmap_alloc(); + hwloc_bitmap_or(obj->complete_cpuset, obj->complete_cpuset, child->complete_cpuset); + } + if (child->online_cpuset) { + if (!obj->online_cpuset) + obj->online_cpuset = hwloc_bitmap_alloc(); + hwloc_bitmap_or(obj->online_cpuset, obj->online_cpuset, child->online_cpuset); + } + if (child->allowed_cpuset) { + if (!obj->allowed_cpuset) + obj->allowed_cpuset = hwloc_bitmap_alloc(); + hwloc_bitmap_or(obj->allowed_cpuset, obj->allowed_cpuset, child->allowed_cpuset); + } + if (child->nodeset) { + if (!obj->nodeset) + obj->nodeset = hwloc_bitmap_alloc(); + hwloc_bitmap_or(obj->nodeset, obj->nodeset, child->nodeset); + } + if (child->complete_nodeset) { + if (!obj->complete_nodeset) + obj->complete_nodeset = hwloc_bitmap_alloc(); + hwloc_bitmap_or(obj->complete_nodeset, obj->complete_nodeset, child->complete_nodeset); + } + if (child->allowed_nodeset) { + if (!obj->allowed_nodeset) + obj->allowed_nodeset = hwloc_bitmap_alloc(); + hwloc_bitmap_or(obj->allowed_nodeset, obj->allowed_nodeset, child->allowed_nodeset); + } + child = child->next_sibling; + } + return 0; +} + +/* Propagate nodesets up and down */ +static void +propagate_nodeset(hwloc_obj_t obj, hwloc_obj_t sys) +{ + hwloc_obj_t child, *temp; + hwloc_bitmap_t parent_nodeset = NULL; + int parent_weight = 0; + + if (!sys && obj->nodeset) { + sys = obj; + if (!obj->complete_nodeset) + obj->complete_nodeset = hwloc_bitmap_dup(obj->nodeset); + if (!obj->allowed_nodeset) + obj->allowed_nodeset = hwloc_bitmap_dup(obj->complete_nodeset); + } + + if (sys) { + if (obj->nodeset) { + /* Some existing nodeset coming from above, to possibly propagate down */ + parent_nodeset = obj->nodeset; + parent_weight = hwloc_bitmap_weight(parent_nodeset); + } else + obj->nodeset = hwloc_bitmap_alloc(); + } + + for_each_child_safe(child, obj, temp) { + /* don't propagate nodesets in I/O objects, keep them NULL */ + if (hwloc_obj_type_is_io(child->type)) + return; + /* don't propagate nodesets in Misc inserted by parent (no nodeset if no cpuset) */ + if (child->type == HWLOC_OBJ_MISC && !child->cpuset) + return; + + /* Propagate singleton nodesets down */ + if (parent_weight == 1) { + if (!child->nodeset) + child->nodeset = hwloc_bitmap_dup(obj->nodeset); + else if (!hwloc_bitmap_isequal(child->nodeset, parent_nodeset)) { + hwloc_debug_bitmap("Oops, parent nodeset %s", parent_nodeset); + hwloc_debug_bitmap(" is different from child nodeset %s, ignoring the child one\n", child->nodeset); + hwloc_bitmap_copy(child->nodeset, parent_nodeset); + } + } + + /* Recurse */ + propagate_nodeset(child, sys); + + /* Propagate children nodesets up */ + if (sys && child->nodeset) + hwloc_bitmap_or(obj->nodeset, obj->nodeset, child->nodeset); + } +} + +/* Propagate allowed and complete nodesets */ +static void +propagate_nodesets(hwloc_obj_t obj) +{ + hwloc_bitmap_t mask = hwloc_bitmap_alloc(); + hwloc_obj_t child, *temp; + + for_each_child_safe(child, obj, temp) { + /* don't propagate nodesets in I/O objects, keep them NULL */ + if (hwloc_obj_type_is_io(child->type)) + continue; + + if (obj->nodeset) { + /* Update complete nodesets down */ + if (child->complete_nodeset) { + hwloc_bitmap_and(child->complete_nodeset, child->complete_nodeset, obj->complete_nodeset); + } else if (child->nodeset) { + child->complete_nodeset = hwloc_bitmap_dup(obj->complete_nodeset); + hwloc_bitmap_and(child->complete_nodeset, child->complete_nodeset, child->nodeset); + } /* else the child doesn't have nodeset information, we can not provide a complete nodeset */ + + /* Update allowed nodesets down */ + if (child->allowed_nodeset) { + hwloc_bitmap_and(child->allowed_nodeset, child->allowed_nodeset, obj->allowed_nodeset); + } else if (child->nodeset) { + child->allowed_nodeset = hwloc_bitmap_dup(obj->allowed_nodeset); + hwloc_bitmap_and(child->allowed_nodeset, child->allowed_nodeset, child->nodeset); + } + } + + propagate_nodesets(child); + + if (obj->nodeset) { + /* Update allowed nodesets up */ + if (child->nodeset && child->allowed_nodeset) { + hwloc_bitmap_copy(mask, child->nodeset); + hwloc_bitmap_andnot(mask, mask, child->allowed_nodeset); + hwloc_bitmap_andnot(obj->allowed_nodeset, obj->allowed_nodeset, mask); + } + } + } + hwloc_bitmap_free(mask); + + if (obj->nodeset) { + /* Apply complete nodeset to nodeset and allowed_nodeset */ + if (obj->complete_nodeset) + hwloc_bitmap_and(obj->nodeset, obj->nodeset, obj->complete_nodeset); + else + obj->complete_nodeset = hwloc_bitmap_dup(obj->nodeset); + if (obj->allowed_nodeset) + hwloc_bitmap_and(obj->allowed_nodeset, obj->allowed_nodeset, obj->complete_nodeset); + else + obj->allowed_nodeset = hwloc_bitmap_dup(obj->complete_nodeset); + } +} + +static void +remove_unused_sets(hwloc_obj_t obj) +{ + hwloc_obj_t child, *temp; + + if (obj->cpuset) { + hwloc_bitmap_and(obj->cpuset, obj->cpuset, obj->online_cpuset); + hwloc_bitmap_and(obj->cpuset, obj->cpuset, obj->allowed_cpuset); + } + if (obj->nodeset) { + hwloc_bitmap_and(obj->nodeset, obj->nodeset, obj->allowed_nodeset); + } + if (obj->type == HWLOC_OBJ_NUMANODE && obj->os_index != (unsigned) -1 && + !hwloc_bitmap_isset(obj->allowed_nodeset, obj->os_index)) { + unsigned i; + hwloc_debug("Dropping memory from disallowed node %u\n", obj->os_index); + obj->memory.local_memory = 0; + obj->memory.total_memory = 0; + for(i=0; imemory.page_types_len; i++) + obj->memory.page_types[i].count = 0; + } + + for_each_child_safe(child, obj, temp) + remove_unused_sets(child); +} + +static void +reorder_children(hwloc_obj_t parent) +{ + /* move the children list on the side */ + hwloc_obj_t *prev, child, children = parent->first_child; + parent->first_child = NULL; + while (children) { + /* dequeue child */ + child = children; + children = child->next_sibling; + /* find where to enqueue it */ + prev = &parent->first_child; + while (*prev + && (!child->cpuset || !(*prev)->cpuset + || hwloc__object_cpusets_compare_first(child, *prev) > 0)) + prev = &((*prev)->next_sibling); + /* enqueue */ + child->next_sibling = *prev; + *prev = child; + } +} + +/* Remove all ignored objects. */ +static int +remove_ignored(hwloc_topology_t topology, hwloc_obj_t *pparent) +{ + hwloc_obj_t parent = *pparent, child, *pchild; + int dropped_children = 0; + int dropped = 0; + + for_each_child_safe(child, parent, pchild) + dropped_children += remove_ignored(topology, pchild); + + if ((parent != topology->levels[0][0] && + topology->ignored_types[parent->type] == HWLOC_IGNORE_TYPE_ALWAYS) + || (parent->type == HWLOC_OBJ_CACHE && parent->attr->cache.type == HWLOC_OBJ_CACHE_INSTRUCTION + && !(topology->flags & HWLOC_TOPOLOGY_FLAG_ICACHES))) { + hwloc_debug("%s", "\nDropping ignored object "); + hwloc_debug_print_object(0, parent); + unlink_and_free_single_object(pparent); + dropped = 1; + + } else if (dropped_children) { + /* we keep this object but its children changed, reorder them by complete_cpuset */ + reorder_children(parent); + } + + return dropped; +} + +/* Remove all children whose cpuset is empty, except NUMA nodes + * since we want to keep memory information, and except PCI bridges and devices. + */ +static void +remove_empty(hwloc_topology_t topology, hwloc_obj_t *pobj) +{ + hwloc_obj_t obj = *pobj, child, *pchild; + + for_each_child_safe(child, obj, pchild) + remove_empty(topology, pchild); + + if (obj->type != HWLOC_OBJ_NUMANODE + && !obj->first_child /* only remove if all children were removed above, so that we don't remove parents of NUMAnode */ + && !hwloc_obj_type_is_io(obj->type) && obj->type != HWLOC_OBJ_MISC + && obj->cpuset /* don't remove if no cpuset at all, there's likely a good reason why it's different from having an empty cpuset */ + && hwloc_bitmap_iszero(obj->cpuset)) { + /* Remove empty children */ + hwloc_debug("%s", "\nRemoving empty object "); + hwloc_debug_print_object(0, obj); + unlink_and_free_single_object(pobj); + } +} + +/* adjust object cpusets according the given droppedcpuset, + * drop object whose cpuset becomes empty, + * and mark dropped nodes in droppednodeset + */ +static void +restrict_object(hwloc_topology_t topology, unsigned long flags, hwloc_obj_t *pobj, hwloc_const_cpuset_t droppedcpuset, hwloc_nodeset_t droppednodeset, int droppingparent) +{ + hwloc_obj_t obj = *pobj, child, *pchild; + int dropping; + int modified = obj->complete_cpuset && hwloc_bitmap_intersects(obj->complete_cpuset, droppedcpuset); + + hwloc_clear_object_distances(obj); + + if (obj->cpuset) + hwloc_bitmap_andnot(obj->cpuset, obj->cpuset, droppedcpuset); + if (obj->complete_cpuset) + hwloc_bitmap_andnot(obj->complete_cpuset, obj->complete_cpuset, droppedcpuset); + if (obj->online_cpuset) + hwloc_bitmap_andnot(obj->online_cpuset, obj->online_cpuset, droppedcpuset); + if (obj->allowed_cpuset) + hwloc_bitmap_andnot(obj->allowed_cpuset, obj->allowed_cpuset, droppedcpuset); + + if (obj->type == HWLOC_OBJ_MISC) { + dropping = droppingparent && !(flags & HWLOC_RESTRICT_FLAG_ADAPT_MISC); + } else if (hwloc_obj_type_is_io(obj->type)) { + dropping = droppingparent && !(flags & HWLOC_RESTRICT_FLAG_ADAPT_IO); + } else { + dropping = droppingparent || (obj->cpuset && hwloc_bitmap_iszero(obj->cpuset)); + } + + if (modified) + for_each_child_safe(child, obj, pchild) + restrict_object(topology, flags, pchild, droppedcpuset, droppednodeset, dropping); + + if (dropping) { + hwloc_debug("%s", "\nRemoving object during restrict"); + hwloc_debug_print_objects(0, obj); + if (obj->type == HWLOC_OBJ_NUMANODE) + hwloc_bitmap_set(droppednodeset, obj->os_index); + /* remove the object from the tree (no need to remove from levels, they will be entirely rebuilt by the caller) */ + unlink_and_free_single_object(pobj); + /* do not remove children. if they were to be removed, they would have been already */ + } +} + +/* adjust object nodesets accordingly the given droppednodeset + */ +static void +restrict_object_nodeset(hwloc_topology_t topology, hwloc_obj_t *pobj, hwloc_nodeset_t droppednodeset) +{ + hwloc_obj_t obj = *pobj, child, *pchild; + + /* if this object isn't modified, don't bother looking at children */ + if (obj->complete_nodeset && !hwloc_bitmap_intersects(obj->complete_nodeset, droppednodeset)) + return; + + if (obj->nodeset) + hwloc_bitmap_andnot(obj->nodeset, obj->nodeset, droppednodeset); + if (obj->complete_nodeset) + hwloc_bitmap_andnot(obj->complete_nodeset, obj->complete_nodeset, droppednodeset); + if (obj->allowed_nodeset) + hwloc_bitmap_andnot(obj->allowed_nodeset, obj->allowed_nodeset, droppednodeset); + + for_each_child_safe(child, obj, pchild) + restrict_object_nodeset(topology, pchild, droppednodeset); +} + +/* we don't want to merge groups that were inserted explicitly with the custom interface */ +static int +can_merge_group(hwloc_topology_t topology, hwloc_obj_t obj) +{ + const char *value; + /* custom-inserted groups are in custom topologies and have no cpusets, + * don't bother calling hwloc_obj_get_info_by_name() and strcmp() uselessly. + */ + if (!topology->backends->is_custom || obj->cpuset) + return 1; + value = hwloc_obj_get_info_by_name(obj, "Backend"); + return (!value) || strcmp(value, "Custom"); +} + +/* + * Merge with the only child if either the parent or the child has a type to be + * ignored while keeping structure + */ +static int +merge_useless_child(hwloc_topology_t topology, hwloc_obj_t *pparent) +{ + hwloc_obj_t parent = *pparent, child, *pchild, ios; + int replacechild = 0, replaceparent = 0, droppedchildren = 0; + + if (!parent->first_child) + /* There are no child, nothing to merge. */ + return 0; + + for_each_child_safe(child, parent, pchild) + droppedchildren += merge_useless_child(topology, pchild); + + if (droppedchildren) + reorder_children(parent); + + child = parent->first_child; + /* we don't merge if there are multiple "important" children. + * non-important ones are at the end of the list. + * look at the second child to find out. + */ + if (child->next_sibling + /* I/O objects may be ignored when trying to merge */ + && !hwloc_obj_type_is_io(child->next_sibling->type) + /* Misc objects without cpuset may be ignored as well */ + && !(child->next_sibling->type == HWLOC_OBJ_MISC && !child->next_sibling->cpuset)) + /* There are several children that prevent from merging */ + return 0; + + /* There is one important child, and some children that may be ignored + * during merging because they can be attached to anything with the same locality. + * Move them to the side during merging, and append them back later. + * This is easy because children with no cpuset are always last in the list. + */ + ios = child->next_sibling; + child->next_sibling = NULL; + + /* Check whether parent and/or child can be replaced */ + if (topology->ignored_types[parent->type] == HWLOC_IGNORE_TYPE_KEEP_STRUCTURE) { + if (parent->type != HWLOC_OBJ_GROUP || can_merge_group(topology, parent)) + /* Parent can be ignored in favor of the child. */ + replaceparent = 1; + } + if (topology->ignored_types[child->type] == HWLOC_IGNORE_TYPE_KEEP_STRUCTURE) { + if (child->type != HWLOC_OBJ_GROUP || can_merge_group(topology, child)) + /* Child can be ignored in favor of the parent. */ + replacechild = 1; + } + + /* Decide which one to actually replace */ + if (replaceparent && replacechild) { + /* If both may be replaced, look at obj_type_priority */ + if (obj_type_priority[parent->type] > obj_type_priority[child->type]) + replaceparent = 0; + else + replacechild = 0; + } + + if (replaceparent) { + /* Replace parent with child */ + hwloc_debug("%s", "\nIgnoring parent "); + hwloc_debug_print_object(0, parent); + if (parent == topology->levels[0][0]) { + child->parent = NULL; + child->depth = 0; + } + unlink_and_free_single_object(pparent); + + } else if (replacechild) { + /* Replace child with parent */ + hwloc_debug("%s", "\nIgnoring child "); + hwloc_debug_print_object(0, child); + unlink_and_free_single_object(&parent->first_child); + } + + if (ios) { + /* append the remaining list of children to the remaining object */ + pchild = &((*pparent)->first_child); + while (*pchild) + pchild = &((*pchild)->next_sibling); + *pchild = ios; + } + + return replaceparent ? 1 : 0; +} + +static void +hwloc_drop_all_io(hwloc_topology_t topology, hwloc_obj_t root) +{ + hwloc_obj_t child, *pchild; + for_each_child_safe(child, root, pchild) { + if (hwloc_obj_type_is_io(child->type)) + unlink_and_free_object_and_children(pchild); + else + hwloc_drop_all_io(topology, child); + } +} + +/* + * If IO_DEVICES and WHOLE_IO are not set, we drop everything. + * If WHOLE_IO is not set, we drop non-interesting devices, + * and bridges that have no children. + * If IO_BRIDGES is also not set, we also drop all bridges + * except the hostbridges. + */ +static void +hwloc_drop_useless_io(hwloc_topology_t topology, hwloc_obj_t root) +{ + hwloc_obj_t child, *pchild; + + if (!(topology->flags & (HWLOC_TOPOLOGY_FLAG_IO_DEVICES|HWLOC_TOPOLOGY_FLAG_WHOLE_IO))) { + /* drop all I/O children */ + hwloc_drop_all_io(topology, root); + return; + } + + if (!(topology->flags & HWLOC_TOPOLOGY_FLAG_WHOLE_IO)) { + /* drop non-interesting devices */ + for_each_child_safe(child, root, pchild) { + if (child->type == HWLOC_OBJ_PCI_DEVICE) { + unsigned classid = child->attr->pcidev.class_id; + unsigned baseclass = classid >> 8; + if (baseclass != 0x03 /* PCI_BASE_CLASS_DISPLAY */ + && baseclass != 0x02 /* PCI_BASE_CLASS_NETWORK */ + && baseclass != 0x01 /* PCI_BASE_CLASS_STORAGE */ + && baseclass != 0x0b /* PCI_BASE_CLASS_PROCESSOR */ + && classid != 0x0c06 /* PCI_CLASS_SERIAL_INFINIBAND */ + && baseclass != 0x12 /* Processing Accelerators */) + unlink_and_free_object_and_children(pchild); + } + } + } + + /* look at remaining children, process recursively, and remove useless bridges */ + for_each_child_safe(child, root, pchild) { + hwloc_drop_useless_io(topology, child); + + if (child->type == HWLOC_OBJ_BRIDGE) { + if (!child->first_child) { + /* bridges with no children are removed if WHOLE_IO isn't given */ + if (!(topology->flags & (HWLOC_TOPOLOGY_FLAG_WHOLE_IO))) { + unlink_and_free_single_object(pchild); + } + + } else if (child->attr->bridge.upstream_type != HWLOC_OBJ_BRIDGE_HOST) { + /* only hostbridges are kept if WHOLE_IO or IO_BRIDGE are not given */ + if (!(topology->flags & (HWLOC_TOPOLOGY_FLAG_IO_BRIDGES|HWLOC_TOPOLOGY_FLAG_WHOLE_IO))) { + unlink_and_free_single_object(pchild); + } + } + } + } +} + +static void +hwloc_propagate_bridge_depth(hwloc_topology_t topology, hwloc_obj_t root, unsigned depth) +{ + hwloc_obj_t child = root->first_child; + while (child) { + if (child->type == HWLOC_OBJ_BRIDGE) { + child->attr->bridge.depth = depth; + hwloc_propagate_bridge_depth(topology, child, depth+1); + } else if (!hwloc_obj_type_is_io(child->type)) { + hwloc_propagate_bridge_depth(topology, child, 0); + } + child = child->next_sibling; + } +} + +static void +hwloc_propagate_symmetric_subtree(hwloc_topology_t topology, hwloc_obj_t root) +{ + hwloc_obj_t child, *array; + + /* assume we're not symmetric by default */ + root->symmetric_subtree = 0; + + /* if no child, we are symmetric */ + if (!root->arity) { + root->symmetric_subtree = 1; + return; + } + + /* look at children, and return if they are not symmetric */ + child = NULL; + while ((child = hwloc_get_next_child(topology, root, child)) != NULL) + hwloc_propagate_symmetric_subtree(topology, child); + while ((child = hwloc_get_next_child(topology, root, child)) != NULL) + if (!child->symmetric_subtree) + return; + + /* now check that children subtrees are identical. + * just walk down the first child in each tree and compare their depth and arities + */ + array = malloc(root->arity * sizeof(*array)); + memcpy(array, root->children, root->arity * sizeof(*array)); + while (1) { + unsigned i; + /* check current level arities and depth */ + for(i=1; iarity; i++) + if (array[i]->depth != array[0]->depth + || array[i]->arity != array[0]->arity) { + free(array); + return; + } + if (!array[0]->arity) + /* no more children level, we're ok */ + break; + /* look at first child of each element now */ + for(i=0; iarity; i++) + array[i] = array[i]->first_child; + } + free(array); + + /* everything went fine, we're symmetric */ + root->symmetric_subtree = 1; +} + +/* + * Initialize handy pointers in the whole topology. + * The topology only had first_child and next_sibling pointers. + * When this funtions return, all parent/children pointers are initialized. + * The remaining fields (levels, cousins, logical_index, depth, ...) will + * be setup later in hwloc_connect_levels(). + * + * Can be called several times, so may have to update the array. + */ +void +hwloc_connect_children(hwloc_obj_t parent) +{ + unsigned n, oldn = parent->arity; + hwloc_obj_t child, prev_child = NULL; + int ok = 1; + + for (n = 0, child = parent->first_child; + child; + n++, prev_child = child, child = child->next_sibling) { + child->parent = parent; + child->sibling_rank = n; + child->prev_sibling = prev_child; + /* already OK in the array? */ + if (n >= oldn || parent->children[n] != child) + ok = 0; + /* recurse */ + hwloc_connect_children(child); + } + parent->last_child = prev_child; + parent->arity = n; + if (!n) { + /* no need for an array anymore */ + free(parent->children); + parent->children = NULL; + return; + } + if (ok) + /* array is already OK (even if too large) */ + return; + + /* alloc a larger array if needed */ + if (oldn < n) { + free(parent->children); + parent->children = malloc(n * sizeof(*parent->children)); + } + /* refill */ + for (n = 0, child = parent->first_child; + child; + n++, child = child->next_sibling) { + parent->children[n] = child; + } +} + +/* + * Check whether there is an object below ROOT that has the same type as OBJ + */ +static int +find_same_type(hwloc_obj_t root, hwloc_obj_t obj) +{ + hwloc_obj_t child; + + if (hwloc_type_cmp(root, obj) == HWLOC_TYPE_EQUAL) + return 1; + + for (child = root->first_child; child; child = child->next_sibling) + if (find_same_type(child, obj)) + return 1; + + return 0; +} + +/* traverse the array of current object and compare them with top_obj. + * if equal, take the object and put its children into the remaining objs. + * if not equal, put the object into the remaining objs. + */ +static int +hwloc_level_take_objects(hwloc_obj_t top_obj, + hwloc_obj_t *current_objs, unsigned n_current_objs, + hwloc_obj_t *taken_objs, unsigned n_taken_objs __hwloc_attribute_unused, + hwloc_obj_t *remaining_objs, unsigned n_remaining_objs __hwloc_attribute_unused) +{ + unsigned taken_i = 0; + unsigned new_i = 0; + unsigned i, j; + + for (i = 0; i < n_current_objs; i++) + if (hwloc_type_cmp(top_obj, current_objs[i]) == HWLOC_TYPE_EQUAL) { + /* Take it, add children. */ + taken_objs[taken_i++] = current_objs[i]; + for (j = 0; j < current_objs[i]->arity; j++) + remaining_objs[new_i++] = current_objs[i]->children[j]; + } else { + /* Leave it. */ + remaining_objs[new_i++] = current_objs[i]; + } + +#ifdef HWLOC_DEBUG + /* Make sure we didn't mess up. */ + assert(taken_i == n_taken_objs); + assert(new_i == n_current_objs - n_taken_objs + n_remaining_objs); +#endif + + return new_i; +} + +/* Given an input object, copy it or its interesting children into the output array. + * If new_obj is NULL, we're just counting interesting ohjects. + */ +static unsigned +hwloc_level_filter_object(hwloc_topology_t topology, + hwloc_obj_t *new_obj, hwloc_obj_t old) +{ + unsigned i, total; + if (hwloc_obj_type_is_io(old->type)) { + if (new_obj) + append_iodevs(topology, old); + return 0; + } + if (old->type != HWLOC_OBJ_MISC) { + if (new_obj) + *new_obj = old; + return 1; + } + for(i=0, total=0; iarity; i++) { + int nb = hwloc_level_filter_object(topology, new_obj, old->children[i]); + if (new_obj) { + new_obj += nb; + } + total += nb; + } + return total; +} + +/* Replace an input array of objects with an input array containing + * only interesting objects for levels. + * Misc objects are removed, their interesting children are added. + * I/O devices are removed and queue to their own lists. + */ +static int +hwloc_level_filter_objects(hwloc_topology_t topology, + hwloc_obj_t **objs, unsigned *n_objs) +{ + hwloc_obj_t *old = *objs, *new; + unsigned nold = *n_objs, nnew, i; + + /* anything to filter? */ + for(i=0; itype) + || old[i]->type == HWLOC_OBJ_MISC) + break; + if (i==nold) + return 0; + + /* count interesting objects and allocate the new array */ + for(i=0, nnew=0; inext_cousin; + } + nb = i; + + /* allocate and fill level */ + *levelp = malloc(nb * sizeof(struct hwloc_obj *)); + obj = first; + i = 0; + while (obj) { + obj->logical_index = i; + (*levelp)[i] = obj; + i++; + obj = obj->next_cousin; + } + + return nb; +} + +/* + * Do the remaining work that hwloc_connect_children() did not do earlier. + */ +int +hwloc_connect_levels(hwloc_topology_t topology) +{ + unsigned l, i=0; + hwloc_obj_t *objs, *taken_objs, *new_objs, top_obj; + unsigned n_objs, n_taken_objs, n_new_objs; + int err; + + /* reset non-root levels (root was initialized during init and will not change here) */ + for(l=1; llevels[l]); + memset(topology->levels+1, 0, (HWLOC_DEPTH_MAX-1)*sizeof(*topology->levels)); + memset(topology->level_nbobjects+1, 0, (HWLOC_DEPTH_MAX-1)*sizeof(*topology->level_nbobjects)); + topology->nb_levels = 1; + /* don't touch next_group_depth, the Group objects are still here */ + + /* initialize all depth to unknown */ + for (l = HWLOC_OBJ_SYSTEM; l < HWLOC_OBJ_TYPE_MAX; l++) + topology->type_depth[l] = HWLOC_TYPE_DEPTH_UNKNOWN; + /* initialize root type depth */ + topology->type_depth[topology->levels[0][0]->type] = 0; + + /* initialize I/O special levels */ + free(topology->bridge_level); + topology->bridge_level = NULL; + topology->bridge_nbobjects = 0; + topology->first_bridge = topology->last_bridge = NULL; + topology->type_depth[HWLOC_OBJ_BRIDGE] = HWLOC_TYPE_DEPTH_BRIDGE; + free(topology->pcidev_level); + topology->pcidev_level = NULL; + topology->pcidev_nbobjects = 0; + topology->first_pcidev = topology->last_pcidev = NULL; + topology->type_depth[HWLOC_OBJ_PCI_DEVICE] = HWLOC_TYPE_DEPTH_PCI_DEVICE; + free(topology->osdev_level); + topology->osdev_level = NULL; + topology->osdev_nbobjects = 0; + topology->first_osdev = topology->last_osdev = NULL; + topology->type_depth[HWLOC_OBJ_OS_DEVICE] = HWLOC_TYPE_DEPTH_OS_DEVICE; + + /* Start with children of the whole system. */ + n_objs = topology->levels[0][0]->arity; + objs = malloc(n_objs * sizeof(objs[0])); + if (!objs) { + errno = ENOMEM; + return -1; + } + memcpy(objs, topology->levels[0][0]->children, n_objs*sizeof(objs[0])); + + /* Filter-out interesting objects */ + err = hwloc_level_filter_objects(topology, &objs, &n_objs); + if (err < 0) + return -1; + + /* Keep building levels while there are objects left in OBJS. */ + while (n_objs) { + /* At this point, the objs array contains only objects that may go into levels */ + + /* First find which type of object is the topmost. + * Don't use PU if there are other types since we want to keep PU at the bottom. + */ + + /* Look for the first non-PU object, and use the first PU if we really find nothing else */ + for (i = 0; i < n_objs; i++) + if (objs[i]->type != HWLOC_OBJ_PU) + break; + top_obj = i == n_objs ? objs[0] : objs[i]; + + /* See if this is actually the topmost object */ + for (i = 0; i < n_objs; i++) { + if (hwloc_type_cmp(top_obj, objs[i]) != HWLOC_TYPE_EQUAL) { + if (find_same_type(objs[i], top_obj)) { + /* OBJS[i] is strictly above an object of the same type as TOP_OBJ, so it + * is above TOP_OBJ. */ + top_obj = objs[i]; + } + } + } + + /* Now peek all objects of the same type, build a level with that and + * replace them with their children. */ + + /* First count them. */ + n_taken_objs = 0; + n_new_objs = 0; + for (i = 0; i < n_objs; i++) + if (hwloc_type_cmp(top_obj, objs[i]) == HWLOC_TYPE_EQUAL) { + n_taken_objs++; + n_new_objs += objs[i]->arity; + } + + /* New level. */ + taken_objs = malloc((n_taken_objs + 1) * sizeof(taken_objs[0])); + /* New list of pending objects. */ + if (n_objs - n_taken_objs + n_new_objs) { + new_objs = malloc((n_objs - n_taken_objs + n_new_objs) * sizeof(new_objs[0])); + } else { +#ifdef HWLOC_DEBUG + assert(!n_new_objs); + assert(n_objs == n_taken_objs); +#endif + new_objs = NULL; + } + + n_new_objs = hwloc_level_take_objects(top_obj, + objs, n_objs, + taken_objs, n_taken_objs, + new_objs, n_new_objs); + + /* Ok, put numbers in the level and link cousins. */ + for (i = 0; i < n_taken_objs; i++) { + taken_objs[i]->depth = topology->nb_levels; + taken_objs[i]->logical_index = i; + if (i) { + taken_objs[i]->prev_cousin = taken_objs[i-1]; + taken_objs[i-1]->next_cousin = taken_objs[i]; + } + } + taken_objs[0]->prev_cousin = NULL; + taken_objs[n_taken_objs-1]->next_cousin = NULL; + + /* One more level! */ + if (top_obj->type == HWLOC_OBJ_CACHE) + hwloc_debug("--- Cache level depth %u", top_obj->attr->cache.depth); + else + hwloc_debug("--- %s level", hwloc_obj_type_string(top_obj->type)); + hwloc_debug(" has number %u\n\n", topology->nb_levels); + + if (topology->type_depth[top_obj->type] == HWLOC_TYPE_DEPTH_UNKNOWN) + topology->type_depth[top_obj->type] = topology->nb_levels; + else + topology->type_depth[top_obj->type] = HWLOC_TYPE_DEPTH_MULTIPLE; /* mark as unknown */ + + taken_objs[n_taken_objs] = NULL; + + topology->level_nbobjects[topology->nb_levels] = n_taken_objs; + topology->levels[topology->nb_levels] = taken_objs; + + topology->nb_levels++; + + free(objs); + + /* Switch to new_objs, after filtering-out interesting objects */ + err = hwloc_level_filter_objects(topology, &new_objs, &n_new_objs); + if (err < 0) + return -1; + + objs = new_objs; + n_objs = n_new_objs; + } + + /* It's empty now. */ + if (objs) + free(objs); + + topology->bridge_nbobjects = hwloc_build_level_from_list(topology->first_bridge, &topology->bridge_level); + topology->pcidev_nbobjects = hwloc_build_level_from_list(topology->first_pcidev, &topology->pcidev_level); + topology->osdev_nbobjects = hwloc_build_level_from_list(topology->first_osdev, &topology->osdev_level); + + hwloc_propagate_symmetric_subtree(topology, topology->levels[0][0]); + + return 0; +} + +void hwloc_alloc_obj_cpusets(hwloc_obj_t obj) +{ + obj->cpuset = hwloc_bitmap_alloc_full(); + obj->complete_cpuset = hwloc_bitmap_alloc(); + obj->online_cpuset = hwloc_bitmap_alloc_full(); + obj->allowed_cpuset = hwloc_bitmap_alloc_full(); + obj->nodeset = hwloc_bitmap_alloc(); + obj->complete_nodeset = hwloc_bitmap_alloc(); + obj->allowed_nodeset = hwloc_bitmap_alloc_full(); +} + +/* Main discovery loop */ +static int +hwloc_discover(struct hwloc_topology *topology) +{ + struct hwloc_backend *backend; + int gotsomeio = 0; + unsigned discoveries = 0; + unsigned need_reconnect = 0; + + /* discover() callbacks should use hwloc_insert to add objects initialized + * through hwloc_alloc_setup_object. + * For node levels, nodeset and memory must be initialized. + * For cache levels, memory and type/depth must be initialized. + * For group levels, depth must be initialized. + */ + + /* There must be at least a PU object for each logical processor, at worse + * produced by hwloc_setup_pu_level() + */ + + /* 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 + * initialized. + */ + + /* A priori, All processors are visible in the topology, online, and allowed + * for the application. + * + * - If some processors exist but topology information is unknown for them + * (and thus the backend couldn't create objects for them), they should be + * added to the complete_cpuset field of the lowest object where the object + * could reside. + * + * - If some processors are not online, they should be dropped from the + * online_cpuset field. + * + * - If some processors are not allowed for the application (e.g. for + * administration reasons), they should be dropped from the allowed_cpuset + * field. + * + * The same applies to the node sets complete_nodeset and allowed_cpuset. + * + * If such field doesn't exist yet, it can be allocated, and initialized to + * zero (for complete), or to full (for online and allowed). The values are + * automatically propagated to the whole tree after detection. + */ + + /* + * Discover CPUs first + */ + backend = topology->backends; + while (NULL != backend) { + int err; + if (backend->component->type != HWLOC_DISC_COMPONENT_TYPE_CPU + && backend->component->type != HWLOC_DISC_COMPONENT_TYPE_GLOBAL) + /* not yet */ + goto next_cpubackend; + if (!backend->discover) + goto next_cpubackend; + + if (need_reconnect && (backend->flags & HWLOC_BACKEND_FLAG_NEED_LEVELS)) { + hwloc_debug("Backend %s forcing a reconnect of levels\n", backend->component->name); + hwloc_connect_children(topology->levels[0][0]); + if (hwloc_connect_levels(topology) < 0) + return -1; + need_reconnect = 0; + } + + err = backend->discover(backend); + if (err >= 0) { + if (backend->component->type == HWLOC_DISC_COMPONENT_TYPE_GLOBAL) + gotsomeio += err; + discoveries++; + if (err > 0) + need_reconnect++; + } + hwloc_debug_print_objects(0, topology->levels[0][0]); + +next_cpubackend: + backend = backend->next; + } + + if (!discoveries) { + hwloc_debug("%s", "No CPU backend enabled or no discovery succeeded\n"); + errno = EINVAL; + return -1; + } + + /* + * Group levels by distances + */ + hwloc_distances_finalize_os(topology); + hwloc_group_by_distances(topology); + + /* Update objects cpusets and nodesets now that the CPU/GLOBAL backend populated PUs and nodes */ + + hwloc_debug("%s", "\nRestrict topology cpusets to existing PU and NODE objects\n"); + collect_proc_cpuset(topology->levels[0][0], NULL); + + hwloc_debug("%s", "\nPropagate offline and disallowed cpus down and up\n"); + propagate_unused_cpuset(topology->levels[0][0], NULL); + + if (topology->levels[0][0]->complete_nodeset && hwloc_bitmap_iszero(topology->levels[0][0]->complete_nodeset)) { + /* No nodeset, drop all of them */ + hwloc_bitmap_free(topology->levels[0][0]->nodeset); + topology->levels[0][0]->nodeset = NULL; + hwloc_bitmap_free(topology->levels[0][0]->complete_nodeset); + topology->levels[0][0]->complete_nodeset = NULL; + hwloc_bitmap_free(topology->levels[0][0]->allowed_nodeset); + topology->levels[0][0]->allowed_nodeset = NULL; + } + hwloc_debug("%s", "\nPropagate nodesets\n"); + propagate_nodeset(topology->levels[0][0], NULL); + propagate_nodesets(topology->levels[0][0]); + + hwloc_debug_print_objects(0, topology->levels[0][0]); + + if (!(topology->flags & HWLOC_TOPOLOGY_FLAG_WHOLE_SYSTEM)) { + hwloc_debug("%s", "\nRemoving unauthorized and offline sets from all sets\n"); + remove_unused_sets(topology->levels[0][0]); + hwloc_debug_print_objects(0, topology->levels[0][0]); + } + + hwloc_debug("%s", "\nAdd default object sets\n"); + add_default_object_sets(topology->levels[0][0], 0); + + /* Now connect handy pointers to make remaining discovery easier. */ + hwloc_debug("%s", "\nOk, finished tweaking, now connect\n"); + hwloc_connect_children(topology->levels[0][0]); + if (hwloc_connect_levels(topology) < 0) + return -1; + hwloc_debug_print_objects(0, topology->levels[0][0]); + + /* + * Additional discovery with other backends + */ + + backend = topology->backends; + need_reconnect = 0; + while (NULL != backend) { + int err; + if (backend->component->type == HWLOC_DISC_COMPONENT_TYPE_CPU + || backend->component->type == HWLOC_DISC_COMPONENT_TYPE_GLOBAL) + /* already done above */ + goto next_noncpubackend; + if (!backend->discover) + goto next_noncpubackend; + + if (need_reconnect && (backend->flags & HWLOC_BACKEND_FLAG_NEED_LEVELS)) { + hwloc_debug("Backend %s forcing a reconnect of levels\n", backend->component->name); + hwloc_connect_children(topology->levels[0][0]); + if (hwloc_connect_levels(topology) < 0) + return -1; + need_reconnect = 0; + } + + err = backend->discover(backend); + if (err >= 0) { + gotsomeio += err; + if (err > 0) + need_reconnect++; + } + hwloc_debug_print_objects(0, topology->levels[0][0]); + +next_noncpubackend: + backend = backend->next; + } + + /* if we got anything, filter interesting objects and update the tree */ + if (gotsomeio) { + hwloc_drop_useless_io(topology, topology->levels[0][0]); + hwloc_debug("%s", "\nNow reconnecting\n"); + hwloc_debug_print_objects(0, topology->levels[0][0]); + hwloc_propagate_bridge_depth(topology, topology->levels[0][0], 0); + } + + /* Removed some stuff */ + + hwloc_debug("%s", "\nRemoving ignored objects\n"); + remove_ignored(topology, &topology->levels[0][0]); + hwloc_debug_print_objects(0, topology->levels[0][0]); + + hwloc_debug("%s", "\nRemoving empty objects except numa nodes and PCI devices\n"); + remove_empty(topology, &topology->levels[0][0]); + if (!topology->levels[0][0]) { + fprintf(stderr, "Topology became empty, aborting!\n"); + abort(); + } + hwloc_debug_print_objects(0, topology->levels[0][0]); + + hwloc_debug("%s", "\nRemoving objects whose type has HWLOC_IGNORE_TYPE_KEEP_STRUCTURE and have only one child or are the only child\n"); + merge_useless_child(topology, &topology->levels[0][0]); + hwloc_debug_print_objects(0, topology->levels[0][0]); + + /* Reconnect things after all these changes */ + hwloc_connect_children(topology->levels[0][0]); + if (hwloc_connect_levels(topology) < 0) + return -1; + + /* accumulate children memory in total_memory fields (only once parent is set) */ + hwloc_debug("%s", "\nPropagate total memory up\n"); + propagate_total_memory(topology->levels[0][0]); + + /* + * Now that objects are numbered, take distance matrices from backends and put them in the main topology. + * + * Some objects may have disappeared (in removed_empty or removed_ignored) since we setup os distances + * (hwloc_distances_finalize_os()) above. Reset them so as to not point to disappeared objects anymore. + */ + hwloc_distances_restrict_os(topology); + hwloc_distances_finalize_os(topology); + hwloc_distances_finalize_logical(topology); + + /* add some identification attributes if not loading from XML */ + if (topology->backends + && strcmp(topology->backends->component->name, "xml")) { + char *value; + /* add a hwlocVersion */ + hwloc_obj_add_info(topology->levels[0][0], "hwlocVersion", VERSION); + /* add a ProcessName */ + value = hwloc_progname(topology); + if (value) { + hwloc_obj_add_info(topology->levels[0][0], "ProcessName", value); + free(value); + } + } + + /* + * Now set binding hooks according to topology->is_thissystem + * what the native OS backend offers. + */ + hwloc_set_binding_hooks(topology); + + return 0; +} + +/* To be before discovery is actually launched, + * Resets everything in case a previous load initialized some stuff. + */ +void +hwloc_topology_setup_defaults(struct hwloc_topology *topology) +{ + struct hwloc_obj *root_obj; + + /* reset support */ + memset(&topology->binding_hooks, 0, sizeof(topology->binding_hooks)); + memset(topology->support.discovery, 0, sizeof(*topology->support.discovery)); + memset(topology->support.cpubind, 0, sizeof(*topology->support.cpubind)); + memset(topology->support.membind, 0, sizeof(*topology->support.membind)); + + /* Only the System object on top by default */ + topology->nb_levels = 1; /* there's at least SYSTEM */ + topology->next_group_depth = 0; + topology->levels[0] = malloc (sizeof (hwloc_obj_t)); + topology->level_nbobjects[0] = 1; + /* NULLify other levels so that we can detect and free old ones in hwloc_connect_levels() if needed */ + memset(topology->levels+1, 0, (HWLOC_DEPTH_MAX-1)*sizeof(*topology->levels)); + topology->bridge_level = NULL; + topology->pcidev_level = NULL; + topology->osdev_level = NULL; + topology->first_bridge = topology->last_bridge = NULL; + topology->first_pcidev = topology->last_pcidev = NULL; + topology->first_osdev = topology->last_osdev = NULL; + + /* Create the actual machine object, but don't touch its attributes yet + * since the OS backend may still change the object into something else + * (for instance System) + */ + root_obj = hwloc_alloc_setup_object(HWLOC_OBJ_MACHINE, 0); + root_obj->depth = 0; + root_obj->logical_index = 0; + root_obj->sibling_rank = 0; + topology->levels[0][0] = root_obj; +} + +int +hwloc_topology_init (struct hwloc_topology **topologyp) +{ + struct hwloc_topology *topology; + int i; + + topology = malloc (sizeof (struct hwloc_topology)); + if(!topology) + return -1; + + hwloc_components_init(topology); + + /* Setup topology context */ + topology->is_loaded = 0; + topology->flags = 0; + topology->is_thissystem = 1; + topology->pid = 0; + topology->userdata = NULL; + + topology->support.discovery = malloc(sizeof(*topology->support.discovery)); + topology->support.cpubind = malloc(sizeof(*topology->support.cpubind)); + topology->support.membind = malloc(sizeof(*topology->support.membind)); + + /* Only ignore useless cruft by default */ + for(i = HWLOC_OBJ_SYSTEM; i < HWLOC_OBJ_TYPE_MAX; i++) + topology->ignored_types[i] = HWLOC_IGNORE_TYPE_NEVER; + topology->ignored_types[HWLOC_OBJ_GROUP] = HWLOC_IGNORE_TYPE_KEEP_STRUCTURE; + + hwloc_distances_init(topology); + + topology->userdata_export_cb = NULL; + topology->userdata_import_cb = NULL; + + /* Make the topology look like something coherent but empty */ + hwloc_topology_setup_defaults(topology); + + *topologyp = topology; + return 0; +} + +int +hwloc_topology_set_pid(struct hwloc_topology *topology __hwloc_attribute_unused, + hwloc_pid_t pid __hwloc_attribute_unused) +{ + /* this does *not* change the backend */ +#ifdef HWLOC_LINUX_SYS + topology->pid = pid; + return 0; +#else /* HWLOC_LINUX_SYS */ + errno = ENOSYS; + return -1; +#endif /* HWLOC_LINUX_SYS */ +} + +int +hwloc_topology_set_fsroot(struct hwloc_topology *topology, const char *fsroot_path) +{ + return hwloc_disc_component_force_enable(topology, + 0 /* api */, + HWLOC_DISC_COMPONENT_TYPE_CPU, "linux", + fsroot_path, NULL, NULL); +} + +int +hwloc_topology_set_synthetic(struct hwloc_topology *topology, const char *description) +{ + return hwloc_disc_component_force_enable(topology, + 0 /* api */, + -1, "synthetic", + description, NULL, NULL); +} + +int +hwloc_topology_set_xml(struct hwloc_topology *topology, + const char *xmlpath) +{ + return hwloc_disc_component_force_enable(topology, + 0 /* api */, + -1, "xml", + xmlpath, NULL, NULL); +} + +int +hwloc_topology_set_xmlbuffer(struct hwloc_topology *topology, + const char *xmlbuffer, + int size) +{ + return hwloc_disc_component_force_enable(topology, + 0 /* api */, + -1, "xml", NULL, + xmlbuffer, (void*) (uintptr_t) size); +} + +int +hwloc_topology_set_custom(struct hwloc_topology *topology) +{ + return hwloc_disc_component_force_enable(topology, + 0 /* api */, + -1, "custom", + NULL, NULL, NULL); +} + +int +hwloc_topology_set_flags (struct hwloc_topology *topology, unsigned long flags) +{ + if (topology->is_loaded) { + /* actually harmless */ + errno = EBUSY; + return -1; + } + topology->flags = flags; + return 0; +} + +unsigned long +hwloc_topology_get_flags (struct hwloc_topology *topology) +{ + return topology->flags; +} + +int +hwloc_topology_ignore_type(struct hwloc_topology *topology, hwloc_obj_type_t type) +{ + if (type >= HWLOC_OBJ_TYPE_MAX) { + errno = EINVAL; + return -1; + } + + if (type == HWLOC_OBJ_PU) { + /* we need the PU level */ + errno = EINVAL; + return -1; + } else if (hwloc_obj_type_is_io(type)) { + /* I/O devices aren't in any level, use topology flags to ignore them */ + errno = EINVAL; + return -1; + } + + topology->ignored_types[type] = HWLOC_IGNORE_TYPE_ALWAYS; + return 0; +} + +int +hwloc_topology_ignore_type_keep_structure(struct hwloc_topology *topology, hwloc_obj_type_t type) +{ + if (type >= HWLOC_OBJ_TYPE_MAX) { + errno = EINVAL; + return -1; + } + + if (type == HWLOC_OBJ_PU) { + /* we need the PU level */ + errno = EINVAL; + return -1; + } else if (hwloc_obj_type_is_io(type)) { + /* I/O devices aren't in any level, use topology flags to ignore them */ + errno = EINVAL; + return -1; + } + + topology->ignored_types[type] = HWLOC_IGNORE_TYPE_KEEP_STRUCTURE; + return 0; +} + +int +hwloc_topology_ignore_all_keep_structure(struct hwloc_topology *topology) +{ + unsigned type; + for(type = HWLOC_OBJ_SYSTEM; type < HWLOC_OBJ_TYPE_MAX; type++) + if (type != HWLOC_OBJ_PU + && !hwloc_obj_type_is_io((hwloc_obj_type_t) type)) + topology->ignored_types[type] = HWLOC_IGNORE_TYPE_KEEP_STRUCTURE; + return 0; +} + +/* traverse the tree and free everything. + * only use first_child/next_sibling so that it works before load() + * and may be used when switching between backend. + */ +static void +hwloc_topology_clear_tree (struct hwloc_topology *topology, struct hwloc_obj *root) +{ + hwloc_obj_t child = root->first_child; + while (child) { + hwloc_obj_t nextchild = child->next_sibling; + hwloc_topology_clear_tree (topology, child); + child = nextchild; + } + hwloc_free_unlinked_object (root); +} + +void +hwloc_topology_clear (struct hwloc_topology *topology) +{ + unsigned l; + hwloc_topology_clear_tree (topology, topology->levels[0][0]); + for (l=0; lnb_levels; l++) { + free(topology->levels[l]); + topology->levels[l] = NULL; + } + free(topology->bridge_level); + free(topology->pcidev_level); + free(topology->osdev_level); +} + +void +hwloc_topology_destroy (struct hwloc_topology *topology) +{ + hwloc_backends_disable_all(topology); + hwloc_components_destroy_all(topology); + + hwloc_topology_clear(topology); + hwloc_distances_destroy(topology); + + free(topology->support.discovery); + free(topology->support.cpubind); + free(topology->support.membind); + free(topology); +} + +int +hwloc_topology_load (struct hwloc_topology *topology) +{ + int err; + + if (topology->is_loaded) { + errno = EBUSY; + return -1; + } + + /* enforce backend anyway if a FORCE variable was given */ + { + const char *fsroot_path_env = getenv("HWLOC_FORCE_FSROOT"); + if (fsroot_path_env) + hwloc_disc_component_force_enable(topology, + 1 /* env force */, + HWLOC_DISC_COMPONENT_TYPE_CPU, "linux", + fsroot_path_env, NULL, NULL); + } + { + const char *xmlpath_env = getenv("HWLOC_FORCE_XMLFILE"); + if (xmlpath_env) + hwloc_disc_component_force_enable(topology, + 1 /* env force */, + -1, "xml", + xmlpath_env, NULL, NULL); + } + + /* only apply non-FORCE variables if we have not changed the backend yet */ + if (!topology->backends) { + const char *fsroot_path_env = getenv("HWLOC_FSROOT"); + if (fsroot_path_env) + hwloc_disc_component_force_enable(topology, + 1 /* env force */, + HWLOC_DISC_COMPONENT_TYPE_CPU, "linux", + fsroot_path_env, NULL, NULL); + } + if (!topology->backends) { + const char *xmlpath_env = getenv("HWLOC_XMLFILE"); + if (xmlpath_env) + hwloc_disc_component_force_enable(topology, + 1 /* env force */, + -1, "xml", + xmlpath_env, NULL, NULL); + } + + /* instantiate all possible other backends now */ + hwloc_disc_components_enable_others(topology); + /* now that backends are enabled, update the thissystem flag */ + hwloc_backends_is_thissystem(topology); + + /* get distance matrix from the environment are store them (as indexes) in the topology. + * indexes will be converted into objects later once the tree will be filled + */ + hwloc_distances_set_from_env(topology); + + /* actual topology discovery */ + err = hwloc_discover(topology); + if (err < 0) + goto out; + +#ifndef HWLOC_DEBUG + if (getenv("HWLOC_DEBUG_CHECK")) +#endif + hwloc_topology_check(topology); + + topology->is_loaded = 1; + return 0; + + out: + hwloc_topology_clear(topology); + hwloc_distances_destroy(topology); + hwloc_topology_setup_defaults(topology); + hwloc_backends_disable_all(topology); + return -1; +} + +int +hwloc_topology_restrict(struct hwloc_topology *topology, hwloc_const_cpuset_t cpuset, unsigned long flags) +{ + hwloc_bitmap_t droppedcpuset, droppednodeset; + + /* make sure we'll keep something in the topology */ + if (!hwloc_bitmap_intersects(cpuset, topology->levels[0][0]->cpuset)) { + errno = EINVAL; /* easy failure, just don't touch the topology */ + return -1; + } + + droppedcpuset = hwloc_bitmap_alloc(); + droppednodeset = hwloc_bitmap_alloc(); + + /* drop object based on the reverse of cpuset, and fill the 'dropped' nodeset */ + hwloc_bitmap_not(droppedcpuset, cpuset); + restrict_object(topology, flags, &topology->levels[0][0], droppedcpuset, droppednodeset, 0 /* root cannot be removed */); + /* update nodesets according to dropped nodeset */ + restrict_object_nodeset(topology, &topology->levels[0][0], droppednodeset); + + hwloc_bitmap_free(droppedcpuset); + hwloc_bitmap_free(droppednodeset); + + hwloc_connect_children(topology->levels[0][0]); + if (hwloc_connect_levels(topology) < 0) + goto out; + + propagate_total_memory(topology->levels[0][0]); + hwloc_distances_restrict(topology, flags); + hwloc_distances_finalize_os(topology); + hwloc_distances_finalize_logical(topology); + return 0; + + out: + /* unrecoverable failure, re-init the topology */ + hwloc_topology_clear(topology); + hwloc_distances_destroy(topology); + hwloc_topology_setup_defaults(topology); + return -1; +} + +int +hwloc_topology_is_thissystem(struct hwloc_topology *topology) +{ + return topology->is_thissystem; +} + +unsigned +hwloc_topology_get_depth(struct hwloc_topology *topology) +{ + return topology->nb_levels; +} + +/* check children between a parent object */ +static void +hwloc__check_children(struct hwloc_obj *parent) +{ + unsigned j; + + if (!parent->arity) { + /* check whether that parent has no children for real */ + assert(!parent->children); + assert(!parent->first_child); + assert(!parent->last_child); + return; + } + /* check whether that parent has children for real */ + assert(parent->children); + assert(parent->first_child); + assert(parent->last_child); + + /* first child specific checks */ + assert(parent->first_child->sibling_rank == 0); + assert(parent->first_child == parent->children[0]); + assert(parent->first_child->prev_sibling == NULL); + + /* last child specific checks */ + assert(parent->last_child->sibling_rank == parent->arity-1); + assert(parent->last_child == parent->children[parent->arity-1]); + assert(parent->last_child->next_sibling == NULL); + + /* check that parent->cpuset == exclusive OR of children + * (can be wrong for complete_cpuset since disallowed/offline/unknown PUs can be removed) + */ + if (parent->cpuset) { + hwloc_bitmap_t remaining_parent_set = hwloc_bitmap_dup(parent->cpuset); + for(j=0; jarity; j++) { + if (!parent->children[j]->cpuset) + continue; + /* check that child cpuset is included in the reminder of the parent */ + assert(hwloc_bitmap_isincluded(parent->children[j]->cpuset, remaining_parent_set)); + hwloc_bitmap_andnot(remaining_parent_set, remaining_parent_set, parent->children[j]->cpuset); + } + if (parent->type == HWLOC_OBJ_PU) { + /* if parent is a PU, its os_index bit may remain. + * it may be in a Misc child inserted by cpuset, or could be in no child */ + if (hwloc_bitmap_weight(remaining_parent_set) == 1) + assert((unsigned) hwloc_bitmap_first(remaining_parent_set) == parent->os_index); + else + assert(hwloc_bitmap_iszero(remaining_parent_set)); + } else { + /* nothing remains */ + assert(hwloc_bitmap_iszero(remaining_parent_set)); + } + hwloc_bitmap_free(remaining_parent_set); + } + + /* check that children complete_cpuset are properly ordered, empty ones may be anywhere + * (can be wrong for main cpuset since removed PUs can break the ordering). + */ + if (parent->complete_cpuset) { + int firstchild; + int prev_firstchild = -1; /* -1 works fine with first comparisons below */ + for(j=0; jarity; j++) { + if (!parent->children[j]->complete_cpuset + || hwloc_bitmap_iszero(parent->children[j]->complete_cpuset)) + continue; + + firstchild = hwloc_bitmap_first(parent->children[j]->complete_cpuset); + assert(prev_firstchild < firstchild); + prev_firstchild = firstchild; + } + } + + /* checks for all children */ + for(j=1; jarity; j++) { + assert(parent->children[j]->parent == parent); + assert(parent->children[j]->sibling_rank == j); + assert(parent->children[j-1]->next_sibling == parent->children[j]); + assert(parent->children[j]->prev_sibling == parent->children[j-1]); + } +} + +static void +hwloc__check_children_depth(struct hwloc_topology *topology, struct hwloc_obj *parent) +{ + hwloc_obj_t child = NULL; + while ((child = hwloc_get_next_child(topology, parent, child)) != NULL) { + if (child->type == HWLOC_OBJ_BRIDGE) + assert(child->depth == (unsigned) HWLOC_TYPE_DEPTH_BRIDGE); + else if (child->type == HWLOC_OBJ_PCI_DEVICE) + assert(child->depth == (unsigned) HWLOC_TYPE_DEPTH_PCI_DEVICE); + else if (child->type == HWLOC_OBJ_OS_DEVICE) + assert(child->depth == (unsigned) HWLOC_TYPE_DEPTH_OS_DEVICE); + else if (child->type == HWLOC_OBJ_MISC) + assert(child->depth == (unsigned) -1); + else if (parent->depth != (unsigned) -1) + assert(child->depth > parent->depth); + hwloc__check_children_depth(topology, child); + } +} + +/* check a whole topology structure */ +void +hwloc_topology_check(struct hwloc_topology *topology) +{ + struct hwloc_obj *obj; + hwloc_obj_type_t type; + unsigned i, j, depth; + + /* check type orders */ + for (type = HWLOC_OBJ_SYSTEM; type < HWLOC_OBJ_TYPE_MAX; type++) { + assert(hwloc_get_order_type(hwloc_get_type_order(type)) == type); + } + for (i = hwloc_get_type_order(HWLOC_OBJ_SYSTEM); + i <= hwloc_get_type_order(HWLOC_OBJ_CORE); i++) { + assert(i == hwloc_get_type_order(hwloc_get_order_type(i))); + } + + /* check that last level is PU */ + assert(hwloc_get_depth_type(topology, hwloc_topology_get_depth(topology)-1) == HWLOC_OBJ_PU); + /* check that other levels are not PU */ + for(i=1; iparent); + + depth = hwloc_topology_get_depth(topology); + + /* check each level */ + for(i=0; idepth == i); + assert(obj->logical_index == j); + /* check that all objects in the level have the same type */ + if (prev) { + assert(hwloc_type_cmp(obj, prev) == HWLOC_TYPE_EQUAL); + assert(prev->next_cousin == obj); + assert(obj->prev_cousin == prev); + } + if (obj->complete_cpuset) { + if (obj->cpuset) + assert(hwloc_bitmap_isincluded(obj->cpuset, obj->complete_cpuset)); + if (obj->online_cpuset) + assert(hwloc_bitmap_isincluded(obj->online_cpuset, obj->complete_cpuset)); + if (obj->allowed_cpuset) + assert(hwloc_bitmap_isincluded(obj->allowed_cpuset, obj->complete_cpuset)); + } + if (obj->complete_nodeset) { + if (obj->nodeset) + assert(hwloc_bitmap_isincluded(obj->nodeset, obj->complete_nodeset)); + if (obj->allowed_nodeset) + assert(hwloc_bitmap_isincluded(obj->allowed_nodeset, obj->complete_nodeset)); + } + /* check that PUs and NUMA nodes have cpuset/nodeset */ + if (obj->type == HWLOC_OBJ_PU) { + assert(obj->cpuset); + assert(hwloc_bitmap_weight(obj->complete_cpuset) == 1); + assert(hwloc_bitmap_first(obj->complete_cpuset) == (int) obj->os_index); + } + if (obj->type == HWLOC_OBJ_NUMANODE) { + assert(obj->nodeset); + assert(hwloc_bitmap_weight(obj->complete_nodeset) == 1); + assert(hwloc_bitmap_first(obj->complete_nodeset) == (int) obj->os_index); + } + /* check children */ + hwloc__check_children(obj); + prev = obj; + } + + /* check first object of the level */ + obj = hwloc_get_obj_by_depth(topology, i, 0); + assert(obj); + assert(!obj->prev_cousin); + + /* check type */ + assert(hwloc_get_depth_type(topology, i) == obj->type); + assert(i == (unsigned) hwloc_get_type_depth(topology, obj->type) || + HWLOC_TYPE_DEPTH_MULTIPLE == hwloc_get_type_depth(topology, obj->type)); + + /* check last object of the level */ + obj = hwloc_get_obj_by_depth(topology, i, width-1); + assert(obj); + assert(!obj->next_cousin); + + /* check last+1 object of the level */ + obj = hwloc_get_obj_by_depth(topology, i, width); + assert(!obj); + } + + /* check bottom objects */ + assert(hwloc_get_nbobjs_by_depth(topology, depth-1) > 0); + for(j=0; jtype == HWLOC_OBJ_PU); + } + + /* check relative depths */ + obj = hwloc_get_root_obj(topology); + assert(obj->depth == 0); + hwloc__check_children_depth(topology, obj); +} + +const struct hwloc_topology_support * +hwloc_topology_get_support(struct hwloc_topology * topology) +{ + return &topology->support; +} + +void hwloc_topology_set_userdata(struct hwloc_topology * topology, const void *userdata) +{ + topology->userdata = (void *) userdata; +} + +void * hwloc_topology_get_userdata(struct hwloc_topology * topology) +{ + return topology->userdata; +} diff --git a/opal/mca/hwloc/hwloc1110/hwloc/src/traversal.c b/opal/mca/hwloc/hwloc1110/hwloc/src/traversal.c new file mode 100644 index 0000000000..97b3e5b3b8 --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/src/traversal.c @@ -0,0 +1,700 @@ +/* + * Copyright © 2009 CNRS + * Copyright © 2009-2015 Inria. All rights reserved. + * Copyright © 2009-2010 Université Bordeaux + * Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved. + * See COPYING in top-level directory. + */ + +#include +#include +#include +#include +#include +#ifdef HAVE_STRINGS_H +#include +#endif /* HAVE_STRINGS_H */ + +int +hwloc_get_type_depth (struct hwloc_topology *topology, hwloc_obj_type_t type) +{ + return topology->type_depth[type]; +} + +hwloc_obj_type_t +hwloc_get_depth_type (hwloc_topology_t topology, unsigned depth) +{ + if (depth >= topology->nb_levels) + switch (depth) { + case HWLOC_TYPE_DEPTH_BRIDGE: + return HWLOC_OBJ_BRIDGE; + case HWLOC_TYPE_DEPTH_PCI_DEVICE: + return HWLOC_OBJ_PCI_DEVICE; + case HWLOC_TYPE_DEPTH_OS_DEVICE: + return HWLOC_OBJ_OS_DEVICE; + default: + return (hwloc_obj_type_t) -1; + } + return topology->levels[depth][0]->type; +} + +unsigned +hwloc_get_nbobjs_by_depth (struct hwloc_topology *topology, unsigned depth) +{ + if (depth >= topology->nb_levels) + switch (depth) { + case HWLOC_TYPE_DEPTH_BRIDGE: + return topology->bridge_nbobjects; + case HWLOC_TYPE_DEPTH_PCI_DEVICE: + return topology->pcidev_nbobjects; + case HWLOC_TYPE_DEPTH_OS_DEVICE: + return topology->osdev_nbobjects; + default: + return 0; + } + return topology->level_nbobjects[depth]; +} + +struct hwloc_obj * +hwloc_get_obj_by_depth (struct hwloc_topology *topology, unsigned depth, unsigned idx) +{ + if (depth >= topology->nb_levels) + switch (depth) { + case HWLOC_TYPE_DEPTH_BRIDGE: + return idx < topology->bridge_nbobjects ? topology->bridge_level[idx] : NULL; + case HWLOC_TYPE_DEPTH_PCI_DEVICE: + return idx < topology->pcidev_nbobjects ? topology->pcidev_level[idx] : NULL; + case HWLOC_TYPE_DEPTH_OS_DEVICE: + return idx < topology->osdev_nbobjects ? topology->osdev_level[idx] : NULL; + default: + return NULL; + } + if (idx >= topology->level_nbobjects[depth]) + return NULL; + return topology->levels[depth][idx]; +} + +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; + int i,src_nbobjects; + unsigned stored = 0; + + if (!src->cpuset) + return 0; + + src_nbobjects = topology->level_nbobjects[src->depth]; + src_objs = topology->levels[src->depth]; + + parent = src; + while (stored < max) { + while (1) { + nextparent = parent->parent; + if (!nextparent) + goto out; + if (!nextparent->cpuset || !hwloc_bitmap_isequal(parent->cpuset, nextparent->cpuset)) + break; + parent = nextparent; + } + + if (!nextparent->cpuset) + break; + + /* traverse src's objects and find those that are in nextparent and were not in parent */ + for(i=0; icpuset, nextparent->cpuset) + && !hwloc_bitmap_isincluded(src_objs[i]->cpuset, parent->cpuset)) { + objs[stored++] = src_objs[i]; + if (stored == max) + goto out; + } + } + parent = nextparent; + } + + out: + return stored; +} + +static int +hwloc__get_largest_objs_inside_cpuset (struct hwloc_obj *current, hwloc_const_bitmap_t set, + struct hwloc_obj ***res, int *max) +{ + int gotten = 0; + unsigned i; + + /* the caller must ensure this */ + if (*max <= 0) + return 0; + + if (hwloc_bitmap_isequal(current->cpuset, set)) { + **res = current; + (*res)++; + (*max)--; + return 1; + } + + for (i=0; iarity; i++) { + hwloc_bitmap_t subset = hwloc_bitmap_dup(set); + int ret; + + /* split out the cpuset part corresponding to this child and see if there's anything to do */ + if (current->children[i]->cpuset) { + hwloc_bitmap_and(subset, subset, current->children[i]->cpuset); + if (hwloc_bitmap_iszero(subset)) { + hwloc_bitmap_free(subset); + continue; + } + } + + ret = hwloc__get_largest_objs_inside_cpuset (current->children[i], subset, res, max); + gotten += ret; + hwloc_bitmap_free(subset); + + /* if no more room to store remaining objects, return what we got so far */ + if (!*max) + break; + } + + return gotten; +} + +int +hwloc_get_largest_objs_inside_cpuset (struct hwloc_topology *topology, hwloc_const_bitmap_t set, + struct hwloc_obj **objs, int max) +{ + struct hwloc_obj *current = topology->levels[0][0]; + + if (!current->cpuset || !hwloc_bitmap_isincluded(set, current->cpuset)) + return -1; + + if (max <= 0) + return 0; + + return hwloc__get_largest_objs_inside_cpuset (current, set, &objs, &max); +} + +const char * +hwloc_obj_type_string (hwloc_obj_type_t obj) +{ + switch (obj) + { + case HWLOC_OBJ_SYSTEM: return "System"; + case HWLOC_OBJ_MACHINE: return "Machine"; + case HWLOC_OBJ_MISC: return "Misc"; + case HWLOC_OBJ_GROUP: return "Group"; + case HWLOC_OBJ_NUMANODE: return "NUMANode"; + case HWLOC_OBJ_PACKAGE: return "Package"; + case HWLOC_OBJ_CACHE: return "Cache"; + case HWLOC_OBJ_CORE: return "Core"; + case HWLOC_OBJ_BRIDGE: return "Bridge"; + case HWLOC_OBJ_PCI_DEVICE: return "PCIDev"; + case HWLOC_OBJ_OS_DEVICE: return "OSDev"; + case HWLOC_OBJ_PU: return "PU"; + default: return "Unknown"; + } +} + +hwloc_obj_type_t +hwloc_obj_type_of_string (const char * string) +{ + if (!strcasecmp(string, "System")) return HWLOC_OBJ_SYSTEM; + if (!strcasecmp(string, "Machine")) return HWLOC_OBJ_MACHINE; + if (!strcasecmp(string, "Misc")) return HWLOC_OBJ_MISC; + if (!strcasecmp(string, "Group")) return HWLOC_OBJ_GROUP; + if (!strcasecmp(string, "NUMANode") || !strcasecmp(string, "Node")) return HWLOC_OBJ_NUMANODE; + if (!strcasecmp(string, "Package") || !strcasecmp(string, "Socket") /* backward compat with v1.10 */) return HWLOC_OBJ_PACKAGE; + if (!strcasecmp(string, "Cache")) return HWLOC_OBJ_CACHE; + if (!strcasecmp(string, "Core")) return HWLOC_OBJ_CORE; + if (!strcasecmp(string, "PU")) return HWLOC_OBJ_PU; + if (!strcasecmp(string, "Bridge")) return HWLOC_OBJ_BRIDGE; + if (!strcasecmp(string, "PCIDev")) return HWLOC_OBJ_PCI_DEVICE; + if (!strcasecmp(string, "OSDev")) return HWLOC_OBJ_OS_DEVICE; + return (hwloc_obj_type_t) -1; +} + +int +hwloc_obj_type_sscanf(const char *string, hwloc_obj_type_t *typep, int *depthattrp, void *typeattrp, size_t typeattrsize) +{ + hwloc_obj_type_t type = (hwloc_obj_type_t) -1; + int depthattr = -1; + hwloc_obj_cache_type_t cachetypeattr = (hwloc_obj_cache_type_t) -1; /* unspecified */ + char *end; + + /* types without depthattr */ + if (!hwloc_strncasecmp(string, "system", 2)) { + type = HWLOC_OBJ_SYSTEM; + } else if (!hwloc_strncasecmp(string, "machine", 2)) { + type = HWLOC_OBJ_MACHINE; + } else if (!hwloc_strncasecmp(string, "node", 1) + || !hwloc_strncasecmp(string, "numa", 1)) { /* matches node and numanode */ + type = HWLOC_OBJ_NUMANODE; + } else if (!hwloc_strncasecmp(string, "package", 2) + || !hwloc_strncasecmp(string, "socket", 2)) { /* backward compat with v1.10 */ + type = HWLOC_OBJ_PACKAGE; + } else if (!hwloc_strncasecmp(string, "core", 2)) { + type = HWLOC_OBJ_CORE; + } else if (!hwloc_strncasecmp(string, "pu", 2)) { + type = HWLOC_OBJ_PU; + } else if (!hwloc_strncasecmp(string, "misc", 2)) { + type = HWLOC_OBJ_MISC; + } else if (!hwloc_strncasecmp(string, "bridge", 2)) { + type = HWLOC_OBJ_BRIDGE; + } else if (!hwloc_strncasecmp(string, "pci", 2)) { + type = HWLOC_OBJ_PCI_DEVICE; + } else if (!hwloc_strncasecmp(string, "os", 2)) { + type = HWLOC_OBJ_OS_DEVICE; + + /* types with depthattr */ + } else if (!hwloc_strncasecmp(string, "cache", 2)) { + type = HWLOC_OBJ_CACHE; + + } else if ((string[0] == 'l' || string[0] == 'L') && string[1] >= '0' && string[1] <= '9') { + type = HWLOC_OBJ_CACHE; + depthattr = strtol(string+1, &end, 10); + if (*end == 'd') { + cachetypeattr = HWLOC_OBJ_CACHE_DATA; + } else if (*end == 'i') { + cachetypeattr = HWLOC_OBJ_CACHE_INSTRUCTION; + } else if (*end == 'u') { + cachetypeattr = HWLOC_OBJ_CACHE_UNIFIED; + } + + } else if (!hwloc_strncasecmp(string, "group", 2)) { + int length; + type = HWLOC_OBJ_GROUP; + length = strcspn(string, "0123456789"); + if (length <= 5 && !hwloc_strncasecmp(string, "group", length) + && string[length] >= '0' && string[length] <= '9') { + depthattr = strtol(string+length, &end, 10); + } + } else + return -1; + + *typep = type; + if (depthattrp) + *depthattrp = depthattr; + if (typeattrp) { + if (type == HWLOC_OBJ_CACHE && sizeof(hwloc_obj_cache_type_t) <= typeattrsize) + memcpy(typeattrp, &cachetypeattr, sizeof(hwloc_obj_cache_type_t)); + } + + return 0; +} + +static const char * +hwloc_pci_class_string(unsigned short class_id) +{ + switch ((class_id & 0xff00) >> 8) { + case 0x00: + switch (class_id) { + case 0x0001: return "VGA"; + } + return "PCI"; + case 0x01: + switch (class_id) { + case 0x0100: return "SCSI"; + case 0x0101: return "IDE"; + case 0x0102: return "Flop"; + case 0x0103: return "IPI"; + case 0x0104: return "RAID"; + case 0x0105: return "ATA"; + case 0x0106: return "SATA"; + case 0x0107: return "SAS"; + case 0x0108: return "NVMExp"; + } + return "Stor"; + case 0x02: + switch (class_id) { + case 0x0200: return "Ether"; + case 0x0201: return "TokRn"; + case 0x0202: return "FDDI"; + case 0x0203: return "ATM"; + case 0x0204: return "ISDN"; + case 0x0205: return "WrdFip"; + case 0x0206: return "PICMG"; + case 0x0207: return "IB"; + } + return "Net"; + case 0x03: + switch (class_id) { + case 0x0300: return "VGA"; + case 0x0301: return "XGA"; + case 0x0302: return "3D"; + } + return "Disp"; + case 0x04: + switch (class_id) { + case 0x0400: return "Video"; + case 0x0401: return "Audio"; + case 0x0402: return "Phone"; + case 0x0403: return "Auddv"; + } + return "MM"; + case 0x05: + switch (class_id) { + case 0x0500: return "RAM"; + case 0x0501: return "Flash"; + } + return "Mem"; + case 0x06: + switch (class_id) { + case 0x0600: return "Host"; + case 0x0601: return "ISA"; + case 0x0602: return "EISA"; + case 0x0603: return "MC"; + case 0x0604: return "PCI_B"; + case 0x0605: return "PCMCIA"; + case 0x0606: return "Nubus"; + case 0x0607: return "CardBus"; + case 0x0608: return "RACEway"; + case 0x0609: return "PCI_SB"; + case 0x060a: return "IB_B"; + } + return "Bridg"; + case 0x07: + switch (class_id) { + case 0x0700: return "Ser"; + case 0x0701: return "Para"; + case 0x0702: return "MSer"; + case 0x0703: return "Modm"; + case 0x0704: return "GPIB"; + case 0x0705: return "SmrtCrd"; + } + return "Comm"; + case 0x08: + switch (class_id) { + case 0x0800: return "PIC"; + case 0x0801: return "DMA"; + case 0x0802: return "Time"; + case 0x0803: return "RTC"; + case 0x0804: return "HtPl"; + case 0x0805: return "SD-HtPl"; + case 0x0806: return "IOMMU"; + } + return "Syst"; + case 0x09: + switch (class_id) { + case 0x0900: return "Kbd"; + case 0x0901: return "Pen"; + case 0x0902: return "Mouse"; + case 0x0903: return "Scan"; + case 0x0904: return "Game"; + } + return "In"; + case 0x0a: + return "Dock"; + case 0x0b: + switch (class_id) { + case 0x0b00: return "386"; + case 0x0b01: return "486"; + case 0x0b02: return "Pent"; + case 0x0b10: return "Alpha"; + case 0x0b20: return "PPC"; + case 0x0b30: return "MIPS"; + case 0x0b40: return "CoProc"; + } + return "Proc"; + case 0x0c: + switch (class_id) { + case 0x0c00: return "Firw"; + case 0x0c01: return "ACCES"; + case 0x0c02: return "SSA"; + case 0x0c03: return "USB"; + case 0x0c04: return "Fiber"; + case 0x0c05: return "SMBus"; + case 0x0c06: return "IB"; + case 0x0c07: return "IPMI"; + case 0x0c08: return "SERCOS"; + case 0x0c09: return "CANBUS"; + } + return "Ser"; + case 0x0d: + switch (class_id) { + case 0x0d00: return "IRDA"; + case 0x0d01: return "IR"; + case 0x0d10: return "RF"; + case 0x0d11: return "Blueth"; + case 0x0d12: return "BroadB"; + case 0x0d20: return "802.1a"; + case 0x0d21: return "802.1b"; + } + return "Wifi"; + case 0x0e: + switch (class_id) { + case 0x0e00: return "I2O"; + } + return "Intll"; + case 0x0f: + switch (class_id) { + case 0x0f00: return "S-TV"; + case 0x0f01: return "S-Aud"; + case 0x0f02: return "S-Voice"; + case 0x0f03: return "S-Data"; + } + return "Satel"; + case 0x10: + return "Crypt"; + case 0x11: + return "Signl"; + case 0x12: + return "Accel"; + case 0x13: + return "Instr"; + case 0xff: + return "Oth"; + } + return "PCI"; +} + +static const char* hwloc_obj_cache_type_letter(hwloc_obj_cache_type_t type) +{ + switch (type) { + case HWLOC_OBJ_CACHE_UNIFIED: return ""; + case HWLOC_OBJ_CACHE_DATA: return "d"; + case HWLOC_OBJ_CACHE_INSTRUCTION: return "i"; + default: return "unknown"; + } +} + +int +hwloc_obj_type_snprintf(char * __hwloc_restrict string, size_t size, hwloc_obj_t obj, int verbose) +{ + hwloc_obj_type_t type = obj->type; + switch (type) { + case HWLOC_OBJ_MISC: + case HWLOC_OBJ_SYSTEM: + case HWLOC_OBJ_MACHINE: + case HWLOC_OBJ_NUMANODE: + case HWLOC_OBJ_PACKAGE: + case HWLOC_OBJ_CORE: + case HWLOC_OBJ_PU: + return hwloc_snprintf(string, size, "%s", hwloc_obj_type_string(type)); + case HWLOC_OBJ_CACHE: + return hwloc_snprintf(string, size, "L%u%s%s", obj->attr->cache.depth, + hwloc_obj_cache_type_letter(obj->attr->cache.type), + verbose ? hwloc_obj_type_string(type): ""); + case HWLOC_OBJ_GROUP: + /* TODO: more pretty presentation? */ + if (obj->attr->group.depth != (unsigned) -1) + return hwloc_snprintf(string, size, "%s%u", hwloc_obj_type_string(type), obj->attr->group.depth); + else + return hwloc_snprintf(string, size, "%s", hwloc_obj_type_string(type)); + case HWLOC_OBJ_BRIDGE: + if (verbose) + return snprintf(string, size, "Bridge %s->%s", + obj->attr->bridge.upstream_type == HWLOC_OBJ_BRIDGE_PCI ? "PCI" : "Host", + "PCI"); + else + return snprintf(string, size, obj->attr->bridge.upstream_type == HWLOC_OBJ_BRIDGE_PCI ? "PCIBridge" : "HostBridge"); + case HWLOC_OBJ_PCI_DEVICE: + return snprintf(string, size, "PCI %04x:%04x", + obj->attr->pcidev.vendor_id, obj->attr->pcidev.device_id); + case HWLOC_OBJ_OS_DEVICE: + switch (obj->attr->osdev.type) { + case HWLOC_OBJ_OSDEV_BLOCK: return hwloc_snprintf(string, size, "Block"); + case HWLOC_OBJ_OSDEV_NETWORK: return hwloc_snprintf(string, size, verbose ? "Network" : "Net"); + case HWLOC_OBJ_OSDEV_OPENFABRICS: return hwloc_snprintf(string, size, "OpenFabrics"); + case HWLOC_OBJ_OSDEV_DMA: return hwloc_snprintf(string, size, "DMA"); + case HWLOC_OBJ_OSDEV_GPU: return hwloc_snprintf(string, size, "GPU"); + case HWLOC_OBJ_OSDEV_COPROC: return hwloc_snprintf(string, size, verbose ? "Co-Processor" : "CoProc"); + default: + *string = '\0'; + return 0; + } + break; + default: + if (size > 0) + *string = '\0'; + return 0; + } +} + +int +hwloc_obj_attr_snprintf(char * __hwloc_restrict string, size_t size, hwloc_obj_t obj, const char * separator, int verbose) +{ + const char *prefix = ""; + char *tmp = string; + ssize_t tmplen = size; + int ret = 0; + int res; + + /* make sure we output at least an empty string */ + if (size) + *string = '\0'; + + /* print memory attributes */ + res = 0; + if (verbose) { + if (obj->memory.local_memory) + res = hwloc_snprintf(tmp, tmplen, "%slocal=%lu%s%stotal=%lu%s", + prefix, + (unsigned long) hwloc_memory_size_printf_value(obj->memory.local_memory, verbose), + hwloc_memory_size_printf_unit(obj->memory.total_memory, verbose), + separator, + (unsigned long) hwloc_memory_size_printf_value(obj->memory.total_memory, verbose), + hwloc_memory_size_printf_unit(obj->memory.local_memory, verbose)); + else if (obj->memory.total_memory) + res = hwloc_snprintf(tmp, tmplen, "%stotal=%lu%s", + prefix, + (unsigned long) hwloc_memory_size_printf_value(obj->memory.total_memory, verbose), + hwloc_memory_size_printf_unit(obj->memory.total_memory, verbose)); + } else { + if (obj->memory.local_memory) + res = hwloc_snprintf(tmp, tmplen, "%s%lu%s", + prefix, + (unsigned long) hwloc_memory_size_printf_value(obj->memory.local_memory, verbose), + hwloc_memory_size_printf_unit(obj->memory.local_memory, verbose)); + } + if (res < 0) + return -1; + ret += res; + if (ret > 0) + prefix = separator; + if (res >= tmplen) + res = tmplen>0 ? tmplen - 1 : 0; + tmp += res; + tmplen -= res; + + /* printf type-specific attributes */ + res = 0; + switch (obj->type) { + case HWLOC_OBJ_CACHE: + if (verbose) { + char assoc[32]; + if (obj->attr->cache.associativity == -1) + snprintf(assoc, sizeof(assoc), "%sfully-associative", separator); + else if (obj->attr->cache.associativity == 0) + *assoc = '\0'; + else + snprintf(assoc, sizeof(assoc), "%sways=%d", separator, obj->attr->cache.associativity); + res = hwloc_snprintf(tmp, tmplen, "%ssize=%lu%s%slinesize=%u%s", + prefix, + (unsigned long) hwloc_memory_size_printf_value(obj->attr->cache.size, verbose), + hwloc_memory_size_printf_unit(obj->attr->cache.size, verbose), + separator, obj->attr->cache.linesize, + assoc); + } else + res = hwloc_snprintf(tmp, tmplen, "%s%lu%s", + prefix, + (unsigned long) hwloc_memory_size_printf_value(obj->attr->cache.size, verbose), + hwloc_memory_size_printf_unit(obj->attr->cache.size, verbose)); + break; + case HWLOC_OBJ_BRIDGE: + if (verbose) { + char up[128], down[64]; + /* upstream is PCI or HOST */ + if (obj->attr->bridge.upstream_type == HWLOC_OBJ_BRIDGE_PCI) { + char linkspeed[64]= ""; + if (obj->attr->pcidev.linkspeed) + snprintf(linkspeed, sizeof(linkspeed), "%slink=%.2fGB/s", separator, obj->attr->pcidev.linkspeed); + snprintf(up, sizeof(up), "busid=%04x:%02x:%02x.%01x%sid=%04x:%04x%sclass=%04x(%s)%s", + obj->attr->pcidev.domain, obj->attr->pcidev.bus, obj->attr->pcidev.dev, obj->attr->pcidev.func, separator, + obj->attr->pcidev.vendor_id, obj->attr->pcidev.device_id, separator, + obj->attr->pcidev.class_id, hwloc_pci_class_string(obj->attr->pcidev.class_id), linkspeed); + } else + *up = '\0'; + /* downstream is_PCI */ + snprintf(down, sizeof(down), "buses=%04x:[%02x-%02x]", + obj->attr->bridge.downstream.pci.domain, obj->attr->bridge.downstream.pci.secondary_bus, obj->attr->bridge.downstream.pci.subordinate_bus); + if (*up) + res = snprintf(string, size, "%s%s%s", up, separator, down); + else + res = snprintf(string, size, "%s", down); + } + break; + case HWLOC_OBJ_PCI_DEVICE: + if (verbose) { + char linkspeed[64]= ""; + char busid[16] = "[collapsed]"; + if (obj->attr->pcidev.linkspeed) + snprintf(linkspeed, sizeof(linkspeed), "%slink=%.2fGB/s", separator, obj->attr->pcidev.linkspeed); + if (!hwloc_obj_get_info_by_name(obj, "lstopoCollapse")) + snprintf(busid, sizeof(busid), "%04x:%02x:%02x.%01x", + obj->attr->pcidev.domain, obj->attr->pcidev.bus, obj->attr->pcidev.dev, obj->attr->pcidev.func); + res = snprintf(string, size, "busid=%s%sclass=%04x(%s)%s", + busid, separator, + obj->attr->pcidev.class_id, hwloc_pci_class_string(obj->attr->pcidev.class_id), linkspeed); + } + break; + default: + break; + } + if (res < 0) + return -1; + ret += res; + if (ret > 0) + prefix = separator; + if (res >= tmplen) + res = tmplen>0 ? tmplen - 1 : 0; + tmp += res; + tmplen -= res; + + /* printf infos */ + if (verbose) { + unsigned i; + for(i=0; iinfos_count; i++) { + if (!strcmp(obj->infos[i].name, "lstopoCollapse")) + continue; + if (strchr(obj->infos[i].value, ' ')) + res = hwloc_snprintf(tmp, tmplen, "%s%s=\"%s\"", + prefix, + obj->infos[i].name, obj->infos[i].value); + else + res = hwloc_snprintf(tmp, tmplen, "%s%s=%s", + prefix, + obj->infos[i].name, obj->infos[i].value); + if (res < 0) + return -1; + ret += res; + if (res >= tmplen) + res = tmplen>0 ? tmplen - 1 : 0; + tmp += res; + tmplen -= res; + if (ret > 0) + prefix = separator; + } + } + + return ret; +} + + +int +hwloc_obj_snprintf(char *string, size_t size, + struct hwloc_topology *topology __hwloc_attribute_unused, struct hwloc_obj *l, const char *_indexprefix, int verbose) +{ + const char *indexprefix = _indexprefix ? _indexprefix : "#"; + char os_index[12] = ""; + char type[64]; + char attr[128]; + int attrlen; + + if (l->os_index != (unsigned) -1) { + hwloc_snprintf(os_index, 12, "%s%u", indexprefix, l->os_index); + } + + hwloc_obj_type_snprintf(type, sizeof(type), l, verbose); + attrlen = hwloc_obj_attr_snprintf(attr, sizeof(attr), l, " ", verbose); + + if (attrlen > 0) + return hwloc_snprintf(string, size, "%s%s(%s)", type, os_index, attr); + else + return hwloc_snprintf(string, size, "%s%s", type, os_index); +} + +int hwloc_obj_cpuset_snprintf(char *str, size_t size, size_t nobj, struct hwloc_obj * const *objs) +{ + hwloc_bitmap_t set = hwloc_bitmap_alloc(); + int res; + unsigned i; + + hwloc_bitmap_zero(set); + for(i=0; icpuset) + hwloc_bitmap_or(set, set, objs[i]->cpuset); + + res = hwloc_bitmap_snprintf(str, size, set); + hwloc_bitmap_free(set); + return res; +} diff --git a/opal/mca/hwloc/hwloc1110/hwloc/tests/README.txt b/opal/mca/hwloc/hwloc1110/hwloc/tests/README.txt new file mode 100644 index 0000000000..2a72583279 --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/tests/README.txt @@ -0,0 +1,4 @@ +Open MPI doesn't need this tree from hwloc. But automake *requires* +that this directory has to be here. So we have an empty directory +with a README in it, a) just to explain why it's here, and b) so that +hg clones won't delete the directory (because it's empty). diff --git a/opal/mca/hwloc/hwloc1110/hwloc/utils/README.txt b/opal/mca/hwloc/hwloc1110/hwloc/utils/README.txt new file mode 100644 index 0000000000..2a72583279 --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc/utils/README.txt @@ -0,0 +1,4 @@ +Open MPI doesn't need this tree from hwloc. But automake *requires* +that this directory has to be here. So we have an empty directory +with a README in it, a) just to explain why it's here, and b) so that +hg clones won't delete the directory (because it's empty). diff --git a/opal/mca/hwloc/hwloc1110/hwloc1110.h b/opal/mca/hwloc/hwloc1110/hwloc1110.h new file mode 100644 index 0000000000..35215b4557 --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc1110.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2011-2013 Cisco Systems, Inc. All rights reserved. + * Copyright (c) 2014-2015 Intel, Inc. All rights reserved. + * + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + * + * When this component is used, this file is included in the rest of + * the OPAL/ORTE/OMPI code base via opal/mca/hwloc/hwloc.h. As such, + * this header represents the public interface to this static component. + */ + +#ifndef MCA_OPAL_HWLOC_HWLOC1110_H +#define MCA_OPAL_HWLOC_HWLOC1110_H + +BEGIN_C_DECLS + +#include "hwloc/include/hwloc.h" + +/* If the including file requested it, also include the hwloc verbs + helper file. We can't just always include this file (even if we + know we have ) because there are some inline + functions in that file that invoke ibv_* functions. Some linkers + (e.g., Solaris Studio Compilers) will instantiate those static + inline functions even if we don't use them, and therefore we need + to be able to resolve the ibv_* symbols at link time. + + Since -libverbs is only specified in places where we use other + ibv_* functions (e.g., the OpenFabrics-based BTLs), that means that + linking random executables can/will fail (e.g., orterun). + */ +#if defined(OPAL_HWLOC_WANT_VERBS_HELPER) && OPAL_HWLOC_WANT_VERBS_HELPER +# if defined(HAVE_INFINIBAND_VERBS_H) +# include "hwloc/include/hwloc/openfabrics-verbs.h" +# else +# error Tried to include hwloc verbs helper file, but hwloc was compiled with no OpenFabrics support +# endif +#endif + +END_C_DECLS + +#endif /* MCA_OPAL_HWLOC_HWLOC1110_H */ diff --git a/opal/mca/hwloc/hwloc1110/hwloc1110_component.c b/opal/mca/hwloc/hwloc1110/hwloc1110_component.c new file mode 100644 index 0000000000..02322fca4b --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/hwloc1110_component.c @@ -0,0 +1,55 @@ +/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ +/* + * Copyright (c) 2011-2013 Cisco Systems, Inc. All rights reserved. + * Copyright (c) 2014-2015 Intel, Inc. All rights reserved. + * Copyright (c) 2015 Los Alamos National Security, LLC. All rights + * reserved. + * + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + * + * These symbols are in a file by themselves to provide nice linker + * semantics. Since linkers generally pull in symbols by object + * files, keeping these symbols as the only symbols in this file + * prevents utility programs such as "ompi_info" from having to import + * entire components just to query their version and parameters. + */ + +#include "opal_config.h" +#include "opal/constants.h" + +#include "opal/mca/hwloc/hwloc.h" +#include "hwloc1110.h" + +/* + * Public string showing the sysinfo ompi_linux component version number + */ +const char *opal_hwloc_hwloc1110_component_version_string = + "OPAL hwloc1110 hwloc MCA component version " OPAL_VERSION; + +/* + * Instantiate the public struct with all of our public information + * and pointers to our public functions in it + */ + +const opal_hwloc_component_t mca_hwloc_hwloc1110_component = { + + /* First, the mca_component_t struct containing meta information + about the component itself */ + + .base_version = { + OPAL_HWLOC_BASE_VERSION_2_0_0, + + /* Component name and version */ + .mca_component_name = "hwloc1110", + MCA_BASE_MAKE_VERSION(component, OPAL_MAJOR_VERSION, OPAL_MINOR_VERSION, + OPAL_RELEASE_VERSION), + }, + .base_data = { + /* The component is checkpoint ready */ + MCA_BASE_METADATA_PARAM_CHECKPOINT + } +}; diff --git a/opal/mca/hwloc/hwloc1110/owner.txt b/opal/mca/hwloc/hwloc1110/owner.txt new file mode 100644 index 0000000000..d72196b959 --- /dev/null +++ b/opal/mca/hwloc/hwloc1110/owner.txt @@ -0,0 +1,7 @@ +# +# owner/status file +# owner: institution that is responsible for this package +# status: e.g. active, maintenance, unmaintained +# +owner:INTEL +status: maintenance diff --git a/opal/mca/hwloc/hwloc191/configure.m4 b/opal/mca/hwloc/hwloc191/configure.m4 index abe75fc59f..d66e68dadb 100644 --- a/opal/mca/hwloc/hwloc191/configure.m4 +++ b/opal/mca/hwloc/hwloc191/configure.m4 @@ -13,7 +13,7 @@ # # Priority # -AC_DEFUN([MCA_opal_hwloc_hwloc191_PRIORITY], [90]) +AC_DEFUN([MCA_opal_hwloc_hwloc191_PRIORITY], [10]) # # Force this component to compile in static-only mode