Patchwork [v3] define std::thread::hardware_concurrency()

login
register
mail settings
Submitter Jonathan Wakely
Date May 28, 2011, 12:43 a.m.
Message ID <BANLkTinhSEO0Wh_FBr6=Q_GpebCfVdkiqw@mail.gmail.com>
Download mbox | patch
Permalink /patch/97762/
State New
Headers show

Comments

Jonathan Wakely - May 28, 2011, 12:43 a.m.
This patch uses glibc's get_nprocs() or the non-standard but widely
available _SC_NPROCESSORS_ONLN sysconf variable to determine the
number of processors.

2011-05-28  Jonathan Wakely  <jwakely.gcc@gmail.com>

        * acinclude.m4: Define GLIBCXX_CHECK_GET_NPROCS and
        GLIBCXX_CHECK_SC_NPROCESSORS_ONLN.
        * configure.ac: Use them. Increase minor version.
        * configure: Regenerate.
        * config.h.in: Regenerate.
        * include/std/thread (thread::hardware_concurrency): Remove inline
        definition.
        * src/thread.cc (thread::hardware_concurrency): Define.
        * config/abi/pre/gnu.ver: Export new symbol @3.4.17
        * testsuite/util/testsuite_abi.cc: Add new version.
        * testsuite/lib/libstdc++.exp (check_v3_target_nprocs): Add.
        * testsuite/lib/dg-options.exp (dg-require-nprocs): Add.
        * testsuite/30_threads/thread/members/hardware_concurrency.cc: Use
        dg-require-nprocs and verify hardware_concurrency returns non-zero.


Tested x86_64-linux, I intend to commit to trunk tomorrow.
Jonathan Wakely - May 28, 2011, 5:29 p.m.
On 28 May 2011 01:43, Jonathan Wakely wrote:
> This patch uses glibc's get_nprocs() or the non-standard but widely
> available _SC_NPROCESSORS_ONLN sysconf variable to determine the
> number of processors.
>
> 2011-05-28  Jonathan Wakely  <jwakely.gcc@gmail.com>
>
>        * acinclude.m4: Define GLIBCXX_CHECK_GET_NPROCS and
>        GLIBCXX_CHECK_SC_NPROCESSORS_ONLN.
>        * configure.ac: Use them. Increase minor version.
>        * configure: Regenerate.
>        * config.h.in: Regenerate.
>        * include/std/thread (thread::hardware_concurrency): Remove inline
>        definition.
>        * src/thread.cc (thread::hardware_concurrency): Define.
>        * config/abi/pre/gnu.ver: Export new symbol @3.4.17
>        * testsuite/util/testsuite_abi.cc: Add new version.
>        * testsuite/lib/libstdc++.exp (check_v3_target_nprocs): Add.
>        * testsuite/lib/dg-options.exp (dg-require-nprocs): Add.
>        * testsuite/30_threads/thread/members/hardware_concurrency.cc: Use
>        dg-require-nprocs and verify hardware_concurrency returns non-zero.
>
>
> Tested x86_64-linux, I intend to commit to trunk tomorrow.

I've checked that patch in, so the library version on mainline is
libstdc++.so.6.0.17 now.

If my configury changes or using sysconf breaks anything I'll try to
fix it asap.

Patch

Index: acinclude.m4
===================================================================
--- acinclude.m4	(revision 174307)
+++ acinclude.m4	(working copy)
@@ -3204,6 +3204,61 @@ 
   ])
 ])
 
