[m-rev.] for review: Add thread.num_processors/3

Paul Bone paul at bone.id.au
Tue May 10 16:23:13 AEST 2016


For review by anyone.  This is actually pretty simple, but people may wish
to review the name of the new predicate.

---

Add thread.num_processors/3

Add a predicate that retrieves the number of processors available to this
process if known.

library/thread.m:
    As above.

runtime/mercury_context.c:
    The existing code that determines the number of processors was only used
    on thread safe low-level C grades.  Make it also available for thread
    safe high-level C grades.

    Add a fall back (less accurate) method of determining the number of
    processors.

    Remove an out-of-date comment.

runtime/mercury_context.h:
    Export the number of available processors.

scripts/ml.in:
    Link to libhwloc (if configured) on thread safe high and low-level C
    grades.

NEWS:
    Announce new predicate.

configure.ac:
    Update a --help message.
---
 NEWS                      |  3 +++
 configure.ac              |  3 +--
 library/thread.m          | 55 +++++++++++++++++++++++++++++++++++++++++++++++
 runtime/mercury_context.c | 31 ++++++++++++++------------
 runtime/mercury_context.h |  5 +++++
 scripts/ml.in             |  6 +++---
 6 files changed, 84 insertions(+), 19 deletions(-)

diff --git a/NEWS b/NEWS
index 9b9f8a5..b1a6648 100644
--- a/NEWS
+++ b/NEWS
@@ -152,6 +152,9 @@ Changes to the Mercury standard library:
 * We have added thread.spawn_native/4 to dedicate an OS thread to a Mercury
   thread. thread.spawn/4 was added as well.
 
+* We have added thread.num_processors/3 which returns the number of
+  processors available for parallel work.
+
 + We have deprecated the impure init/1 function in thread.semaphore.
 
 * In C grades, the math module now provides the fused multiply-add operation
diff --git a/configure.ac b/configure.ac
index 9619319..3a2258b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -5160,8 +5160,7 @@ PKG_PROG_PKG_CONFIG
 
 AC_ARG_WITH([hwloc],
     [AS_HELP_STRING([--without-hwloc],
-        [Do not use libhwloc to detect the processors available in low-level C
-         parallel grades.])],
+        [Do not use libhwloc to detect the processors available.])],
     [],
     [with_hwloc=check])
 
diff --git a/library/thread.m b/library/thread.m
index 0177681..9f1e96f 100644
--- a/library/thread.m
+++ b/library/thread.m
@@ -93,6 +93,21 @@
     %
 :- pred yield(io::di, io::uo) is det.
 
+    % num_processors(Num, !IO)
+    %
+    % Retrieve the number of processors available to this process for
+    % parallel execution, if known.
+    %
+    % Note that the number of available processors can be different from the
+    % actual number of processors/cores:
+    %
+    %  + It includes hardware threads.
+    %  + The Mercury grade may restrict the process to one processor.
+    %  + The OS may be configured to restrict the number of processors
+    %    available (e.g. cpuset(7) on Linux).
+    %
+:- pred num_processors(maybe(int)::out, io::di, io::uo) is det.
+
 %---------------------------------------------------------------------------%
 %---------------------------------------------------------------------------%
 
@@ -709,5 +724,45 @@ public static class RunGoal implements Runnable {
 }").
 
 %---------------------------------------------------------------------------%
