summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog10
-rw-r--r--configure.in1
-rw-r--r--ext/etc/etc.c72
3 files changed, 83 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index 7a6bb08cc6..80925f5867 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+Wed Oct 15 18:26:19 2014 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * ext/etc/etc.c (etc_nprocessors_affinity): use sched_getaffinity
+ for getting precious number of available cpus.
+
+ * ext/etc/etc.c (etc_nprocessors): use etc_nprocessors_affinity if
+ possible.
+
+ [Feature #10267] etc-nprocessors-kosaki2.patch
+
Wed Oct 15 17:53:28 2014 Tanaka Akira <akr@fsij.org>
* test/ruby/envutil.rb (assert_pattern_list) Renamed from
diff --git a/configure.in b/configure.in
index 4cc8afaea6..9ebe009489 100644
--- a/configure.in
+++ b/configure.in
@@ -2052,6 +2052,7 @@ AC_CHECK_FUNCS(pread)
AC_CHECK_FUNCS(qsort_r)
AC_CHECK_FUNCS(readlink)
AC_CHECK_FUNCS(round)
+AC_CHECK_FUNCS(sched_getaffinity)
AC_CHECK_FUNCS(seekdir)
AC_CHECK_FUNCS(select_large_fdset)
AC_CHECK_FUNCS(sendfile)
diff --git a/ext/etc/etc.c b/ext/etc/etc.c
index 94b9cc34f0..aaa5025a9c 100644
--- a/ext/etc/etc.c
+++ b/ext/etc/etc.c
@@ -30,6 +30,10 @@
#include <sys/utsname.h>
#endif
+#ifdef HAVE_SCHED_GETAFFINITY
+#include <sched.h>
+#endif
+
static VALUE sPasswd;
#ifdef HAVE_GETGRENT
static VALUE sGroup;
@@ -904,6 +908,54 @@ io_pathconf(VALUE io, VALUE arg)
#endif
#if (defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN)) || defined(_WIN32)
+
+#ifdef HAVE_SCHED_GETAFFINITY
+static int
+etc_nprocessors_affin(void)
+{
+ cpu_set_t *cpuset;
+ size_t size;
+ int ret;
+ int ncpus;
+
+ /*
+ * XXX:
+ * man page says CPU_ALLOC takes number of cpus. But it is not accurate
+ * explanation. sched_getaffinity() returns EINVAL if cpuset bitmap is
+ * smaller than kernel internal bitmap.
+ * That said, sched_getaffinity() can fail when a kernel have sparse bitmap
+ * even if cpuset bitmap is larger than number of cpus.
+ * The precious way is to use /sys/devices/system/cpu/online. But there are
+ * two problems,
+ * - Costly calculation
+ * It is minor issue, but possibly kill the benefit of parallel processing.
+ * - No guarantee to exist /sys/devices/system/cpu/online
+ * This is an issue especially when using containers.
+ * So, we use hardcode number for workaround. Current linux kernel
+ * (Linux 3.17) support 8192 cpus at maximum. Then 16384 is enough large.
+ */
+ ncpus = 16384;
+
+ cpuset = CPU_ALLOC(ncpus);
+ if (!cpuset) {
+ return -1;
+ }
+ size = CPU_ALLOC_SIZE(ncpus);
+ CPU_ZERO_S(size, cpuset);
+
+ ret = sched_getaffinity(0, size, cpuset);
+ if (ret==-1) {
+ goto free;
+ }
+
+ ret = CPU_COUNT_S(size, cpuset);
+ free:
+ CPU_FREE(cpuset);
+
+ return ret;
+}
+#endif
+
/*
* Returns the number of online processors.
*
@@ -912,12 +964,21 @@ io_pathconf(VALUE io, VALUE arg)
*
* This method is implemented as:
* - sysconf(_SC_NPROCESSORS_ONLN): GNU/Linux, NetBSD, FreeBSD, OpenBSD, DragonFly BSD, OpenIndiana, Mac OS X, AIX
+ * - sched_getaffinity(): Linux
*
* Example:
*
* require 'etc'
* p Etc.nprocessors #=> 4
*
+ * The result might be smaller number than physical cpus especially when ruby
+ * process is bound to specific cpus. This is intended for getting better
+ * parallel processing.
+ *
+ * Example: (Linux)
+ *
+ * $ taskset 0x3 ./ruby -retc -e "p Etc.nprocessors" #=> 2
+ *
*/
static VALUE
etc_nprocessors(VALUE obj)
@@ -925,6 +986,17 @@ etc_nprocessors(VALUE obj)
long ret;
#if !defined(_WIN32)
+
+#ifdef HAVE_SCHED_GETAFFINITY
+ int ncpus;
+
+ ncpus = etc_nprocessors_affin();
+ if (ncpus != -1) {
+ return INT2NUM(ncpus);
+ }
+ /* fallback to _SC_NPROCESSORS_ONLN */
+#endif
+
errno = 0;
ret = sysconf(_SC_NPROCESSORS_ONLN);
if (ret == -1) {