+dnl
+dnl Check whether get_nprocs is available in <sys/sysinfo.h>, and define _GLIBCXX_USE_GET_NPROCS.
+dnl
+AC_DEFUN([GLIBCXX_CHECK_GET_NPROCS], [
+
+  AC_LANG_SAVE
+  AC_LANG_CPLUSPLUS
+  ac_save_CXXFLAGS="$CXXFLAGS"
+  CXXFLAGS="$CXXFLAGS -fno-exceptions"
+
+  AC_MSG_CHECKING([for get_nprocs])
+  AC_CACHE_VAL(glibcxx_cv_GET_NPROCS, [
+    GCC_TRY_COMPILE_OR_LINK(
+      [#include <sys/sysinfo.h>],
+      [int n = get_nprocs();],
+      [glibcxx_cv_GET_NPROCS=yes],
+      [glibcxx_cv_GET_NPROCS=no])
+  ])
+  if test $glibcxx_cv_GET_NPROCS = yes; then
+    AC_DEFINE(_GLIBCXX_USE_GET_NPROCS, 1, [Define if get_nprocs is available in <sys/sysinfo.h>.])
+  fi
+  AC_MSG_RESULT($glibcxx_cv_GET_NPROCS)
+
+  CXXFLAGS="$ac_save_CXXFLAGS"
+  AC_LANG_RESTORE
+])
+
+dnl
+dnl Check whether sysconf is available in <unistd.h>, and define _GLIBCXX_USE_SYSCONF.
+dnl
+AC_DEFUN([GLIBCXX_CHECK_SYSCONF], [
+
+  AC_LANG_SAVE
+  AC_LANG_CPLUSPLUS
+  ac_save_CXXFLAGS="$CXXFLAGS"
+  CXXFLAGS="$CXXFLAGS -fno-exceptions"
+
+  AC_MSG_CHECKING([for sysconf])
+  AC_CACHE_VAL(glibcxx_cv_SYSCONF, [
+    GCC_TRY_COMPILE_OR_LINK(
+      [#include <unistd.h>],
+      [int n = sysconf(_SC_ARG_MAX);],
+      [glibcxx_cv_SYSCONF=yes],
+      [glibcxx_cv_SYSCONF=no])
+  ])
+  if test $glibcxx_cv_SYSCONF = yes; then
+    AC_DEFINE(_GLIBCXX_USE_SYSCONF, 1, [Define if sysconf is available in <unistd.h>.])
+  fi
+  AC_MSG_RESULT($glibcxx_cv_SYSCONF)
+
+  CXXFLAGS="$ac_save_CXXFLAGS"
+  AC_LANG_RESTORE
+])
+
+
 # Macros from the top-level gcc directory.
 m4_include([../config/gc++filt.m4])
 m4_include([../config/tls.m4])
Index: configure.ac
===================================================================
--- configure.ac	(revision 174307)
+++ configure.ac	(working copy)
@@ -12,7 +12,7 @@ 
 ### am handles this now?  ORIGINAL_LD_FOR_MULTILIBS=$LD
 
 # For libtool versioning info, format is CURRENT:REVISION:AGE
-libtool_VERSION=6:16:0
+libtool_VERSION=6:17:0
 AC_SUBST(libtool_VERSION)
 
 # Find the rest of the source tree framework.
@@ -170,6 +170,10 @@ 
 
 AC_LC_MESSAGES
 
+# For hardware_concurrency
+GLIBCXX_CHECK_GET_NPROCS
+GLIBCXX_CHECK_SYSCONF
+
 # Check for available headers.
 AC_CHECK_HEADERS([endian.h execinfo.h float.h fp.h ieeefp.h inttypes.h \
 locale.h machine/endian.h machine/param.h nan.h stdint.h stdlib.h string.h \
Index: include/std/thread
===================================================================
--- include/std/thread	(revision 174307)
+++ include/std/thread	(working copy)
@@ -179,8 +179,7 @@ 
 
     // Returns a value that hints at the number of hardware thread contexts.
     static unsigned int
-    hardware_concurrency() noexcept
-    { return 0; }
+    hardware_concurrency() noexcept;
 
   private:
     void
Index: src/thread.cc
===================================================================
--- src/thread.cc	(revision 174307)
+++ src/thread.cc	(working copy)
@@ -26,6 +26,16 @@ 
 #include <thread>
 #include <cerrno>
 
+#if defined(_GLIBCXX_USE_GET_NPROCS)
+# include <sys/sysinfo.h>
+# define _GLIBCXX_NPROCS get_nprocs()
+#elif defined(_GLIBCXX_USE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN)
+# include <unistd.h>
+# define _GLIBCXX_NPROCS sysconf(_SC_NPROCESSORS_ONLN)
+#else
+# define _GLIBCXX_NPROCS 0
+#endif
+
 #if defined(_GLIBCXX_HAS_GTHREADS) && defined(_GLIBCXX_USE_C99_STDINT_TR1)
 
 namespace std _GLIBCXX_VISIBILITY(default)
@@ -98,6 +108,15 @@ 
     }
   }
 
+  unsigned int
+  thread::hardware_concurrency() noexcept
+  {
+    int __n = _GLIBCXX_NPROCS;
+    if (__n < 0)
+      __n = 0;
+    return __n;
+  }
+
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 
Index: config/abi/pre/gnu.ver
===================================================================
--- config/abi/pre/gnu.ver	(revision 174307)
+++ config/abi/pre/gnu.ver	(working copy)
@@ -1279,6 +1279,13 @@ 
 
 } GLIBCXX_3.4.15;
 
+GLIBCXX_3.4.17 {
+
+    # std::thread::hardware_concurrency
+    _ZNSt6thread20hardware_concurrencyEv;
+
+} GLIBCXX_3.4.16;
+
 # Symbols in the support library (libsupc++) have their own tag.
 CXXABI_1.3 {
 
Index: testsuite/lib/libstdc++.exp
===================================================================
--- testsuite/lib/libstdc++.exp	(revision 174307)
+++ testsuite/lib/libstdc++.exp	(working copy)
@@ -1579,4 +1579,67 @@ 
     return $et_binary_io
 }
 
+proc check_v3_target_nprocs { } {
+    global cxxflags
+    global DEFAULT_CXXFLAGS
+    global et_nprocs
+
+    global tool
+
+    if { ![info exists et_nprocs_target_name] } {
+	set et_nprocs_target_name ""
+    }
+
+    # If the target has changed since we set the cached value, clear it.
+    set current_target [current_target_name]
+    if { $current_target != $et_nprocs_target_name } {
+	verbose "check_v3_target_nprocs: `$et_nprocs_target_name'" 2
+	set et_nprocs_target_name $current_target
+	if [info exists et_nprocs] {
+	    verbose "check_v3_target_nprocs: removing cached result" 2
+	    unset et_nprocs
+	}
+    }
+
+    if [info exists et_nprocs] {
+	verbose "check_v3_target_nprocs: using cached result" 2
+    } else {
+	set et_nprocs 0
+
+	# Set up and preprocess a C++0x test program that depends
+	# on either get_nprocs or sysconf to be available.
+	set src nprocs[pid].cc
+
+	set f [open $src "w"]
+        puts $f "#include <bits/c++config.h>"
+	puts $f "#if defined(_GLIBCXX_USE_GET_NPROCS)"
+	puts $f "#elif defined(_GLIBCXX_USE_SYSCONF)"
+        puts $f "# include <unistd.h>"
+	puts $f "# if !defined(_SC_NPROCESSORS_ONLN)"
+	puts $f "#  error No sysconf option"
+	puts $f "# endif"
+	puts $f "#else"
+	puts $f "#  error No get_nprocs or sysconf"
+	puts $f "#endif"
+	close $f
+
+	set cxxflags_saved $cxxflags
+	set cxxflags "$cxxflags $DEFAULT_CXXFLAGS -Werror"
+
+	set lines [v3_target_compile $src /dev/null preprocess ""]
+	set cxxflags $cxxflags_saved
+	file delete $src
+
+	if [string match "" $lines] {
+	    # No error message, preprocess succeeded.
+	    set et_nprocs 1
+	} else {
+	    verbose "check_v3_target_nprocs: compilation failed" 2
+	}
+    }
+    verbose "check_v3_target_nprocs: $et_nprocs" 2
+    return $et_nprocs
+}
+
+
 set additional_prunes ""
Index: testsuite/lib/dg-options.exp
===================================================================
--- testsuite/lib/dg-options.exp	(revision 174307)
+++ testsuite/lib/dg-options.exp	(working copy)
@@ -179,6 +179,15 @@ 
     return
 }
 