+
+num_processors(MaybeProcs, !IO) :-
+    num_processors(Procs, Success, !IO),
+    (
+        Success = yes,
+        MaybeProcs = yes(Procs)
+    ;
+        Success = no,
+        MaybeProcs = no
+    ).
+
+:- pred num_processors(int::out, bool::out, io::di, io::uo) is det.
+
+:- pragma foreign_proc("C",
+    num_processors(Procs::out, Success::out, _IO0::di, _IO::uo),
+    [promise_pure, thread_safe, will_not_call_mercury,
+     will_not_throw_exception, tabled_for_io],
+"
+#ifdef MR_THREAD_SAFE
+    Procs = MR_num_processors;
+    Success = MR_YES;
+#else
+    Procs = 1;
+    Success = MR_YES;
+#endif
+").
+
+:- pragma foreign_proc("Java",
+    num_processors(Procs::out, Success::out, _IO0::di, _IO::uo),
+    [promise_pure, thread_safe, will_not_call_mercury,
+     will_not_throw_exception, tabled_for_io],
+"
+    Procs = Runtime.getRuntime().availableProcessors();
+    Success = bool.YES;
+").
+
+% On other backends se don't know how to determine this yet.
+num_processors(0, no, !IO).
+
+%---------------------------------------------------------------------------%
 :- end_module thread.
 %---------------------------------------------------------------------------%
diff --git a/runtime/mercury_context.c b/runtime/mercury_context.c
index 49dfcd2..3b225d8 100644
--- a/runtime/mercury_context.c
+++ b/runtime/mercury_context.c
@@ -59,7 +59,7 @@ ENDINIT
   #include "mercury_windows.h"
 #endif
 
-#if defined(MR_LL_PARALLEL_CONJ) && defined(MR_HAVE_HWLOC)
+#if defined(MR_THREAD_SAFE) && defined(MR_HAVE_HWLOC)
   #include <hwloc.h>
 #endif
 
@@ -212,19 +212,18 @@ static MR_Integer       MR_profile_parallel_regular_context_kept = 0;
   #endif /* ! MR_HIGHLEVEL_CODE */
 #endif /* MR_PROFILE_PARALLEL_EXECUTION_SUPPORT */
 
+#ifdef MR_THREAD_SAFE
 /*
 ** Detect number of processors.
 */
-#ifdef MR_LL_PARALLEL_CONJ
-static unsigned         MR_num_processors;
-  #if defined(MR_HAVE_HWLOC)
+unsigned         MR_num_processors;
+#if defined(MR_HAVE_HWLOC)
     static hwloc_topology_t MR_hw_topology;
     static hwloc_cpuset_t   MR_hw_available_pus = NULL;
-  #elif defined(MR_HAVE_SCHED_SETAFFINITY)
+#elif defined(MR_HAVE_SCHED_SETAFFINITY)
     static cpu_set_t        *MR_available_cpus;
     /* The number of CPUs that MR_available_cpus can refer to */
     static unsigned         MR_cpuset_size = 0;
-  #endif
 #endif
 
 /*
@@ -236,6 +235,7 @@ static MercuryLock      MR_thread_pinning_lock;
 static unsigned         MR_num_threads_left_to_pin;
 MR_Unsigned             MR_primordial_thread_cpu;
 #endif
+#endif
 
 #if defined(MR_LL_PARALLEL_CONJ) && \
     defined(MR_PROFILE_PARALLEL_EXECUTION_SUPPORT)
@@ -283,7 +283,7 @@ MR_SparkDeque           **MR_spark_deques = NULL;
 
 /*---------------------------------------------------------------------------*/
 
-#ifdef MR_LL_PARALLEL_CONJ
+#ifdef MR_THREAD_SAFE
 /*
 ** Reset or initialize the cpuset that tracks which CPUs are available for
 ** binding.
@@ -294,6 +294,7 @@ MR_reset_available_cpus(void);
 static void
 MR_detect_num_processors(void);
 
+#ifdef MR_LL_PARALLEL_CONJ
 static void
 MR_setup_num_threads(void);
 
@@ -322,6 +323,7 @@ static MR_bool
 try_notify_engine(MR_EngineId engine_id, int action,
     union MR_engine_wake_action_data *action_data, MR_Unsigned engine_state);
 #endif
+#endif
 
 #ifdef MR_PROFILE_PARALLEL_EXECUTION_SUPPORT
 /*
@@ -382,10 +384,10 @@ MR_init_context_stuff(void)
     MR_KEY_CREATE(&MR_backjump_next_choice_id_key, (void *)0);
   #endif
 
-  #ifdef MR_LL_PARALLEL_CONJ
     MR_detect_num_processors();
     assert(MR_num_processors > 0);
 
+  #ifdef MR_LL_PARALLEL_CONJ
     MR_setup_num_threads();
     assert(MR_num_ws_engines > 0);
 
@@ -419,11 +421,11 @@ MR_init_context_stuff(void)
 #endif /* MR_THREAD_SAFE */
 }
 
+#ifdef MR_THREAD_SAFE
 /*
 ** Detect number of processors
 */
 
-#ifdef MR_LL_PARALLEL_CONJ
 static void
 MR_reset_available_cpus(void)
 {
@@ -478,7 +480,9 @@ MR_reset_available_cpus(void)
 
     if (-1 == sched_getaffinity(0, cpuset_size, MR_available_cpus)) {
         MR_perror("Couldn't get CPU affinity");
+      #if defined(MR_LL_PARALLEL_CONJ) && defined(MR_HAVE_THREAD_PINNING)
         MR_thread_pinning = MR_FALSE;
+      #endif
         CPU_FREE(MR_available_cpus);
         MR_available_cpus = NULL;
     }
@@ -504,11 +508,6 @@ MR_detect_num_processors(void)
   #ifdef MR_HAVE_HWLOC
     MR_num_processors = hwloc_bitmap_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.
-    */
     MR_num_processors = CPU_COUNT_S(MR_cpuset_size, MR_available_cpus);
   #elif defined(MR_WIN32_GETSYSTEMINFO)
     {
@@ -516,12 +515,15 @@ MR_detect_num_processors(void)
         GetSystemInfo(&sysinfo);
         MR_num_processors = sysinfo.dwNumberOfProcessors;
     }
+  #elif defined(MR_HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN)
+    MR_num_processors = sysconf(_SC_NPROCESSORS_ONLN);
   #else
     #warning "Cannot detect MR_num_processors"
     MR_num_processors = 1;
   #endif
 }
 
+#ifdef MR_LL_PARALLEL_CONJ
 static void
 MR_setup_num_threads(void)
 {
@@ -542,6 +544,7 @@ MR_setup_num_threads(void)
   #endif
 }
 #endif /* MR_LL_PARALLEL_CONJ */
+#endif /* MR_THREAD_SAFE */
 
 /*
 ** Thread pinning
diff --git a/runtime/mercury_context.h b/runtime/mercury_context.h
index 5503b54..1f5f0ae 100644
--- a/runtime/mercury_context.h
+++ b/runtime/mercury_context.h
@@ -390,6 +390,11 @@ extern MR_bool      MR_profile_parallel_execution;
 extern MR_Stats     MR_profile_parallel_executed_local_sparks;
 #endif
 
+#ifdef MR_THREAD_SAFE
+/* The number of processors available */
+extern unsigned     MR_num_processors;
+#endif
+
 /*
 ** As well as the runqueue, we maintain a linked list of contexts
 ** and associated file descriptors that are suspended blocked for
diff --git a/scripts/ml.in b/scripts/ml.in
index 52103be..03e496a 100644
--- a/scripts/ml.in
+++ b/scripts/ml.in
@@ -387,11 +387,11 @@ case $use_thread_libs.$make_shared_lib in
 		THREAD_LIBS=""
 		;;
 esac
-case "$thread_safe,$highlevel_code,$all_libs" in
-	true,false,static)
+case "$thread_safe,$all_libs" in
+	true,static)
 		THREAD_LIBS="$THREAD_LIBS $HWLOC_STATIC_LIBS"
 		;;
-	true,false,shared)
+	true,shared)
 		THREAD_LIBS="$THREAD_LIBS $HWLOC_LIBS"
 		;;
 esac
-- 
2.8.1



More information about the reviews mailing list