[m-rev.] For review: Thread pinning improvements.
Paul Bone
pbone at csse.unimelb.edu.au
Wed Oct 5 01:34:57 AEDT 2011
For review by anyone:
While I'm confident that my runtime changes do the right thing I wouldn't mind
if someone would look over the build system changes.
Thanks.
---
Improve thread pinning:
+ Now pins threads intelligently on SMT systems by balancing threads among
cores.
+ performs fewer migrations when pinning threads (If a thread's current
CPU is a valid CPU for pinning, then it is not migrated).
+ Handle cases where the user requests more threads than available CPUs.
+ Handle cases where the process is restricted to a subset of CPUs by its
environment. (for instance, Linux cpuset(7))
This is largely made possible by the hwloc library
http://www.open-mpi.org/projects/hwloc/ However, hwloc is not required and the
runtime system will fall back to sched_setaffinity(), it will simply be less
intelligent WRT SMT.
runtime/mercury_context.h:
runtime/mercury_context.c:
Do thread pinning either via hwloc or sched_setaffinity. Previously only
sched_setaffinity was used.
Update thread-pinning algorithm, this:
Include the general thread pinning code only if MR_HAVE_THREAD_PINNING is
defined.
Use a combination of sysconf and sched_getaffinity to detect the number of
processors when hwloc isn't available. This makes the runtime compatible
with Linux cpuset(7) when hwloc isn't available.
configure.in:
Mmake.common.in:
Detect presence of the hwloc library.
configure.in:
Detect sched_getaffinity()
aclocal.m4:
acinclude.m4:
Move aclocal.m4 to acinclude.m4, the aclocal program will build aclocal.m4
and retrieve macros from the system and the contents of acinclude.m4.
Mmakefile:
Create a make target for aclocal.m4.
runtime/Mmakefile:
Link the runtime with libhwloc in low-level C parallel grades.
Include CFLAGS for libhwloc.
scripts/ml.in:
Link programs and libraries with libhwloc in low-level C parallel grades.
runtime/mercury_conf.h.in:
Define MR_HAVE_HWLOC when it is available.
Define MR_HAVE_SCHED_GETAFFINITY when it is available.
runtime/mercury_conf_param.h:
Define MR_HAVE_THREAD_PINNING if either hwloc or [sched_setaffinity and
sched_getaffinity] are available.
runtime/mercury_thread.c:
runtime/mercury_wrapper.c:
Only call MR_pin_thread and MR_pin_primordial_thread if
MR_HAVE_THREAD_PINNING is defined.
runtime/mercury_thread.h:
runtime/mercury_context.h:
Move the declaration of MR_pin_primordial_thread to mercury_context.h from
mercury_thead.h since it's definition is in mercury_context.c.
Require MR_HAVE_THREAD_PINNING for the declaration of
MR_pin_primordial_thread.
runtime/mercury_wrapper.c:
Conform to changes in mercury_context.h
Index: Mmake.common.in
===================================================================
RCS file: /home/mercury1/repository/mercury/Mmake.common.in,v
retrieving revision 1.103
diff -u -p -b -r1.103 Mmake.common.in
--- Mmake.common.in 17 Dec 2010 11:59:02 -0000 1.103
+++ Mmake.common.in 4 Oct 2011 12:19:52 -0000
@@ -234,6 +234,8 @@ NSL_LIBRARY=@NSL_LIBRARY@
DL_LIBRARY=@DL_LIBRARY@
READLINE_LIBRARIES=@READLINE_LIBRARIES@
TERMCAP_LIBRARY=@TERMCAP_LIBRARY@
+HWLOC_CFLAGS=@HWLOC_CFLAGS@
+HWLOC_LIBS=@HWLOC_LIBS@
# Extensions to use
O=@OBJ_SUFFIX@
Index: Mmakefile
===================================================================
RCS file: /home/mercury1/repository/mercury/Mmakefile,v
retrieving revision 1.145
diff -u -p -b -r1.145 Mmakefile
--- Mmakefile 27 Sep 2011 04:41:21 -0000 1.145
+++ Mmakefile 4 Oct 2011 12:19:52 -0000
@@ -370,6 +370,9 @@ cleanint:
#-----------------------------------------------------------------------------#
+aclocal.m4: configure.in acinclude.m4
+ aclocal
+
configure: configure.in aclocal.m4
autoconf
Index: acinclude.m4
===================================================================
RCS file: acinclude.m4
diff -N acinclude.m4
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ acinclude.m4 4 Oct 2011 12:19:52 -0000
@@ -0,0 +1,665 @@
+#-----------------------------------------------------------------------------#
+# Copyright (C) 1999,2001-2004, 2006-2011 The University of Melbourne.
+# This file may only be copied under the terms of the GNU General
+# Public Licence - see the file COPYING in the Mercury distribution.
+#-----------------------------------------------------------------------------#
+#
+# aclocal.m4
+#
+# This file contains Mercury-specific autoconf tests.
+#
+# We ought to move most of the code in configure.in into this file...
+#
+#-----------------------------------------------------------------------------#
+AC_DEFUN(MERCURY_CHECK_FOR_HEADERS,
+[
+ for mercury_cv_header in $1; do
+ mercury_cv_header_define="MR_HAVE_`echo $mercury_cv_header | \
+ tr abcdefghijklmnopqrstuvwxyz./ ABCDEFGHIJKLMNOPQRSTUVWXYZ__`"
+ AC_CHECK_HEADER($mercury_cv_header, [
+ AC_DEFINE_UNQUOTED($mercury_cv_header_define)
+ eval "$mercury_cv_header_define=1"
+ ])
+ done
+])
+#-----------------------------------------------------------------------------#
+AC_DEFUN(MERCURY_CHECK_FOR_IEEEFP_H,
+[
+ MERCURY_CHECK_FOR_HEADERS(ieeefp.h)
+])
+
+AC_DEFUN(MERCURY_CHECK_FOR_IEEE_FUNC,
+[
+AC_REQUIRE([MERCURY_CHECK_FOR_IEEEFP_H])
+AC_MSG_CHECKING(for $1 function)
+mercury_cv_ieee_func_define="MR_HAVE_`echo $1 | \
+ tr abcdefghijklmnopqrstuvwxyz./ ABCDEFGHIJKLMNOPQRSTUVWXYZ__`"
+
+AC_TRY_LINK([
+ #include <math.h>
+#ifdef MR_HAVE_IEEEFP_H
+ #include <ieeefp.h>
+#endif
+],[
+ float f;
+ $1(f);
+],[mercury_cv_have_ieee_func=yes],[mercury_cv_have_ieee_func=no])
+
+if test "$mercury_cv_have_ieee_func" = yes; then
+ AC_MSG_RESULT(yes)
+ AC_DEFINE_UNQUOTED($mercury_cv_ieee_func_define)
+else
+ AC_MSG_RESULT(no)
+fi
+])
+
+#-----------------------------------------------------------------------------#
+
+# Test for C99 fp environment functions in the math library.
+# The second argument to this macro should be the flags required by the
+# C compiler to link against the math library. This is needed because
+# some OSs, e.g. Mac OS X, don't have a separate math library.
+
+AC_DEFUN([MERCURY_CHECK_FOR_FENV_FUNC],
+[
+AC_MSG_CHECKING(for $1 function)
+mercury_cv_math_func_define="MR_HAVE_`echo $1 | \
+ tr abcdefghijklmnopqrstuvwxyz./ ABCDEFGHIJKLMNOPQRSTUVWXYZ__`"
+
+save_libs="$LIBS"
+LIBS="$2 $LIBS"
+
+AC_TRY_LINK([
+#ifdef MR_HAVE_FENV_H
+ #include <fenv.h>
+#endif
+],[
+
+ int i = 0;
+ $1(i);
+],[mercury_cv_have_math_func=yes],[mercury_cv_have_math_func=no])
+
+LIBS="$save_libs"
+
+if test "$mercury_cv_have_math_func" = "yes"
+then
+ AC_MSG_RESULT([yes])
+ AC_DEFINE_UNQUOTED([$mercury_cv_math_func_define])
+else
+ AC_MSG_RESULT([no])
+fi
+])
+
+#-----------------------------------------------------------------------------#
+#
+# Turn off MacOS's so-called "smart" C preprocessor, if present,
+# since it causes lots of spurious warning messages,
+# and furthermore it takes way too long and uses way too much memory
+# when preprocessing the C code generated by the Mercury compiler's LLDS
+# back-end.
+#
+AC_DEFUN(MERCURY_CHECK_CC_NEEDS_TRAD_CPP,
+[
+AC_REQUIRE([AC_PROG_CC])
+AC_MSG_CHECKING(whether C compiler needs -no-cpp-precomp)
+AC_CACHE_VAL(mercury_cv_cpp_precomp, [
+ >conftest.c
+ if test "$GCC" = yes &&
+ $CC -v -c conftest.c 2>&1 | \
+ grep "cpp-precomp.*-smart" > /dev/null
+ then
+ mercury_cv_cpp_precomp=yes
+ else
+ mercury_cv_cpp_precomp=no
+ fi
+])
+AC_MSG_RESULT($mercury_cv_cpp_precomp)
+if test $mercury_cv_cpp_precomp = yes; then
+ CC="$CC -no-cpp-precomp"
+fi
+])
+#-----------------------------------------------------------------------------#
+#
+# Check whether we need to add any extra directories to the search path for
+# header files, and set ALL_LOCAL_C_INCL_DIRS to the -I option(s) needed
+# for this, if any.
+#
+# GNU C normally searches /usr/local/include by default;
+# to keep things consistent, we do the same for other C compilers.
+#
+AC_DEFUN(MERCURY_CHECK_LOCAL_C_INCL_DIRS,
+[
+AC_REQUIRE([AC_PROG_CC])
+AC_MSG_CHECKING(whether to pass -I/usr/local/include to C compiler)
+ALL_LOCAL_C_INCL_DIRS=""
+ALL_LOCAL_C_INCL_DIR_MMC_OPTS=""
+
+if test "$GCC" = yes -o "$USING_MICROSOFT_CL_COMPILER" = yes; then
+ # Don't add -I/usr/local/include, since it causes a warning
+ # with gcc 3.1, and gcc already searches /usr/local/include.
+ # Microsoft compilers don't understand Unix pathnames.
+ AC_MSG_RESULT(no)
+else
+ # It's some other compiler. We don't know if it searches
+ # /usr/local/include by default, so add it.
+ if test -d /usr/local/include/.; then
+ AC_MSG_RESULT(yes)
+ ALL_LOCAL_C_INCL_DIRS="-I/usr/local/include "
+ ALL_LOCAL_C_INCL_DIR_MMC_OPTS="--c-include-directory /usr/local/include "
+ else
+ AC_MSG_RESULT(no)
+ fi
+fi
+AC_SUBST(ALL_LOCAL_C_INCL_DIRS)
+AC_SUBST(ALL_LOCAL_C_INCL_DIR_MMC_OPTS)
+])
+#-----------------------------------------------------------------------------#
+#
+# Set ALL_LOCAL_C_LIB_DIRS to any extra directories we need to add to the
+# search path for libraries.
+#
+AC_DEFUN(MERCURY_CHECK_LOCAL_C_LIB_DIRS,
+[
+AC_MSG_CHECKING(whether to pass -L/usr/local/lib to the linker)
+
+# Microsoft compilers don't understand Unix pathnames.
+if test "$USING_MICROSOFT_CL_COMPILER" = no -a -d /usr/local/lib/.; then
+ AC_MSG_RESULT(yes)
+ ALL_LOCAL_C_LIB_DIRS=/usr/local/lib
+ ALL_LOCAL_C_LIB_DIR_MMC_OPTS="-L/usr/local/lib -R/usr/local/lib"
+else
+ AC_MSG_RESULT(no)
+ ALL_LOCAL_C_LIB_DIRS=
+ ALL_LOCAL_C_LIB_DIR_MMC_OPTS=
+fi
+AC_SUBST(ALL_LOCAL_C_LIB_DIRS)
+AC_SUBST(ALL_LOCAL_C_LIB_DIR_MMC_OPTS)
+])
+
+#-----------------------------------------------------------------------------#
+#
+# Check for readline and related header files and libraries
+#
+AC_DEFUN(MERCURY_CHECK_READLINE,
+[
+AC_ARG_WITH(readline,
+[ --without-readline Don't use the GPL'd GNU readline library],
+mercury_cv_with_readline="$withval", mercury_cv_with_readline=yes)
+
+if test "$mercury_cv_with_readline" = yes; then
+
+ # check for the readline header files
+ MERCURY_CHECK_FOR_HEADERS(readline/readline.h readline/history.h)
+
+ # check for the libraries that readline depends on
+ MERCURY_MSG('looking for termcap or curses (needed by readline)...')
+ AC_CHECK_LIB(termcap, tgetent, mercury_cv_termcap_lib=-ltermcap,
+ [AC_CHECK_LIB(curses, tgetent, mercury_cv_termcap_lib=-lcurses,
+ [AC_CHECK_LIB(ncurses, tgetent, mercury_cv_termcap_lib=-lncurses,
+ mercury_cv_termcap_lib='')])])
+
+ # check for the readline library
+ AC_CHECK_LIB(readline, readline, mercury_cv_have_readline=yes,
+ mercury_cv_have_readline=no, $mercury_cv_termcap_lib)
+else
+ mercury_cv_have_readline=no
+fi
+
+# Now figure out whether we can use readline, and define variables according.
+# Note that on most systems, we don't actually need the header files in
+# order to use readline. (Ain't C grand? ;-).
+
+if test $mercury_cv_have_readline = no; then
+ TERMCAP_LIBRARY=""
+ READLINE_LIBRARIES=""
+ AC_DEFINE(MR_NO_USE_READLINE)
+else
+ TERMCAP_LIBRARY="$mercury_cv_termcap_lib"
+ READLINE_LIBRARIES="-lreadline $TERMCAP_LIBRARY"
+fi
+AC_SUBST(TERMCAP_LIBRARY)
+AC_SUBST(READLINE_LIBRARIES)
+
+])
+
+#-----------------------------------------------------------------------------#
+#
+# Microsoft.NET configuration
+#
+AC_DEFUN(MERCURY_CHECK_DOTNET,
+[
+AC_PATH_PROG(ILASM, ilasm)
+AC_PATH_PROG(GACUTIL, gacutil)
+
+AC_MSG_CHECKING(for Microsoft.NET Framework SDK)
+AC_CACHE_VAL(mercury_cv_microsoft_dotnet, [
+if test "$ILASM" != ""; then
+ changequote(<<,>>)
+ MS_DOTNET_SDK_DIR=`expr "$ILASM" : '\(.*\)[/\\]*[bB]in[/\\]*ilasm'`
+ changequote([,])
+ mercury_cv_microsoft_dotnet="yes"
+else
+ MS_DOTNET_SDK_DIR=""
+ mercury_cv_microsoft_dotnet="no"
+fi
+])
+AC_MSG_RESULT($mercury_cv_microsoft_dotnet)
+ILASM=`basename "$ILASM"`
+GACUTIL=`basename "$GACUTIL"`
+
+# Check for the C# (C sharp) compiler.
+# gmcs is the Mono C# compiler targeting the 2.0 runtime (with generics).
+# cscc is the DotGNU C# compiler.
+AC_PATH_PROGS(CSC, csc gmcs cscc)
+CSC=`basename "$CSC"`
+
+# We default to the Beta 2 version of the library
+mercury_cv_microsoft_dotnet_library_version=1.0.2411.0
+if test $mercury_cv_microsoft_dotnet = "yes" &&
+ test "$CSC" != "";
+then
+ AC_MSG_CHECKING(version of .NET libraries)
+ cat > conftest.cs << EOF
+ using System;
+ using System.Reflection;
+ public class version {
+ public static void Main()
+ {
+ Assembly asm = Assembly.Load("mscorlib");
+ AssemblyName name = asm.GetName();
+ Version version = name.Version;
+ Console.Write(version);
+ Console.Write("\n");
+ }
+ }
+EOF
+ if
+ echo $CSC conftest.cs >&AC_FD_CC 2>&1 && \
+ $CSC conftest.cs >&AC_FD_CC 2>&1 && \
+ ./conftest > conftest.out 2>&1
+ then
+ mercury_cv_microsoft_dotnet_library_version=`cat conftest.out`
+ AC_MSG_RESULT($mercury_cv_microsoft_dotnet_library_version)
+ rm -f conftest*
+ else
+ rm -f conftest*
+ if test "$enable_dotnet_grades" = "yes"; then
+ AC_MSG_ERROR(unable to determine version)
+ exit 1
+ else
+ AC_MSG_WARN(unable to determine version)
+ fi
+ fi
+fi
+MS_DOTNET_LIBRARY_VERSION=$mercury_cv_microsoft_dotnet_library_version
+
+# Check for the assembly linker.
+# ilalink is the DotGNU assembly linker.
+AC_PATH_PROGS(MS_AL, al ilalink)
+MS_AL=`basename "$MS_AL"`
+
+# Check for an implementation of the Common Language Infrastructure.
+AC_PATH_PROGS(CLI_INTERPRETER, mono)
+MONO=`basename "$CLI_INTERPRETER"`
+
+AC_SUBST(ILASM)
+AC_SUBST(GACUTIL)
+AC_SUBST(CSC)
+AC_SUBST(MS_AL)
+AC_SUBST(MS_DOTNET_SDK_DIR)
+AC_SUBST(MS_DOTNET_LIBRARY_VERSION)
+AC_SUBST(MS_VISUALCPP_DIR)
+AC_SUBST(CLI_INTERPRETER)
+])
+
+#-----------------------------------------------------------------------------#
+#
+# Java configuration
+#
+AC_DEFUN(MERCURY_CHECK_JAVA,
+[
+# jikes requires the usual Java SDK to run, so if we checked for javac first,
+# then that's what we'd get. If the user has jikes installed, then that
+# probably means that they want to use it, so we check for jikes before javac.
+# On Windows, the Java SDK has a high chance of being installed in a path
+# containing spaces. The simplest solution is to keep only the basename.
+# Everything will still work so long as the executables can be found on the
+# PATH later.
+AC_PATH_PROGS(JAVAC, jikes javac gcj)
+case "$JAVAC" in
+ *" "*)
+ JAVAC=`basename "$JAVAC"`
+ ;;
+esac
+case "$JAVAC" in
+ *gcj)
+ JAVAC="$JAVAC -C"
+ ;;
+esac
+AC_PATH_PROG(JAVA_INTERPRETER, java gij)
+case "$JAVA_INTERPRETER" in
+ *" "*)
+ JAVA_INTERPRETER=`basename "$JAVA_INTERPRETER"`
+ ;;
+esac
+AC_PATH_PROG(JAR, jar)
+case "$JAR" in
+ *" "*)
+ JAR=`basename "$JAR"`
+ ;;
+esac
+
+AC_CACHE_VAL(mercury_cv_java, [
+if test "$JAVAC" != "" -a "$JAVA_INTERPRETER" != "" -a "$JAR" != ""; then
+ AC_MSG_CHECKING(if the above Java SDK works and is sufficiently recent)
+ cat > conftest.java << EOF
+ // This program simply retrieves the constant
+ // specifying the version number of the Java SDK and
+ // checks it is at least 1.5, printing "Hello, world"
+ // if successful.
+ public class conftest {
+ public static void main (String[[]] args) {
+ float version;
+ String strVer = System.getProperty(
+ "java.specification.version");
+
+ try {
+ version = Float.valueOf(strVer).floatValue();
+ }
+ catch (NumberFormatException e) {
+ System.out.println("ERROR: \"java." +
+ "specification.version\" " +
+ "constant has incorrect " +
+ "format.\nGot \"" + strVer +
+ "\", expected a number.");
+ version = 0f;
+ }
+
+ if (version >= 1.5f) {
+ System.out.println("Hello, world\n");
+ } else {
+ System.out.println("Nope, sorry.\n");
+ }
+ }
+ }
+EOF
+ if
+ echo "$JAVAC" conftest.java >&AC_FD_CC 2>&1 &&
+ "$JAVAC" conftest.java >&AC_FD_CC 2>&1 &&
+ echo "$JAVA_INTERPRETER" conftest > conftest.out 2>&AC_FD_CC &&
+ CLASSPATH=. "$JAVA_INTERPRETER" conftest > conftest.out 2>&AC_FD_CC &&
+ test "`tr -d '\015' < conftest.out`" = "Hello, world"
+ then
+ mercury_cv_java="yes"
+ else
+ mercury_cv_java="no"
+ fi
+ AC_MSG_RESULT($mercury_cv_java)
+else
+ if test "$JAVAC" = ""; then
+ JAVAC="javac"
+ fi
+ if test "$JAVA_INTERPRETER" = ""; then
+ JAVA_INTERPRETER="java"
+ fi
+ if test "$JAR" = ""; then
+ JAR="jar"
+ fi
+ mercury_cv_java="no"
+fi
+])
+
+AC_SUBST(JAVAC)
+AC_SUBST(JAVA_INTERPRETER)
+AC_SUBST(JAR)
+])
+
+AC_DEFUN(MERCURY_CHECK_JAVAC_HEAP_SIZE,
+[
+# The default maximum heap size is too small to build the standard library and
+# other programs so we need to increase it. The option to do that is
+# non-standard so we have to check that it is accepted.
+AC_CACHE_VAL(mercury_cv_javac_flags_for_heap_size, [
+if test "$mercury_cv_java" = "yes"; then
+ AC_MSG_CHECKING(if the Java compiler accepts the max heap size option)
+ mercury_cv_javac_flags_for_heap_size="-J-Xmx256m"
+ if "$JAVAC" "$mercury_cv_javac_flags_for_heap_size" -version \
+ 2> /dev/null
+ then
+ AC_MSG_RESULT(yes)
+ else
+ AC_MSG_RESULT(no)
+ mercury_cv_javac_flags_for_heap_size=
+ fi
+else
+ mercury_cv_javac_flags_for_heap_size=
+fi
+])
+])
+
+#-----------------------------------------------------------------------------#
+#
+# Erlang configuration
+#
+
+# copy of AC_ERLANG_PATH_ERLC from autoconf-2.60
+AC_DEFUN([MERCURY_ERLANG_PATH_ERLC],
+[AC_ARG_VAR([ERLC], [Erlang/OTP compiler command [autodetected]])dnl
+if test -n "$ERLC"; then
+ AC_MSG_CHECKING([for erlc])
+ AC_MSG_RESULT([$ERLC])
+else
+ AC_PATH_TOOL(ERLC, erlc, [$1], [$2])
+fi
+AC_ARG_VAR([ERLCFLAGS], [Erlang/OTP compiler flags [none]])dnl
+])
+
+# copy of AC_ERLANG_PATH_ERL from autoconf-2.60
+AC_DEFUN([MERCURY_ERLANG_PATH_ERL],
+[AC_ARG_VAR([ERL], [Erlang/OTP interpreter command [autodetected]])dnl
+if test -n "$ERL"; then
+ AC_MSG_CHECKING([for erl])
+ AC_MSG_RESULT([$ERL])
+else
+ AC_PATH_TOOL(ERL, erl, [$1], [$2])[]dnl
+fi
+])
+
+AC_DEFUN(MERCURY_CHECK_ERLANG,
+[
+MERCURY_ERLANG_PATH_ERLC
+MERCURY_ERLANG_PATH_ERL
+
+if test "$ERLC" != "" -a "$ERL" != ""; then
+ mercury_cv_erlang="yes"
+else
+ mercury_cv_erlang="no"
+fi
+
+AC_SUBST(ERLC)
+AC_SUBST(ERL)
+])
+
+#-----------------------------------------------------------------------------#
+
+# NOTE: updates to this macro may need to be reflected in compiler/globals.m.
+
+AC_DEFUN([MERCURY_GCC_VERSION], [
+AC_REQUIRE([AC_PROG_CC])
+
+cat > conftest.c << EOF
+
+#include <stdio.h>
+
+int main(int argc, char **argv)
+{
+
+#if defined(__GNUC__)
+ printf("%d_", __GNUC__);
+ #if defined(__GNUC_MINOR__)
+ printf("%d_", __GNUC_MINOR__);
+ #else
+ printf("u_");
+ #endif /* ! __GNUC_MINOR__ */
+ #if defined(__GNUC_PATCHLEVEL__)
+ printf("%d", __GNUC_PATCHLEVEL__);
+ #else
+ printf("u");
+ #endif /* ! __GNUC_PATCHLEVEL__ */
+#endif /* __GNUC__ */
+
+ return 0;
+}
+EOF
+
+echo "$CC -o conftest contest.c" >&AC_FD_CC 2>&1
+if
+ $CC -o conftest conftest.c
+then
+ mercury_cv_gcc_version=`./conftest`
+else
+ # This shouldn't happen as we have already checked for this.
+ AC_MSG_ERROR([unexpected: $CC cannot create executable])
+fi
+])
+
+#-----------------------------------------------------------------------------#
+
+# Work out the C compiler type using a stronger test than AC_PROG_CC to
+# distinguish between clang and gcc.
+# (We don't handle lcc here - I don't think that it's possible to.)
+
+AC_DEFUN([MERCURY_CC_TYPE], [
+AC_REQUIRE([AC_PROG_CC])
+AC_MSG_CHECKING([what the C compiler type really is])
+
+cat > conftest.c << EOF
+
+#include <stdio.h>
+
+int main(int argc, char **argv)
+{
+ #if defined(__clang__)
+ printf("clang");
+ #elif defined(__GNUC__)
+ printf("gcc");
+ #elif defined(_MSC_VER)
+ printf("msvc");
+ #else
+ printf("unknown");
+ #endif
+
+ return 0;
+}
+EOF
+
+echo "$CC -o conftest conftest.c" >&AC_FD_CC 2>&1
+if
+ $CC -o conftest conftest.c
+then
+ mercury_cv_cc_type=`./conftest`
+else
+ # This shouldn't happen as we have already checked for this.
+ AC_MSG_ERROR([unexpected: $CC cannot create executable])
+fi
+
+AC_MSG_RESULT([$mercury_cv_cc_type])
+])
+
+#-----------------------------------------------------------------------------#
+
+AC_DEFUN([MERCURY_CLANG_VERSION], [
+AC_REQUIRE([AC_PROG_CC])
+
+cat > conftest.c << EOF
+
+#include <stdio.h>
+
+int main(int argc, char **argv)
+{
+
+ printf("%d_%d_%d", __clang_major__, __clang_minor__, __clang_patchlevel__);
+ return 0;
+}
+EOF
+
+echo "$CC -o conftest contest.c" >&AC_FD_CC 2>&1
+if
+ $CC -o conftest conftest.c
+then
+ mercury_cv_clang_version=`./conftest`
+else
+ # This shouldn't happen as we have already checked for this.
+ AC_MSG_ERROR([unexpected: $CC cannot create executable])
+fi
+])
+
+#-----------------------------------------------------------------------------#
+
+AC_DEFUN([MERCURY_MSVC_VERSION], [
+AC_REQUIRE([AC_PROG_CC])
+
+cat > conftest.c << EOF
+
+#include <stdio.h>
+
+int main(int argc, char **argv)
+{
+
+ printf("%d", _MSC_VER);
+ return 0;
+}
+EOF
+
+echo "$CC conftest.c -Fecontest" >&AC_FD_CC 2>&1
+if
+ $CC conftest.c -Feconftest > /dev/null
+then
+ mercury_cv_msvc_version=`./conftest`
+else
+ # This shouldn't happen as we have already checked for this.
+ AC_MSG_ERROR([unexpected: $CC cannot create executable])
+fi
+])
+
+#-----------------------------------------------------------------------------#
+#
+# Check if the POSIX threads library is pthreads-win32.
+#
+
+AC_DEFUN([MERCURY_HAVE_PTHREADS_WIN32], [
+
+AC_MSG_CHECKING([if we are using pthreads-win32])
+
+cat > conftest.c << EOF
+
+#include <pthread.h>
+#include <stdio.h>
+
+int main(int argc, char **argv)
+{
+
+#if defined(PTW32_VERSION)
+ return 0;
+#else
+ return 1;
+#endif
+
+}
+
+EOF
+
+echo "$CC -o conftest contest.c" >&AC_FD_CC 2>&1
+if
+ $CC -o conftest conftest.c
+then
+ mercury_cv_have_pthreads_win32="yes"
+else
+ mercury_cv_have_pthreads_win32="no"
+fi
+
+AC_MSG_RESULT($mercury_cv_have_pthreads_win32)
+
+])
+
+#-----------------------------------------------------------------------------#
Index: aclocal.m4
===================================================================
RCS file: aclocal.m4
diff -N aclocal.m4
--- aclocal.m4 3 Sep 2011 17:50:32 -0000 1.39
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,665 +0,0 @@
-#-----------------------------------------------------------------------------#
-# Copyright (C) 1999,2001-2004, 2006-2011 The University of Melbourne.
-# This file may only be copied under the terms of the GNU General
-# Public Licence - see the file COPYING in the Mercury distribution.
-#-----------------------------------------------------------------------------#
-#
-# aclocal.m4
-#
-# This file contains Mercury-specific autoconf tests.
-#
-# We ought to move most of the code in configure.in into this file...
-#
-#-----------------------------------------------------------------------------#
-AC_DEFUN(MERCURY_CHECK_FOR_HEADERS,
-[
- for mercury_cv_header in $1; do
- mercury_cv_header_define="MR_HAVE_`echo $mercury_cv_header | \
- tr abcdefghijklmnopqrstuvwxyz./ ABCDEFGHIJKLMNOPQRSTUVWXYZ__`"
- AC_CHECK_HEADER($mercury_cv_header, [
- AC_DEFINE_UNQUOTED($mercury_cv_header_define)
- eval "$mercury_cv_header_define=1"
- ])
- done
-])
-#-----------------------------------------------------------------------------#
-AC_DEFUN(MERCURY_CHECK_FOR_IEEEFP_H,
-[
- MERCURY_CHECK_FOR_HEADERS(ieeefp.h)
-])
-
-AC_DEFUN(MERCURY_CHECK_FOR_IEEE_FUNC,
-[
-AC_REQUIRE([MERCURY_CHECK_FOR_IEEEFP_H])
-AC_MSG_CHECKING(for $1 function)
-mercury_cv_ieee_func_define="MR_HAVE_`echo $1 | \
- tr abcdefghijklmnopqrstuvwxyz./ ABCDEFGHIJKLMNOPQRSTUVWXYZ__`"
-
-AC_TRY_LINK([
- #include <math.h>
-#ifdef MR_HAVE_IEEEFP_H
- #include <ieeefp.h>
-#endif
-],[
- float f;
- $1(f);
-],[mercury_cv_have_ieee_func=yes],[mercury_cv_have_ieee_func=no])
-
-if test "$mercury_cv_have_ieee_func" = yes; then
- AC_MSG_RESULT(yes)
- AC_DEFINE_UNQUOTED($mercury_cv_ieee_func_define)
-else
- AC_MSG_RESULT(no)
-fi
-])
-
-#-----------------------------------------------------------------------------#
-
-# Test for C99 fp environment functions in the math library.
-# The second argument to this macro should be the flags required by the
-# C compiler to link against the math library. This is needed because
-# some OSs, e.g. Mac OS X, don't have a separate math library.
-
-AC_DEFUN([MERCURY_CHECK_FOR_FENV_FUNC],
-[
-AC_MSG_CHECKING(for $1 function)
-mercury_cv_math_func_define="MR_HAVE_`echo $1 | \
- tr abcdefghijklmnopqrstuvwxyz./ ABCDEFGHIJKLMNOPQRSTUVWXYZ__`"
-
-save_libs="$LIBS"
-LIBS="$2 $LIBS"
-
-AC_TRY_LINK([
-#ifdef MR_HAVE_FENV_H
- #include <fenv.h>
-#endif
-],[
-
- int i = 0;
- $1(i);
-],[mercury_cv_have_math_func=yes],[mercury_cv_have_math_func=no])
-
-LIBS="$save_libs"
-
-if test "$mercury_cv_have_math_func" = "yes"
-then
- AC_MSG_RESULT([yes])
- AC_DEFINE_UNQUOTED([$mercury_cv_math_func_define])
-else
- AC_MSG_RESULT([no])
-fi
-])
-
-#-----------------------------------------------------------------------------#
-#
-# Turn off MacOS's so-called "smart" C preprocessor, if present,
-# since it causes lots of spurious warning messages,
-# and furthermore it takes way too long and uses way too much memory
-# when preprocessing the C code generated by the Mercury compiler's LLDS
-# back-end.
-#
-AC_DEFUN(MERCURY_CHECK_CC_NEEDS_TRAD_CPP,
-[
-AC_REQUIRE([AC_PROG_CC])
-AC_MSG_CHECKING(whether C compiler needs -no-cpp-precomp)
-AC_CACHE_VAL(mercury_cv_cpp_precomp, [
- >conftest.c
- if test "$GCC" = yes &&
- $CC -v -c conftest.c 2>&1 | \
- grep "cpp-precomp.*-smart" > /dev/null
- then
- mercury_cv_cpp_precomp=yes
- else
- mercury_cv_cpp_precomp=no
- fi
-])
-AC_MSG_RESULT($mercury_cv_cpp_precomp)
-if test $mercury_cv_cpp_precomp = yes; then
- CC="$CC -no-cpp-precomp"
-fi
-])
-#-----------------------------------------------------------------------------#
-#
-# Check whether we need to add any extra directories to the search path for
-# header files, and set ALL_LOCAL_C_INCL_DIRS to the -I option(s) needed
-# for this, if any.
-#
-# GNU C normally searches /usr/local/include by default;
-# to keep things consistent, we do the same for other C compilers.
-#
-AC_DEFUN(MERCURY_CHECK_LOCAL_C_INCL_DIRS,
-[
-AC_REQUIRE([AC_PROG_CC])
-AC_MSG_CHECKING(whether to pass -I/usr/local/include to C compiler)
-ALL_LOCAL_C_INCL_DIRS=""
-ALL_LOCAL_C_INCL_DIR_MMC_OPTS=""
-
-if test "$GCC" = yes -o "$USING_MICROSOFT_CL_COMPILER" = yes; then
- # Don't add -I/usr/local/include, since it causes a warning
- # with gcc 3.1, and gcc already searches /usr/local/include.
- # Microsoft compilers don't understand Unix pathnames.
- AC_MSG_RESULT(no)
-else
- # It's some other compiler. We don't know if it searches
- # /usr/local/include by default, so add it.
- if test -d /usr/local/include/.; then
- AC_MSG_RESULT(yes)
- ALL_LOCAL_C_INCL_DIRS="-I/usr/local/include "
- ALL_LOCAL_C_INCL_DIR_MMC_OPTS="--c-include-directory /usr/local/include "
- else
- AC_MSG_RESULT(no)
- fi
-fi
-AC_SUBST(ALL_LOCAL_C_INCL_DIRS)
-AC_SUBST(ALL_LOCAL_C_INCL_DIR_MMC_OPTS)
-])
-#-----------------------------------------------------------------------------#
-#
-# Set ALL_LOCAL_C_LIB_DIRS to any extra directories we need to add to the
-# search path for libraries.
-#
-AC_DEFUN(MERCURY_CHECK_LOCAL_C_LIB_DIRS,
-[
-AC_MSG_CHECKING(whether to pass -L/usr/local/lib to the linker)
-
-# Microsoft compilers don't understand Unix pathnames.
-if test "$USING_MICROSOFT_CL_COMPILER" = no -a -d /usr/local/lib/.; then
- AC_MSG_RESULT(yes)
- ALL_LOCAL_C_LIB_DIRS=/usr/local/lib
- ALL_LOCAL_C_LIB_DIR_MMC_OPTS="-L/usr/local/lib -R/usr/local/lib"
-else
- AC_MSG_RESULT(no)
- ALL_LOCAL_C_LIB_DIRS=
- ALL_LOCAL_C_LIB_DIR_MMC_OPTS=
-fi
-AC_SUBST(ALL_LOCAL_C_LIB_DIRS)
-AC_SUBST(ALL_LOCAL_C_LIB_DIR_MMC_OPTS)
-])
-
-#-----------------------------------------------------------------------------#
-#
-# Check for readline and related header files and libraries
-#
-AC_DEFUN(MERCURY_CHECK_READLINE,
-[
-AC_ARG_WITH(readline,
-[ --without-readline Don't use the GPL'd GNU readline library],
-mercury_cv_with_readline="$withval", mercury_cv_with_readline=yes)
-
-if test "$mercury_cv_with_readline" = yes; then
-
- # check for the readline header files
- MERCURY_CHECK_FOR_HEADERS(readline/readline.h readline/history.h)
-
- # check for the libraries that readline depends on
- MERCURY_MSG('looking for termcap or curses (needed by readline)...')
- AC_CHECK_LIB(termcap, tgetent, mercury_cv_termcap_lib=-ltermcap,
- [AC_CHECK_LIB(curses, tgetent, mercury_cv_termcap_lib=-lcurses,
- [AC_CHECK_LIB(ncurses, tgetent, mercury_cv_termcap_lib=-lncurses,
- mercury_cv_termcap_lib='')])])
-
- # check for the readline library
- AC_CHECK_LIB(readline, readline, mercury_cv_have_readline=yes,
- mercury_cv_have_readline=no, $mercury_cv_termcap_lib)
-else
- mercury_cv_have_readline=no
-fi
-
-# Now figure out whether we can use readline, and define variables according.
-# Note that on most systems, we don't actually need the header files in
-# order to use readline. (Ain't C grand? ;-).
-
-if test $mercury_cv_have_readline = no; then
- TERMCAP_LIBRARY=""
- READLINE_LIBRARIES=""
- AC_DEFINE(MR_NO_USE_READLINE)
-else
- TERMCAP_LIBRARY="$mercury_cv_termcap_lib"
- READLINE_LIBRARIES="-lreadline $TERMCAP_LIBRARY"
-fi
-AC_SUBST(TERMCAP_LIBRARY)
-AC_SUBST(READLINE_LIBRARIES)
-
-])
-
-#-----------------------------------------------------------------------------#
-#
-# Microsoft.NET configuration
-#
-AC_DEFUN(MERCURY_CHECK_DOTNET,
-[
-AC_PATH_PROG(ILASM, ilasm)
-AC_PATH_PROG(GACUTIL, gacutil)
-
-AC_MSG_CHECKING(for Microsoft.NET Framework SDK)
-AC_CACHE_VAL(mercury_cv_microsoft_dotnet, [
-if test "$ILASM" != ""; then
- changequote(<<,>>)
- MS_DOTNET_SDK_DIR=`expr "$ILASM" : '\(.*\)[/\\]*[bB]in[/\\]*ilasm'`
- changequote([,])
- mercury_cv_microsoft_dotnet="yes"
-else
- MS_DOTNET_SDK_DIR=""
- mercury_cv_microsoft_dotnet="no"
-fi
-])
-AC_MSG_RESULT($mercury_cv_microsoft_dotnet)
-ILASM=`basename "$ILASM"`
-GACUTIL=`basename "$GACUTIL"`
-
-# Check for the C# (C sharp) compiler.
-# gmcs is the Mono C# compiler targeting the 2.0 runtime (with generics).
-# cscc is the DotGNU C# compiler.
-AC_PATH_PROGS(CSC, csc gmcs cscc)
-CSC=`basename "$CSC"`
-
-# We default to the Beta 2 version of the library
-mercury_cv_microsoft_dotnet_library_version=1.0.2411.0
-if test $mercury_cv_microsoft_dotnet = "yes" &&
- test "$CSC" != "";
-then
- AC_MSG_CHECKING(version of .NET libraries)
- cat > conftest.cs << EOF
- using System;
- using System.Reflection;
- public class version {
- public static void Main()
- {
- Assembly asm = Assembly.Load("mscorlib");
- AssemblyName name = asm.GetName();
- Version version = name.Version;
- Console.Write(version);
- Console.Write("\n");
- }
- }
-EOF
- if
- echo $CSC conftest.cs >&AC_FD_CC 2>&1 && \
- $CSC conftest.cs >&AC_FD_CC 2>&1 && \
- ./conftest > conftest.out 2>&1
- then
- mercury_cv_microsoft_dotnet_library_version=`cat conftest.out`
- AC_MSG_RESULT($mercury_cv_microsoft_dotnet_library_version)
- rm -f conftest*
- else
- rm -f conftest*
- if test "$enable_dotnet_grades" = "yes"; then
- AC_MSG_ERROR(unable to determine version)
- exit 1
- else
- AC_MSG_WARN(unable to determine version)
- fi
- fi
-fi
-MS_DOTNET_LIBRARY_VERSION=$mercury_cv_microsoft_dotnet_library_version
-
-# Check for the assembly linker.
-# ilalink is the DotGNU assembly linker.
-AC_PATH_PROGS(MS_AL, al ilalink)
-MS_AL=`basename "$MS_AL"`
-
-# Check for an implementation of the Common Language Infrastructure.
-AC_PATH_PROGS(CLI_INTERPRETER, mono)
-MONO=`basename "$CLI_INTERPRETER"`
-
-AC_SUBST(ILASM)
-AC_SUBST(GACUTIL)
-AC_SUBST(CSC)
-AC_SUBST(MS_AL)
-AC_SUBST(MS_DOTNET_SDK_DIR)
-AC_SUBST(MS_DOTNET_LIBRARY_VERSION)
-AC_SUBST(MS_VISUALCPP_DIR)
-AC_SUBST(CLI_INTERPRETER)
-])
-
-#-----------------------------------------------------------------------------#
-#
-# Java configuration
-#
-AC_DEFUN(MERCURY_CHECK_JAVA,
-[
-# jikes requires the usual Java SDK to run, so if we checked for javac first,
-# then that's what we'd get. If the user has jikes installed, then that
-# probably means that they want to use it, so we check for jikes before javac.
-# On Windows, the Java SDK has a high chance of being installed in a path
-# containing spaces. The simplest solution is to keep only the basename.
-# Everything will still work so long as the executables can be found on the
-# PATH later.
-AC_PATH_PROGS(JAVAC, jikes javac gcj)
-case "$JAVAC" in
- *" "*)
- JAVAC=`basename "$JAVAC"`
- ;;
-esac
-case "$JAVAC" in
- *gcj)
- JAVAC="$JAVAC -C"
- ;;
-esac
-AC_PATH_PROG(JAVA_INTERPRETER, java gij)
-case "$JAVA_INTERPRETER" in
- *" "*)
- JAVA_INTERPRETER=`basename "$JAVA_INTERPRETER"`
- ;;
-esac
-AC_PATH_PROG(JAR, jar)
-case "$JAR" in
- *" "*)
- JAR=`basename "$JAR"`
- ;;
-esac
-
-AC_CACHE_VAL(mercury_cv_java, [
-if test "$JAVAC" != "" -a "$JAVA_INTERPRETER" != "" -a "$JAR" != ""; then
- AC_MSG_CHECKING(if the above Java SDK works and is sufficiently recent)
- cat > conftest.java << EOF
- // This program simply retrieves the constant
- // specifying the version number of the Java SDK and
- // checks it is at least 1.5, printing "Hello, world"
- // if successful.
- public class conftest {
- public static void main (String[[]] args) {
- float version;
- String strVer = System.getProperty(
- "java.specification.version");
-
- try {
- version = Float.valueOf(strVer).floatValue();
- }
- catch (NumberFormatException e) {
- System.out.println("ERROR: \"java." +
- "specification.version\" " +
- "constant has incorrect " +
- "format.\nGot \"" + strVer +
- "\", expected a number.");
- version = 0f;
- }
-
- if (version >= 1.5f) {
- System.out.println("Hello, world\n");
- } else {
- System.out.println("Nope, sorry.\n");
- }
- }
- }
-EOF
- if
- echo "$JAVAC" conftest.java >&AC_FD_CC 2>&1 &&
- "$JAVAC" conftest.java >&AC_FD_CC 2>&1 &&
- echo "$JAVA_INTERPRETER" conftest > conftest.out 2>&AC_FD_CC &&
- CLASSPATH=. "$JAVA_INTERPRETER" conftest > conftest.out 2>&AC_FD_CC &&
- test "`tr -d '\015' < conftest.out`" = "Hello, world"
- then
- mercury_cv_java="yes"
- else
- mercury_cv_java="no"
- fi
- AC_MSG_RESULT($mercury_cv_java)
-else
- if test "$JAVAC" = ""; then
- JAVAC="javac"
- fi
- if test "$JAVA_INTERPRETER" = ""; then
- JAVA_INTERPRETER="java"
- fi
- if test "$JAR" = ""; then
- JAR="jar"
- fi
- mercury_cv_java="no"
-fi
-])
-
-AC_SUBST(JAVAC)
-AC_SUBST(JAVA_INTERPRETER)
-AC_SUBST(JAR)
-])
-
-AC_DEFUN(MERCURY_CHECK_JAVAC_HEAP_SIZE,
-[
-# The default maximum heap size is too small to build the standard library and
-# other programs so we need to increase it. The option to do that is
-# non-standard so we have to check that it is accepted.
-AC_CACHE_VAL(mercury_cv_javac_flags_for_heap_size, [
-if test "$mercury_cv_java" = "yes"; then
- AC_MSG_CHECKING(if the Java compiler accepts the max heap size option)
- mercury_cv_javac_flags_for_heap_size="-J-Xmx256m"
- if "$JAVAC" "$mercury_cv_javac_flags_for_heap_size" -version \
- 2> /dev/null
- then
- AC_MSG_RESULT(yes)
- else
- AC_MSG_RESULT(no)
- mercury_cv_javac_flags_for_heap_size=
- fi
-else
- mercury_cv_javac_flags_for_heap_size=
-fi
-])
-])
-
-#-----------------------------------------------------------------------------#
-#
-# Erlang configuration
-#
-
-# copy of AC_ERLANG_PATH_ERLC from autoconf-2.60
-AC_DEFUN([MERCURY_ERLANG_PATH_ERLC],
-[AC_ARG_VAR([ERLC], [Erlang/OTP compiler command [autodetected]])dnl
-if test -n "$ERLC"; then
- AC_MSG_CHECKING([for erlc])
- AC_MSG_RESULT([$ERLC])
-else
- AC_PATH_TOOL(ERLC, erlc, [$1], [$2])
-fi
-AC_ARG_VAR([ERLCFLAGS], [Erlang/OTP compiler flags [none]])dnl
-])
-
-# copy of AC_ERLANG_PATH_ERL from autoconf-2.60
-AC_DEFUN([MERCURY_ERLANG_PATH_ERL],
-[AC_ARG_VAR([ERL], [Erlang/OTP interpreter command [autodetected]])dnl
-if test -n "$ERL"; then
- AC_MSG_CHECKING([for erl])
- AC_MSG_RESULT([$ERL])
-else
- AC_PATH_TOOL(ERL, erl, [$1], [$2])[]dnl
-fi
-])
-
-AC_DEFUN(MERCURY_CHECK_ERLANG,
-[
-MERCURY_ERLANG_PATH_ERLC
-MERCURY_ERLANG_PATH_ERL
-
-if test "$ERLC" != "" -a "$ERL" != ""; then
- mercury_cv_erlang="yes"
-else
- mercury_cv_erlang="no"
-fi
-
-AC_SUBST(ERLC)
-AC_SUBST(ERL)
-])
-
-#-----------------------------------------------------------------------------#
-
-# NOTE: updates to this macro may need to be reflected in compiler/globals.m.
-
-AC_DEFUN([MERCURY_GCC_VERSION], [
-AC_REQUIRE([AC_PROG_CC])
-
-cat > conftest.c << EOF
-
-#include <stdio.h>
-
-int main(int argc, char **argv)
-{
-
-#if defined(__GNUC__)
- printf("%d_", __GNUC__);
- #if defined(__GNUC_MINOR__)
- printf("%d_", __GNUC_MINOR__);
- #else
- printf("u_");
- #endif /* ! __GNUC_MINOR__ */
- #if defined(__GNUC_PATCHLEVEL__)
- printf("%d", __GNUC_PATCHLEVEL__);
- #else
- printf("u");
- #endif /* ! __GNUC_PATCHLEVEL__ */
-#endif /* __GNUC__ */
-
- return 0;
-}
-EOF
-
-echo "$CC -o conftest contest.c" >&AC_FD_CC 2>&1
-if
- $CC -o conftest conftest.c
-then
- mercury_cv_gcc_version=`./conftest`
-else
- # This shouldn't happen as we have already checked for this.
- AC_MSG_ERROR([unexpected: $CC cannot create executable])
-fi
-])
-
-#-----------------------------------------------------------------------------#
-
-# Work out the C compiler type using a stronger test than AC_PROG_CC to
-# distinguish between clang and gcc.
-# (We don't handle lcc here - I don't think that it's possible to.)
-
-AC_DEFUN([MERCURY_CC_TYPE], [
-AC_REQUIRE([AC_PROG_CC])
-AC_MSG_CHECKING([what the C compiler type really is])
-
-cat > conftest.c << EOF
-
-#include <stdio.h>
-
-int main(int argc, char **argv)
-{
- #if defined(__clang__)
- printf("clang");
- #elif defined(__GNUC__)
- printf("gcc");
- #elif defined(_MSC_VER)
- printf("msvc");
- #else
- printf("unknown");
- #endif
-
- return 0;
-}
-EOF
-
-echo "$CC -o conftest conftest.c" >&AC_FD_CC 2>&1
-if
- $CC -o conftest conftest.c
-then
- mercury_cv_cc_type=`./conftest`
-else
- # This shouldn't happen as we have already checked for this.
- AC_MSG_ERROR([unexpected: $CC cannot create executable])
-fi
-
-AC_MSG_RESULT([$mercury_cv_cc_type])
-])
-
-#-----------------------------------------------------------------------------#
-
-AC_DEFUN([MERCURY_CLANG_VERSION], [
-AC_REQUIRE([AC_PROG_CC])
-
-cat > conftest.c << EOF
-
-#include <stdio.h>
-
-int main(int argc, char **argv)
-{
-
- printf("%d_%d_%d", __clang_major__, __clang_minor__, __clang_patchlevel__);
- return 0;
-}
-EOF
-
-echo "$CC -o conftest contest.c" >&AC_FD_CC 2>&1
-if
- $CC -o conftest conftest.c
-then
- mercury_cv_clang_version=`./conftest`
-else
- # This shouldn't happen as we have already checked for this.
- AC_MSG_ERROR([unexpected: $CC cannot create executable])
-fi
-])
-
-#-----------------------------------------------------------------------------#
-
-AC_DEFUN([MERCURY_MSVC_VERSION], [
-AC_REQUIRE([AC_PROG_CC])
-
-cat > conftest.c << EOF
-
-#include <stdio.h>
-
-int main(int argc, char **argv)
-{
-
- printf("%d", _MSC_VER);
- return 0;
-}
-EOF
-
-echo "$CC conftest.c -Fecontest" >&AC_FD_CC 2>&1
-if
- $CC conftest.c -Feconftest > /dev/null
-then
- mercury_cv_msvc_version=`./conftest`
-else
- # This shouldn't happen as we have already checked for this.
- AC_MSG_ERROR([unexpected: $CC cannot create executable])
-fi
-])
-
-#-----------------------------------------------------------------------------#
-#
-# Check if the POSIX threads library is pthreads-win32.
-#
-
-AC_DEFUN([MERCURY_HAVE_PTHREADS_WIN32], [
-
-AC_MSG_CHECKING([if we are using pthreads-win32])
-
-cat > conftest.c << EOF
-
-#include <pthread.h>
-#include <stdio.h>
-
-int main(int argc, char **argv)
-{
-
-#if defined(PTW32_VERSION)
- return 0;
-#else
- return 1;
-#endif
-
-}
-
-EOF
-
-echo "$CC -o conftest contest.c" >&AC_FD_CC 2>&1
-if
- $CC -o conftest conftest.c
-then
- mercury_cv_have_pthreads_win32="yes"
-else
- mercury_cv_have_pthreads_win32="no"
-fi
-
-AC_MSG_RESULT($mercury_cv_have_pthreads_win32)
-
-])
-
-#-----------------------------------------------------------------------------#
Index: configure.in
===================================================================
RCS file: /home/mercury1/repository/mercury/configure.in,v
retrieving revision 1.596
diff -u -p -b -r1.596 configure.in
--- configure.in 4 Oct 2011 02:37:57 -0000 1.596
+++ configure.in 4 Oct 2011 14:31:39 -0000
@@ -1265,7 +1265,7 @@ mercury_check_for_functions \
grantpt unlockpt ptsname tcgetattr tcsetattr ioctl \
access sleep opendir readdir closedir mkdir symlink readlink \
gettimeofday setenv putenv _putenv posix_spawn sched_setaffinity \
- sched_getcpu sched_yield mkstemp
+ sched_getaffinity sched_getcpu sched_yield mkstemp
#-----------------------------------------------------------------------------#
@@ -5107,6 +5107,30 @@ MERCURY_CHECK_READLINE
#-----------------------------------------------------------------------------#
#
+# Check for libhwloc, http://www.open-mpi.org/projects/hwloc/
+#
+PKG_PROG_PKG_CONFIG
+PKG_CHECK_MODULES(libhwloc, hwloc >= 1.0,
+ [
+ AC_DEFINE(MR_HAVE_HWLOC)
+ ],
+ [
+ case "$LIBGRADES" in
+ $BEST_LLDS_BASE_GRADE.par.gc*)
+ MERCURY_MSG(["Warning: libhwloc not found, thread pinning in"])
+ MERCURY_MSG(["low-level C parallel grades may be less accurate."])
+ ;;
+ *)
+ ;;
+ esac
+ ])
+HWLOC_LIBS="$libhwloc_LIBS"
+HWLOC_CFLAGS="$libhwloc_CFLAGS"
+AC_SUBST(HWLOC_LIBS)
+AC_SUBST(HWLOC_CFLAGS)
+
+#-----------------------------------------------------------------------------#
+#
# Check for flex and bison
#
Index: runtime/Mmakefile
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/Mmakefile,v
retrieving revision 1.152
diff -u -p -b -r1.152 Mmakefile
--- runtime/Mmakefile 30 Sep 2010 07:23:33 -0000 1.152
+++ runtime/Mmakefile 4 Oct 2011 12:19:52 -0000
@@ -252,10 +252,14 @@ LDLIBS = $(SHARED_GC_LIBS)
THREADLIBS = \
` case "$(GRADE)" in \
- *.par*|*.mps*) echo "-lpthread" ;; \
+ *.mps*) echo $(THREAD_LIBS) ;; \
+ *.hlc.par*) echo $(THREAD_LIBS) ;; \
+ *.par*) echo "$(THREAD_LIBS) $(HWLOC_LIBS)" ;; \
esac \
`
+CFLAGS += $(HWLOC_CFLAGS)
+
$(HDR_CHECK_OBJS): mercury_conf.h
#-----------------------------------------------------------------------------#
Index: runtime/mercury_conf.h.in
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_conf.h.in,v
retrieving revision 1.72
diff -u -p -b -r1.72 mercury_conf.h.in
--- runtime/mercury_conf.h.in 6 Sep 2011 05:20:44 -0000 1.72
+++ runtime/mercury_conf.h.in 4 Oct 2011 14:31:39 -0000
@@ -274,6 +274,7 @@
** MR_HAVE_POSIX_SPAWN we have the posix_spawn() function.
** MR_HAVE_FESETROUND we have the fesetround() function.
** MR_HAVE_SCHED_SETAFFINITY we have the sched_setaffinity() function.
+** MR_HAVE_SCHED_GETAFFINITY we have the sched_gettaffinity() function.
** MR_HAVE_SCHED_GETCPU we have the sched_getcpu() function (glibc specific).
** MR_HAVE_SCHED_YIELD we have the sched_yield() function.
** MR_HAVE_PTHREAD_MUTEXATTR_SETPSHARED we have the
@@ -342,6 +343,7 @@
#undef MR_HAVE_POSIX_SPAWN
#undef MR_HAVE_FESETROUND
#undef MR_HAVE_SCHED_SETAFFINITY
+#undef MR_HAVE_SCHED_GETAFFINITY
#undef MR_HAVE_SCHED_GETCPU
#undef MR_HAVE_SCHED_YIELD
#undef MR_HAVE_PTHREAD_MUTEXATTR_SETPSHARED
@@ -420,6 +422,11 @@
#undef MR_PTHREADS_WIN32
/*
+** MR_HAVE_HWLOC is defined if the hwloc library is available.
+*/
+#undef MR_HAVE_HWLOC
+
+/*
** The bytecode files represent floats in 64-bit IEEE format.
**
** MR_FLOAT_IS_64_BITS: defined iff the C type `float' is exactly 64 bits.
Index: runtime/mercury_conf_param.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_conf_param.h,v
retrieving revision 1.121
diff -u -p -b -r1.121 mercury_conf_param.h
--- runtime/mercury_conf_param.h 22 Aug 2011 07:56:10 -0000 1.121
+++ runtime/mercury_conf_param.h 4 Oct 2011 14:31:39 -0000
@@ -1067,4 +1067,15 @@
/*---------------------------------------------------------------------------*/
+/*
+** MR_HAVE_THREAD_PINNING is defined if we can pin threads, either with
+** sched_setaffinity or hwloc.
+*/
+#if (defined(MR_HAVE_SCHED_SETAFFINITY) && \
+ defined(MR_HAVE_SCHED_GETAFFINITY)) || defined(MR_HAVE_HWLOC)
+ #define MR_HAVE_THREAD_PINNING
+#endif
+
+/*---------------------------------------------------------------------------*/
+
#endif /* MERCURY_CONF_PARAM_H */
Index: runtime/mercury_context.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_context.c,v
retrieving revision 1.99
diff -u -p -b -r1.99 mercury_context.c
--- runtime/mercury_context.c 12 Sep 2011 08:09:24 -0000 1.99
+++ runtime/mercury_context.c 4 Oct 2011 14:32:11 -0000
@@ -46,6 +46,10 @@ ENDINIT
#include <sys/timeb.h> /* for _ftime() */
#endif
+#if defined(MR_LL_PARALLEL_CONJ) && defined(MR_HAVE_HWLOC)
+ #include <hwloc.h>
+#endif
+
#include "mercury_memory_handlers.h"
#include "mercury_context.h"
#include "mercury_engine.h" /* for `MR_memdebug' */
@@ -161,12 +165,19 @@ static MR_Integer MR_profile_paral
/*
** Local variables for thread pinning.
*/
-#ifdef MR_LL_PARALLEL_CONJ
-static MercuryLock MR_next_cpu_lock;
+#if defined(MR_LL_PARALLEL_CONJ) && defined(MR_HAVE_THREAD_PINNING)
MR_bool MR_thread_pinning = MR_FALSE;
-static MR_Unsigned MR_next_cpu = 0;
-/* This is initialised the first the MR_pin_primordial_thread() is called */
+
+static MercuryLock MR_thread_pinning_lock;
+static unsigned MR_num_threads_left_to_pin;
+static unsigned MR_num_processors;
MR_Unsigned MR_primordial_thread_cpu;
+#ifdef MR_HAVE_HWLOC
+static hwloc_topology_t MR_hw_topology;
+static hwloc_cpuset_t MR_hw_available_pus = NULL;
+#else /* MR_HAVE_SCHED_SETAFFINITY */
+static cpu_set_t *MR_available_cpus;
+#endif
#endif
#if defined(MR_LL_PARALLEL_CONJ) && \
@@ -217,7 +228,7 @@ MR_SparkDeque **MR_spark_deque
#ifdef MR_LL_PARALLEL_CONJ
/*
-** Try to wake up a sleeping message and tell it to do action. The engine
+** Try to wake up a sleeping engine and tell it to do action. The engine
** is only woken if the engine is in one of the states in the bitfield states.
** If the engine is woken, this function returns MR_TRUE, otherwise it
** returns MR_FALSE.
@@ -233,9 +244,35 @@ try_wake_engine(MR_EngineId engine_id, i
static void
MR_write_out_profiling_parallel_execution(void);
-#if defined(MR_LL_PARALLEL_CONJ) && defined(MR_HAVE_SCHED_SETAFFINITY)
+#if defined(MR_LL_PARALLEL_CONJ)
static void
+MR_setup_thread_pinning(void);
+
+static MR_bool
MR_do_pin_thread(int cpu);
+
+/*
+** Determine which CPU this thread is currently running on.
+*/
+static int
+MR_current_cpu(void);
+
+/*
+** Reset or initialize the cpuset that tracks which CPUs are available for
+** binding.
+*/
+static void
+MR_reset_available_cpus(void);
+
+/*
+** Mark the given CPU as unavailable for thread pinning. This may mark other
+** CPUs as unavailable, if, for instance they share resources with this
+** processor and we can place other tasks elsewhere to avoid this sharing.
+** These resources are usually only considered for hardware threads that share
+** cores.
+*/
+static void
+MR_make_cpu_unavailable(int cpu);
#endif
/*---------------------------------------------------------------------------*/
@@ -253,9 +290,6 @@ MR_init_context_stuff(void)
pthread_mutex_init(&free_context_list_lock, MR_MUTEX_ATTR);
pthread_mutex_init(&MR_pending_contexts_lock, MR_MUTEX_ATTR);
#ifdef MR_LL_PARALLEL_CONJ
- #ifdef MR_HAVE_SCHED_SETAFFINITY
- pthread_mutex_init(&MR_next_cpu_lock, MR_MUTEX_ATTR);
- #endif
#ifdef MR_DEBUG_RUNTIME_GRANULARITY_CONTROL
pthread_mutex_init(&MR_par_cond_stats_lock, MR_MUTEX_ATTR);
#endif
@@ -268,40 +302,10 @@ MR_init_context_stuff(void)
MR_KEY_CREATE(&MR_backjump_next_choice_id_key, (void *)0);
#endif
- /*
- ** If MR_num_threads is unset, configure it to match number of processors
- ** on the system. If we do this, then we prepare to set processor
- ** affinities later on.
- */
- if (MR_num_threads == 0) {
- #if defined(MR_HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN)
- long result;
-
- result = sysconf(_SC_NPROCESSORS_ONLN);
- if (result < 1) {
- /* We couldn't determine the number of processors. */
- MR_num_threads = 1;
- } else {
- MR_num_threads = result;
- /*
- ** On systems that don't support sched_setaffinity, we don't try
- ** to automatically enable thread pinning. This prevents a runtime
- ** warning that could unnecessarily confuse the user.
- **/
- #if defined(MR_LL_PARALLEL_CONJ) && \
- defined(MR_HAVE_SCHED_SETAFFINITY)
- /*
- ** Comment this back in to enable thread pinning by default
- ** if we autodetected the correct number of CPUs.
- */
- /* MR_thread_pinning = MR_TRUE; */
- #endif
- }
- #else /* ! defined(MR_HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN) */
- MR_num_threads = 1;
- #endif /* ! defined(MR_HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN) */
- }
#ifdef MR_LL_PARALLEL_CONJ
+ #if defined(MR_HAVE_THREAD_PINNING)
+ MR_setup_thread_pinning();
+ #endif
MR_granularity_wsdeque_length =
MR_granularity_wsdeque_length_factor * MR_num_threads;
@@ -329,101 +333,352 @@ MR_init_context_stuff(void)
** Pin the primordial thread first to the CPU it is currently using
** (if support is available for thread pinning).
*/
-#if defined(MR_THREAD_SAFE) && defined(MR_LL_PARALLEL_CONJ)
-unsigned
-MR_pin_primordial_thread(void)
+#if defined(MR_HAVE_THREAD_PINNING) && defined(MR_LL_PARALLEL_CONJ)
+static unsigned
+MR_pin_thread_no_locking(void)
{
unsigned cpu;
- int temp;
+ unsigned i = 0;
+ cpu = MR_current_cpu();
+#ifdef MR_DEBUG_THREAD_PINNING
+ fprintf(stderr, "Currently running on cpu %d\n", cpu);
+#endif
+
+ for (i = 0; i < MR_num_processors && MR_thread_pinning; i++) {
+ if (MR_do_pin_thread((cpu + i) % MR_num_processors)) {
+#ifdef MR_DEBUG_THREAD_PINNING
+ fprintf(stderr, "Pinned to cpu %d\n", (cpu + i) % MR_num_processors);
+ fprintf(stderr, "Now running on cpu %d\n", MR_current_cpu());
+#endif
+ MR_num_threads_left_to_pin--;
+ MR_make_cpu_unavailable((cpu + i) % MR_num_processors);
+ break;
+ }
+ if (!MR_thread_pinning) {
/*
- ** We don't need locking to pin the primordial thread as it is called
- ** before any other threads exist.
- */
- /*
- ** We go through the motions of thread pinning even when thread pinning is
- ** not supported as the allocation of CPUs to threads may be used later.
+ ** If MR_thread_pinning becomes false then an error prevented us
+ ** from pinning the thread.
+ ** When we fail to pin a thread but MR_thread_pinning remains true
+ ** it means that that CPU has already had a thread pinned to it.
*/
- #ifdef MR_HAVE_SCHED_GETCPU
- temp = sched_getcpu();
- if (temp == -1) {
- MR_primordial_thread_cpu = 0;
- #ifdef MR_HAVE_SCHED_SET_AFFINITY
- if (MR_thread_pinning) {
- perror("Warning: unable to determine the current CPU for "
- "the primordial thread: ");
+ fprintf(stderr, "Couldn't pin Mercury engine to processor");
+ break;
}
- #endif
- } else {
- MR_primordial_thread_cpu = temp;
}
- #else
- MR_primordial_thread_cpu = 0;
- #endif
- #ifdef MR_HAVE_SCHED_SET_AFFINITY
- if (MR_thread_pinning) {
- MR_do_pin_thread(MR_primordial_thread_cpu);
- }
- #endif
- return MR_primordial_thread_cpu;
+ return (cpu + 1) % MR_num_processors;
}
-#endif /* defined(MR_THREAD_SAFE) && defined(MR_LL_PARALLEL_CONJ) */
-#if defined(MR_THREAD_SAFE) && defined(MR_LL_PARALLEL_CONJ)
unsigned
MR_pin_thread(void)
{
unsigned cpu;
+ MR_LOCK(&MR_thread_pinning_lock, "MR_pin_thread");
+ cpu = MR_pin_thread_no_locking();
+ MR_UNLOCK(&MR_thread_pinning_lock, "MR_pin_thread");
+
+ return cpu;
+}
+
+void
+MR_pin_primordial_thread(void)
+{
/*
- ** We go through the motions of thread pinning even when thread pinning
- ** is not supported, as the allocation of CPUs to threads may be
- ** used later.
+ ** We don't need locking to pin the primordial thread as it is called
+ ** before any other threads exist.
*/
- MR_LOCK(&MR_next_cpu_lock, "MR_pin_thread");
- if (MR_next_cpu == MR_primordial_thread_cpu) {
+ MR_primordial_thread_cpu = MR_pin_thread_no_locking();
+}
+
+static void MR_setup_thread_pinning(void)
+{
+ unsigned num_processors;
+
+#ifdef MR_HAVE_HWLOC
+ if (-1 == hwloc_topology_init(&MR_hw_topology)) {
+ MR_fatal_error("Error allocating libhwloc topology object");
+ }
+ if (-1 == hwloc_topology_load(MR_hw_topology)) {
+ MR_fatal_error("Error detecting hardware topology (hwloc)");
+ }
+#endif
+
+ /*
+ ** Setup num processors
+ */
+ MR_reset_available_cpus();
+#ifdef MR_HAVE_HWLOC
+ num_processors = hwloc_cpuset_weight(MR_hw_available_pus);
+#elif defined(MR_HAVE_SCHED_GETAFFINITY)
+ /*
+ ** This looks redundant but its not. MR_num_processors is a guess that was
+ ** gathered by using sysconf. But the number of CPUs in the CPU_SET is the
+ ** actual number of CPUs that this process is restricted to.
+ */
+ #if defined(MR_HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN)
+ num_processors = sysconf(_SC_NPROCESSORS_ONLN);
+ #else
+ /*
+ ** The user may have supplied MR_num_processors
+ */
+ num_processors = (MR_num_processors > 1 ? MR_num_processors : 1)
+ #endif
+ num_processors = CPU_COUNT_S(num_processors, MR_available_cpus);
+#endif
+ MR_num_processors = num_processors;
+
/*
- ** Skip the CPU that the primordial thread was pinned on.
+ ** If MR_num_threads is unset, configure it to match number of processors
+ ** on the system. If we do this, then we prepare to set processor
+ ** affinities later on.
*/
- MR_next_cpu++;
+ if (MR_num_threads == 0) {
+ MR_num_threads = num_processors;
}
- cpu = MR_next_cpu++;
- MR_UNLOCK(&MR_next_cpu_lock, "MR_pin_thread");
+ MR_num_threads_left_to_pin = MR_num_threads;
+
+#ifdef MR_DEBUG_THREAD_PINNING
+ fprintf(stderr, "Detected %d available processors, will use %d threads\n",
+ MR_num_processors, MR_num_threads);
+#endif
+
+ pthread_mutex_init(&MR_thread_pinning_lock, MR_MUTEX_ATTR);
+
+ /*
+ ** Comment this back in to enable thread pinning by default
+ ** if we autodetected the number of CPUs without error.
+ */
+#if 0
+ if (MR_num_threads > 1) {
+ MR_thread_pinning = MR_TRUE;
+ }
+#endif
+}
+
+/*
+** Determine which CPU this thread is currently running on.
+*/
+static int MR_current_cpu(void)
+{
+#if defined(MR_HAVE_SCHED_GETCPU)
+ int os_cpu;
+#if defined(MR_HAVE_HWLOC)
+ hwloc_obj_t pu;
+#endif
+
+ os_cpu = sched_getcpu();
+ if (-1 == os_cpu) {
+ os_cpu = 0;
-#ifdef MR_HAVE_SCHED_SETAFFINITY
if (MR_thread_pinning) {
- MR_do_pin_thread(cpu);
+ perror("Warning: unable to determine the current CPU for "
+ "this thread: ");
+ }
}
+
+#if defined(MR_HAVE_HWLOC)
+ pu = hwloc_get_pu_obj_by_os_index(MR_hw_topology, os_cpu);
+ return pu->logical_index;
+#else
+ return os_cpu;
#endif
- return cpu;
+#else /* ! MR_HAVE_SCHED_GETCPU */
+ /* We have no idea! */
+ return 0;
+#endif
}
-#endif /* defined(MR_THREAD_SAFE) && defined(MR_LL_PARALLEL_CONJ) */
-#if defined(MR_LL_PARALLEL_CONJ) && defined(MR_HAVE_SCHED_SETAFFINITY)
-static void
+static MR_bool
MR_do_pin_thread(int cpu)
{
- cpu_set_t cpus;
+ /*
+ ** Make sure that we're allowed to bind to this CPU.
+ */
+#if defined(MR_HAVE_HWLOC)
+ hwloc_obj_t pu;
- if (cpu < CPU_SETSIZE) {
- CPU_ZERO(&cpus);
- CPU_SET(cpu, &cpus);
- if (sched_setaffinity(0, sizeof(cpu_set_t), &cpus) == -1) {
+ if (hwloc_cpuset_iszero(MR_hw_available_pus)) {
+ /*
+ ** Each available CPU already has a thread pinned to it. Reset the
+ ** available_pus set so that we can oversubscribe CPUs but still
+ ** attempt to balance load.
+ */
+ MR_reset_available_cpus();
+ }
+
+ pu = hwloc_get_obj_by_type(MR_hw_topology, HWLOC_OBJ_PU, cpu);
+ if (!hwloc_cpuset_intersects(MR_hw_available_pus, pu->cpuset)) {
+ return MR_FALSE;
+ }
+#elif defined(MR_HAVE_SCHED_SETAFFINITY)
+ if (CPU_COUNT_S(MR_num_processors, MR_available_cpus) == 0) {
+ /*
+ ** As above, reset the available cpus.
+ */
+ MR_reset_available_cpus();
+ }
+ if (!CPU_ISSET_S(cpu, MR_num_processors, MR_available_cpus)) {
+ return MR_FALSE;
+ }
+#endif
+
+#if defined(MR_HAVE_HWLOC)
+ errno = hwloc_set_cpubind(MR_hw_topology, pu->cpuset,
+ HWLOC_CPUBIND_THREAD);
+ if (errno != 0) {
+ perror("Warning: Couldn't set CPU affinity: ");
+ MR_thread_pinning = MR_FALSE;
+ return MR_FALSE;
+ }
+#elif defined(MR_HAVE_SCHED_SETAFFINITY)
+ cpu_set_t *cpus;
+
+ cpus = CPU_ALLOC(MR_num_processors);
+
+ CPU_ZERO_S(MR_num_processors, cpus);
+ CPU_SET_S(cpu, MR_num_processors, cpus);
+ if (sched_setaffinity(0, CPU_ALLOC_SIZE(MR_num_processors), cpus) == -1) {
perror("Warning: Couldn't set CPU affinity: ");
/*
** If this failed once, it will probably fail again,
** so we disable it.
*/
MR_thread_pinning = MR_FALSE;
+ return MR_FALSE;
}
- } else {
- perror("Warning: Couldn't set CPU affinity due to a static "
- "system limit: ");
+#endif
+
+ return MR_TRUE;
+}
+
+static void MR_reset_available_cpus(void)
+{
+#if defined(MR_HAVE_HWLOC)
+ hwloc_cpuset_t inherited_binding;
+
+ /*
+ ** Gather the cpuset that our parent process bound this process to.
+ **
+ ** (For information about how to deliberately restrict a process and it's
+ ** sub-processors to a set of CPUs on Linux see cpuset(7).
+ */
+ inherited_binding = hwloc_cpuset_alloc();
+ hwloc_get_cpubind(MR_hw_topology, inherited_binding, HWLOC_CPUBIND_PROCESS);
+
+ /*
+ ** Set the available processors to the union of inherited_binding and the
+ ** cpuset we're allowed to use as reported by libhwloc. In my tests with
+ ** libhwloc_1.0-1 (Debian) hwloc reported that all cpus on the system are
+ ** avaliable, it didn't exclude cpus not in the processor's cpuset(7).
+ */
+ if (MR_hw_available_pus == NULL) {
+ MR_hw_available_pus = hwloc_cpuset_alloc();
+ }
+ hwloc_cpuset_and(MR_hw_available_pus, inherited_binding,
+ hwloc_topology_get_allowed_cpuset(MR_hw_topology));
+
+ hwloc_cpuset_free(inherited_binding);
+#elif defined(MR_HAVE_SCHED_GETAFFINITY)
+ unsigned num_processors;
+
+ #if defined(MR_HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN)
+ num_processors = sysconf(_SC_NPROCESSORS_ONLN);
+ #else
+ /*
+ ** The user may have supplied MR_num_processors
+ */
+ num_processors = (MR_num_processors > 1 ? MR_num_processors : 1)
+ #endif
+
+ if (MR_available_cpus == NULL) {
+ MR_available_cpus = CPU_ALLOC(num_processors);
+ }
+
+ if (-1 == sched_getaffinity(0, CPU_ALLOC_SIZE(num_processors),
+ MR_available_cpus))
+ {
+ perror("Couldn't get CPU affinity");
MR_thread_pinning = MR_FALSE;
+ CPU_FREE(MR_available_cpus);
+ MR_available_cpus = NULL;
}
+#endif
}
+
+#if defined(MR_HAVE_HWLOC)
+static MR_bool MR_make_pu_unavailable(const struct hwloc_obj *pu);
+#endif
+
+static void MR_make_cpu_unavailable(int cpu)
+{
+#if defined(MR_HAVE_HWLOC)
+ hwloc_obj_t pu;
+ pu = hwloc_get_obj_by_type(MR_hw_topology, HWLOC_OBJ_PU, cpu);
+ MR_make_pu_unavailable(pu);
+#elif defined(MR_HAVE_SCHED_SETAFFINITY)
+ CPU_CLR_S(cpu, MR_num_processors, MR_available_cpus);
#endif
+}
+
+#if defined(MR_HAVE_HWLOC)
+static MR_bool MR_make_pu_unavailable(const struct hwloc_obj *pu) {
+ hwloc_obj_t core;
+ static int siblings_to_make_unavailable;
+ int i;
+
+#ifdef MR_DEBUG_THREAD_PINNING
+ char * cpusetstr;
+
+ hwloc_cpuset_asprintf(&cpusetstr, MR_hw_available_pus);
+ fprintf(stderr, "Old available CPU set: %s\n", cpusetstr);
+ free(cpusetstr);
+ hwloc_cpuset_asprintf(&cpusetstr, pu->cpuset);
+ fprintf(stderr, "Making this CPU set unavailable: %s\n", cpusetstr);
+ free(cpusetstr);
+#endif
+
+ hwloc_cpuset_andnot(MR_hw_available_pus, MR_hw_available_pus, pu->cpuset);
+
+#ifdef MR_DEBUG_THREAD_PINNING
+ hwloc_cpuset_asprintf(&cpusetstr, MR_hw_available_pus);
+ fprintf(stderr, "New available CPU set: %s\n", cpusetstr);
+ free(cpusetstr);
+#endif
+
+ siblings_to_make_unavailable = hwloc_cpuset_weight(MR_hw_available_pus) -
+ MR_num_threads_left_to_pin;
+
+ if (siblings_to_make_unavailable > 0) {
+ /*
+ ** Remove sibling processing units that share a core with the one we've just removed.
+ */
+ core = pu->parent;
+ if (core->type != HWLOC_OBJ_CORE) {
+ return MR_FALSE;
+ }
+
+ for (i = 0;
+ (i < core->arity && siblings_to_make_unavailable > 0);
+ i++) {
+ if (core->children[i] == pu) {
+ continue;
+ }
+ if (hwloc_cpuset_intersects(core->children[i]->cpuset,
+ MR_hw_available_pus)) {
+ if (!MR_make_pu_unavailable(core->children[i])) {
+ return MR_FALSE;
+ }
+ }
+ }
+ }
+
+ return MR_TRUE;
+}
+#endif
+
+#endif /* MR_HAVE_THREAD_PINNING && MR_LL_PARALLEL_CONJ */
void
MR_finalize_context_stuff(void)
Index: runtime/mercury_context.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_context.h,v
retrieving revision 1.69
diff -u -p -b -r1.69 mercury_context.h
--- runtime/mercury_context.h 12 Sep 2011 04:51:17 -0000 1.69
+++ runtime/mercury_context.h 4 Oct 2011 12:19:52 -0000
@@ -468,13 +468,20 @@ extern void MR_init_context_stuf
** be pinned to if pinning was both enabled and supported. That is a valid
** value is always returned even if the thread is not actually pinned.
*/
-#if defined(MR_THREAD_SAFE) && defined(MR_LL_PARALLEL_CONJ)
-extern unsigned
+#if defined(MR_LL_PARALLEL_CONJ)
+#if defined(MR_HAVE_THREAD_PINNING)
+extern void
MR_pin_primordial_thread(void);
extern unsigned
MR_pin_thread(void);
/*
+** The CPU that the primordial thread is running on.
+*/
+extern MR_Unsigned MR_primordial_thread_cpu;
+#endif
+
+/*
** Shutdown all the engines.
*/
extern void
Index: runtime/mercury_thread.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_thread.c,v
retrieving revision 1.49
diff -u -p -b -r1.49 mercury_thread.c
--- runtime/mercury_thread.c 24 May 2011 04:16:48 -0000 1.49
+++ runtime/mercury_thread.c 4 Oct 2011 12:19:52 -0000
@@ -115,7 +115,7 @@ MR_init_thread(MR_when_to_use when_to_us
MercuryEngine *eng;
#ifdef MR_THREAD_SAFE
- #ifdef MR_LL_PARALLEL_CONJ
+ #if defined(MR_LL_PARALLEL_CONJ) && defined(MR_HAVE_THREAD_PINNING)
unsigned cpu;
#endif
@@ -129,13 +129,17 @@ MR_init_thread(MR_when_to_use when_to_us
#ifdef MR_LL_PARALLEL_CONJ
switch (when_to_use) {
case MR_use_later:
+#ifdef MR_HAVE_THREAD_PINNING
cpu = MR_pin_thread();
+#endif
break;
case MR_use_now:
/*
** Don't pin the primordial thread here, it's already been done.
*/
+#ifdef MR_HAVE_THREAD_PINNING
cpu = MR_primordial_thread_cpu;
+#endif
break;
/*
** TODO: We may use the cpu value here to determine which CPUs which
Index: runtime/mercury_thread.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_thread.h,v
retrieving revision 1.34
diff -u -p -b -r1.34 mercury_thread.h
--- runtime/mercury_thread.h 13 Apr 2011 13:19:42 -0000 1.34
+++ runtime/mercury_thread.h 4 Oct 2011 12:19:52 -0000
@@ -211,11 +211,6 @@ MR_null_thread(void);
*/
extern MercuryThreadKey MR_exception_handler_key;
- /*
- ** The CPU that the primordial thread is running on.
- */
- extern MR_Unsigned MR_primordial_thread_cpu;
-
#else /* not MR_THREAD_SAFE */
#define MR_LOCK(nothing, from) do { } while (0)
Index: runtime/mercury_wrapper.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_wrapper.c,v
retrieving revision 1.225
diff -u -p -b -r1.225 mercury_wrapper.c
--- runtime/mercury_wrapper.c 27 Sep 2011 00:49:27 -0000 1.225
+++ runtime/mercury_wrapper.c 4 Oct 2011 12:19:52 -0000
@@ -667,7 +667,9 @@ mercury_runtime_init(int argc, char **ar
#else
#if defined(MR_LL_PARALLEL_CONJ)
+#if defined(MR_HAVE_THREAD_PINNING)
MR_pin_primordial_thread();
+#endif
#if defined(MR_THREADSCOPE)
/*
** We must setup threadscope before we setup the first engine.
Index: scripts/ml.in
===================================================================
RCS file: /home/mercury1/repository/mercury/scripts/ml.in,v
retrieving revision 1.127
diff -u -p -b -r1.127 ml.in
--- scripts/ml.in 3 Oct 2011 16:09:13 -0000 1.127
+++ scripts/ml.in 4 Oct 2011 12:19:52 -0000
@@ -50,6 +50,7 @@ LDFLAGS_FOR_THREADS="@LDFLAGS_FOR_THREAD
LDFLAGS_FOR_TRACE="@LDFLAGS_FOR_TRACE@"
LD_LIBFLAGS_FOR_THREADS="@LD_LIBFLAGS_FOR_THREADS@"
THREAD_LIBS="@THREAD_LIBS@"
+HWLOC_LIBS="@HWLOC_LIBS@"
TRACE_BASE_LIBS_SYSTEM="@TRACE_BASE_LIBS_SYSTEM@"
TMPDIR=${TMPDIR=/tmp}
@@ -370,6 +371,13 @@ case $use_thread_libs.$make_shared_lib i
THREAD_LIBS=""
;;
esac
+case "$GRADE" in
+ hlc.*.par*)
+ ;;
+ *.par*)
+ THREAD_LIBS="$THREAD_LIBS $HWLOC_LIBS"
+ ;;
+esac
# Set the correct flags if we're to use the MS Visual C runtime.
use_msvcrt=@USE_MSVCRT@
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 490 bytes
Desc: Digital signature
URL: <http://lists.mercurylang.org/archives/reviews/attachments/20111005/d217b698/attachment.sig>
More information about the reviews
mailing list