+proc dg-require-nprocs { args } {
+    if { ![ check_v3_target_nprocs ] } {
+        upvar dg-do-what dg-do-what
+        set dg-do-what [list [lindex ${dg-do-what} 0] "N" "P"]
+        return
+    }
+    return
+}
+
 proc add_options_for_no_pch { flags } {
     # This forces any generated and possibly included PCH to be invalid.
     return "-D__GLIBCXX__=99999999"
Index: testsuite/util/testsuite_abi.cc
===================================================================
--- testsuite/util/testsuite_abi.cc	(revision 174307)
+++ testsuite/util/testsuite_abi.cc	(working copy)
@@ -194,6 +194,7 @@ 
       known_versions.push_back("GLIBCXX_3.4.14");
       known_versions.push_back("GLIBCXX_3.4.15");
       known_versions.push_back("GLIBCXX_3.4.16");
+      known_versions.push_back("GLIBCXX_3.4.17");
       known_versions.push_back("GLIBCXX_LDBL_3.4");
       known_versions.push_back("GLIBCXX_LDBL_3.4.7");
       known_versions.push_back("GLIBCXX_LDBL_3.4.10");
Index: testsuite/30_threads/thread/members/hardware_concurrency.cc
===================================================================
--- testsuite/30_threads/thread/members/hardware_concurrency.cc	(revision 174307)
+++ testsuite/30_threads/thread/members/hardware_concurrency.cc	(working copy)
@@ -4,8 +4,9 @@ 
 // { dg-options " -std=gnu++0x " { target *-*-cygwin *-*-darwin* } }
 // { dg-require-cstdint "" }
 // { dg-require-gthreads "" }
+// { dg-require-nprocs "" }
 
-// Copyright (C) 2009 Free Software Foundation, Inc.
+// Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
 //
 // This file is part of the GNU ISO C++ Library.  This library is free
 // software; you can redistribute it and/or modify it under the
@@ -29,8 +30,7 @@ 
 {
   bool test __attribute__((unused)) = true;
 
-  // Current implementation punts on this.
-  VERIFY( std::thread::hardware_concurrency() == 0 );
+  VERIFY( std::thread::hardware_concurrency() >= 1 );
 
   return 0;
 }