New function num-processors
This addresses a FIXME comment in lisp/emacs-lisp/comp.el, relating to the number of subsidiary processes used by comp-run-async-workers in native compilation. * admin/merge-gnulib (GNULIB_MODULES): Add nproc. * doc/lispref/processes.texi (Process Information), etc/NEWS: Document num-processors. * lib/gnulib.mk.in, m4/gnulib-comp.m4: Regenerate. * lib/nproc.c, lib/nproc.h, m4/nproc.m4: New files, copied from Gnulib by admin/merge-gnulib. * lisp/emacs-lisp/comp.el (w32-get-nproc): Remove decl. (comp-effective-async-max-jobs): Use num-processors. * src/process.c: Include nproc.h. (Fnum_processors): New function. (syms_of_process): Define ‘all’, ‘current’, ‘num-processors’. * src/w32proc.c (Fw32_get_nproc): Add FIXME comment. * test/src/process-tests.el (process-num-processors): New test.
This commit is contained in:
parent
575e626105
commit
96278de8ac
12 changed files with 564 additions and 15 deletions
|
@ -39,7 +39,8 @@ GNULIB_MODULES='
|
||||||
free-posix fstatat fsusage fsync futimens
|
free-posix fstatat fsusage fsync futimens
|
||||||
getloadavg getopt-gnu getrandom gettime gettimeofday gitlog-to-changelog
|
getloadavg getopt-gnu getrandom gettime gettimeofday gitlog-to-changelog
|
||||||
ieee754-h ignore-value intprops largefile libgmp lstat
|
ieee754-h ignore-value intprops largefile libgmp lstat
|
||||||
manywarnings memmem-simple mempcpy memrchr minmax mkostemp mktime nstrftime
|
manywarnings memmem-simple mempcpy memrchr minmax mkostemp mktime
|
||||||
|
nproc nstrftime
|
||||||
pathmax pipe2 pselect pthread_sigmask
|
pathmax pipe2 pselect pthread_sigmask
|
||||||
qcopy-acl readlink readlinkat regex
|
qcopy-acl readlink readlinkat regex
|
||||||
sig2str sigdescr_np socklen stat-time std-gnu11 stdalign stddef stdio
|
sig2str sigdescr_np socklen stat-time std-gnu11 stdalign stddef stdio
|
||||||
|
|
|
@ -1047,6 +1047,19 @@ This function returns a list of all processes that have not been deleted.
|
||||||
@end smallexample
|
@end smallexample
|
||||||
@end defun
|
@end defun
|
||||||
|
|
||||||
|
@defun num-processors &optional query
|
||||||
|
This function returns the number of processors, a positive integer.
|
||||||
|
Each usable thread execution unit counts as a processor.
|
||||||
|
By default, the count includes the number of available processors,
|
||||||
|
which you can override by setting the
|
||||||
|
@url{https://www.openmp.org/spec-html/5.1/openmpse59.html,
|
||||||
|
@env{OMP_NUM_THREADS} environment variable of OpenMP}.
|
||||||
|
If the optional argument @var{query} is @code{current},
|
||||||
|
this function ignores @env{OMP_NUM_THREADS};
|
||||||
|
if @var{query} is @code{all}, this function also counts processors
|
||||||
|
that are on the system but are not available to the current process.
|
||||||
|
@end defun
|
||||||
|
|
||||||
@defun get-process name
|
@defun get-process name
|
||||||
This function returns the process named @var{name} (a string), or
|
This function returns the process named @var{name} (a string), or
|
||||||
@code{nil} if there is none. The argument @var{name} can also be a
|
@code{nil} if there is none. The argument @var{name} can also be a
|
||||||
|
|
4
etc/NEWS
4
etc/NEWS
|
@ -4094,6 +4094,10 @@ Parse a string as a mail address-like string.
|
||||||
** New function 'make-separator-line'.
|
** New function 'make-separator-line'.
|
||||||
Make a string appropriate for usage as a visual separator line.
|
Make a string appropriate for usage as a visual separator line.
|
||||||
|
|
||||||
|
+++
|
||||||
|
** New function 'num-processors'.
|
||||||
|
Return the number of processors on the system.
|
||||||
|
|
||||||
+++
|
+++
|
||||||
** New function 'object-intervals'.
|
** New function 'object-intervals'.
|
||||||
This function returns a copy of the list of intervals (i.e., text
|
This function returns a copy of the list of intervals (i.e., text
|
||||||
|
|
|
@ -129,6 +129,7 @@
|
||||||
# minmax \
|
# minmax \
|
||||||
# mkostemp \
|
# mkostemp \
|
||||||
# mktime \
|
# mktime \
|
||||||
|
# nproc \
|
||||||
# nstrftime \
|
# nstrftime \
|
||||||
# pathmax \
|
# pathmax \
|
||||||
# pipe2 \
|
# pipe2 \
|
||||||
|
@ -2378,6 +2379,16 @@ EXTRA_libgnu_a_SOURCES += mktime.c
|
||||||
endif
|
endif
|
||||||
## end gnulib module mktime-internal
|
## end gnulib module mktime-internal
|
||||||
|
|
||||||
|
## begin gnulib module nproc
|
||||||
|
ifeq (,$(OMIT_GNULIB_MODULE_nproc))
|
||||||
|
|
||||||
|
libgnu_a_SOURCES += nproc.c
|
||||||
|
|
||||||
|
EXTRA_DIST += nproc.h
|
||||||
|
|
||||||
|
endif
|
||||||
|
## end gnulib module nproc
|
||||||
|
|
||||||
## begin gnulib module nstrftime
|
## begin gnulib module nstrftime
|
||||||
ifeq (,$(OMIT_GNULIB_MODULE_nstrftime))
|
ifeq (,$(OMIT_GNULIB_MODULE_nstrftime))
|
||||||
|
|
||||||
|
|
403
lib/nproc.c
Normal file
403
lib/nproc.c
Normal file
|
@ -0,0 +1,403 @@
|
||||||
|
/* Detect the number of processors.
|
||||||
|
|
||||||
|
Copyright (C) 2009-2021 Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
This file is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as
|
||||||
|
published by the Free Software Foundation; either version 2.1 of the
|
||||||
|
License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This file is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
/* Written by Glen Lenker and Bruno Haible. */
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
#include "nproc.h"
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#if HAVE_PTHREAD_GETAFFINITY_NP && 0
|
||||||
|
# include <pthread.h>
|
||||||
|
# include <sched.h>
|
||||||
|
#endif
|
||||||
|
#if HAVE_SCHED_GETAFFINITY_LIKE_GLIBC || HAVE_SCHED_GETAFFINITY_NP
|
||||||
|
# include <sched.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#if HAVE_SYS_PSTAT_H
|
||||||
|
# include <sys/pstat.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if HAVE_SYS_SYSMP_H
|
||||||
|
# include <sys/sysmp.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if HAVE_SYS_PARAM_H
|
||||||
|
# include <sys/param.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if HAVE_SYS_SYSCTL_H && ! defined __GLIBC__
|
||||||
|
# include <sys/sysctl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined _WIN32 && ! defined __CYGWIN__
|
||||||
|
# define WIN32_LEAN_AND_MEAN
|
||||||
|
# include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "c-ctype.h"
|
||||||
|
|
||||||
|
#include "minmax.h"
|
||||||
|
|
||||||
|
#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
|
||||||
|
|
||||||
|
/* Return the number of processors available to the current process, based
|
||||||
|
on a modern system call that returns the "affinity" between the current
|
||||||
|
process and each CPU. Return 0 if unknown or if such a system call does
|
||||||
|
not exist. */
|
||||||
|
static unsigned long
|
||||||
|
num_processors_via_affinity_mask (void)
|
||||||
|
{
|
||||||
|
/* glibc >= 2.3.3 with NPTL and NetBSD 5 have pthread_getaffinity_np,
|
||||||
|
but with different APIs. Also it requires linking with -lpthread.
|
||||||
|
Therefore this code is not enabled.
|
||||||
|
glibc >= 2.3.4 has sched_getaffinity whereas NetBSD 5 has
|
||||||
|
sched_getaffinity_np. */
|
||||||
|
#if HAVE_PTHREAD_GETAFFINITY_NP && defined __GLIBC__ && 0
|
||||||
|
{
|
||||||
|
cpu_set_t set;
|
||||||
|
|
||||||
|
if (pthread_getaffinity_np (pthread_self (), sizeof (set), &set) == 0)
|
||||||
|
{
|
||||||
|
unsigned long count;
|
||||||
|
|
||||||
|
# ifdef CPU_COUNT
|
||||||
|
/* glibc >= 2.6 has the CPU_COUNT macro. */
|
||||||
|
count = CPU_COUNT (&set);
|
||||||
|
# else
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
count = 0;
|
||||||
|
for (i = 0; i < CPU_SETSIZE; i++)
|
||||||
|
if (CPU_ISSET (i, &set))
|
||||||
|
count++;
|
||||||
|
# endif
|
||||||
|
if (count > 0)
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#elif HAVE_PTHREAD_GETAFFINITY_NP && defined __NetBSD__ && 0
|
||||||
|
{
|
||||||
|
cpuset_t *set;
|
||||||
|
|
||||||
|
set = cpuset_create ();
|
||||||
|
if (set != NULL)
|
||||||
|
{
|
||||||
|
unsigned long count = 0;
|
||||||
|
|
||||||
|
if (pthread_getaffinity_np (pthread_self (), cpuset_size (set), set)
|
||||||
|
== 0)
|
||||||
|
{
|
||||||
|
cpuid_t i;
|
||||||
|
|
||||||
|
for (i = 0;; i++)
|
||||||
|
{
|
||||||
|
int ret = cpuset_isset (i, set);
|
||||||
|
if (ret < 0)
|
||||||
|
break;
|
||||||
|
if (ret > 0)
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cpuset_destroy (set);
|
||||||
|
if (count > 0)
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#elif HAVE_SCHED_GETAFFINITY_LIKE_GLIBC /* glibc >= 2.3.4 */
|
||||||
|
{
|
||||||
|
cpu_set_t set;
|
||||||
|
|
||||||
|
if (sched_getaffinity (0, sizeof (set), &set) == 0)
|
||||||
|
{
|
||||||
|
unsigned long count;
|
||||||
|
|
||||||
|
# ifdef CPU_COUNT
|
||||||
|
/* glibc >= 2.6 has the CPU_COUNT macro. */
|
||||||
|
count = CPU_COUNT (&set);
|
||||||
|
# else
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
count = 0;
|
||||||
|
for (i = 0; i < CPU_SETSIZE; i++)
|
||||||
|
if (CPU_ISSET (i, &set))
|
||||||
|
count++;
|
||||||
|
# endif
|
||||||
|
if (count > 0)
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#elif HAVE_SCHED_GETAFFINITY_NP /* NetBSD >= 5 */
|
||||||
|
{
|
||||||
|
cpuset_t *set;
|
||||||
|
|
||||||
|
set = cpuset_create ();
|
||||||
|
if (set != NULL)
|
||||||
|
{
|
||||||
|
unsigned long count = 0;
|
||||||
|
|
||||||
|
if (sched_getaffinity_np (getpid (), cpuset_size (set), set) == 0)
|
||||||
|
{
|
||||||
|
cpuid_t i;
|
||||||
|
|
||||||
|
for (i = 0;; i++)
|
||||||
|
{
|
||||||
|
int ret = cpuset_isset (i, set);
|
||||||
|
if (ret < 0)
|
||||||
|
break;
|
||||||
|
if (ret > 0)
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cpuset_destroy (set);
|
||||||
|
if (count > 0)
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined _WIN32 && ! defined __CYGWIN__
|
||||||
|
{ /* This works on native Windows platforms. */
|
||||||
|
DWORD_PTR process_mask;
|
||||||
|
DWORD_PTR system_mask;
|
||||||
|
|
||||||
|
if (GetProcessAffinityMask (GetCurrentProcess (),
|
||||||
|
&process_mask, &system_mask))
|
||||||
|
{
|
||||||
|
DWORD_PTR mask = process_mask;
|
||||||
|
unsigned long count = 0;
|
||||||
|
|
||||||
|
for (; mask != 0; mask = mask >> 1)
|
||||||
|
if (mask & 1)
|
||||||
|
count++;
|
||||||
|
if (count > 0)
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return the total number of processors. Here QUERY must be one of
|
||||||
|
NPROC_ALL, NPROC_CURRENT. The result is guaranteed to be at least 1. */
|
||||||
|
static unsigned long int
|
||||||
|
num_processors_ignoring_omp (enum nproc_query query)
|
||||||
|
{
|
||||||
|
/* On systems with a modern affinity mask system call, we have
|
||||||
|
sysconf (_SC_NPROCESSORS_CONF)
|
||||||
|
>= sysconf (_SC_NPROCESSORS_ONLN)
|
||||||
|
>= num_processors_via_affinity_mask ()
|
||||||
|
The first number is the number of CPUs configured in the system.
|
||||||
|
The second number is the number of CPUs available to the scheduler.
|
||||||
|
The third number is the number of CPUs available to the current process.
|
||||||
|
|
||||||
|
Note! On Linux systems with glibc, the first and second number come from
|
||||||
|
the /sys and /proc file systems (see
|
||||||
|
glibc/sysdeps/unix/sysv/linux/getsysstats.c).
|
||||||
|
In some situations these file systems are not mounted, and the sysconf call
|
||||||
|
returns 1 or 2 (<https://sourceware.org/bugzilla/show_bug.cgi?id=21542>),
|
||||||
|
which does not reflect the reality. */
|
||||||
|
|
||||||
|
if (query == NPROC_CURRENT)
|
||||||
|
{
|
||||||
|
/* Try the modern affinity mask system call. */
|
||||||
|
{
|
||||||
|
unsigned long nprocs = num_processors_via_affinity_mask ();
|
||||||
|
|
||||||
|
if (nprocs > 0)
|
||||||
|
return nprocs;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined _SC_NPROCESSORS_ONLN
|
||||||
|
{ /* This works on glibc, Mac OS X 10.5, FreeBSD, AIX, OSF/1, Solaris,
|
||||||
|
Cygwin, Haiku. */
|
||||||
|
long int nprocs = sysconf (_SC_NPROCESSORS_ONLN);
|
||||||
|
if (nprocs > 0)
|
||||||
|
return nprocs;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else /* query == NPROC_ALL */
|
||||||
|
{
|
||||||
|
#if defined _SC_NPROCESSORS_CONF
|
||||||
|
{ /* This works on glibc, Mac OS X 10.5, FreeBSD, AIX, OSF/1, Solaris,
|
||||||
|
Cygwin, Haiku. */
|
||||||
|
long int nprocs = sysconf (_SC_NPROCESSORS_CONF);
|
||||||
|
|
||||||
|
# if __GLIBC__ >= 2 && defined __linux__
|
||||||
|
/* On Linux systems with glibc, this information comes from the /sys and
|
||||||
|
/proc file systems (see glibc/sysdeps/unix/sysv/linux/getsysstats.c).
|
||||||
|
In some situations these file systems are not mounted, and the
|
||||||
|
sysconf call returns 1 or 2. But we wish to guarantee that
|
||||||
|
num_processors (NPROC_ALL) >= num_processors (NPROC_CURRENT). */
|
||||||
|
if (nprocs == 1 || nprocs == 2)
|
||||||
|
{
|
||||||
|
unsigned long nprocs_current = num_processors_via_affinity_mask ();
|
||||||
|
|
||||||
|
if (/* nprocs_current > 0 && */ nprocs_current > nprocs)
|
||||||
|
nprocs = nprocs_current;
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
|
||||||
|
if (nprocs > 0)
|
||||||
|
return nprocs;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if HAVE_PSTAT_GETDYNAMIC
|
||||||
|
{ /* This works on HP-UX. */
|
||||||
|
struct pst_dynamic psd;
|
||||||
|
if (pstat_getdynamic (&psd, sizeof psd, 1, 0) >= 0)
|
||||||
|
{
|
||||||
|
/* The field psd_proc_cnt contains the number of active processors.
|
||||||
|
In newer releases of HP-UX 11, the field psd_max_proc_cnt includes
|
||||||
|
deactivated processors. */
|
||||||
|
if (query == NPROC_CURRENT)
|
||||||
|
{
|
||||||
|
if (psd.psd_proc_cnt > 0)
|
||||||
|
return psd.psd_proc_cnt;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (psd.psd_max_proc_cnt > 0)
|
||||||
|
return psd.psd_max_proc_cnt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if HAVE_SYSMP && defined MP_NAPROCS && defined MP_NPROCS
|
||||||
|
{ /* This works on IRIX. */
|
||||||
|
/* MP_NPROCS yields the number of installed processors.
|
||||||
|
MP_NAPROCS yields the number of processors available to unprivileged
|
||||||
|
processes. */
|
||||||
|
int nprocs =
|
||||||
|
sysmp (query == NPROC_CURRENT && getuid () != 0
|
||||||
|
? MP_NAPROCS
|
||||||
|
: MP_NPROCS);
|
||||||
|
if (nprocs > 0)
|
||||||
|
return nprocs;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Finally, as fallback, use the APIs that don't distinguish between
|
||||||
|
NPROC_CURRENT and NPROC_ALL. */
|
||||||
|
|
||||||
|
#if HAVE_SYSCTL && ! defined __GLIBC__ && defined HW_NCPU
|
||||||
|
{ /* This works on Mac OS X, FreeBSD, NetBSD, OpenBSD. */
|
||||||
|
int nprocs;
|
||||||
|
size_t len = sizeof (nprocs);
|
||||||
|
static int const mib[][2] = {
|
||||||
|
# ifdef HW_NCPUONLINE
|
||||||
|
{ CTL_HW, HW_NCPUONLINE },
|
||||||
|
# endif
|
||||||
|
{ CTL_HW, HW_NCPU }
|
||||||
|
};
|
||||||
|
for (int i = 0; i < ARRAY_SIZE (mib); i++)
|
||||||
|
{
|
||||||
|
if (sysctl (mib[i], ARRAY_SIZE (mib[i]), &nprocs, &len, NULL, 0) == 0
|
||||||
|
&& len == sizeof (nprocs)
|
||||||
|
&& 0 < nprocs)
|
||||||
|
return nprocs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined _WIN32 && ! defined __CYGWIN__
|
||||||
|
{ /* This works on native Windows platforms. */
|
||||||
|
SYSTEM_INFO system_info;
|
||||||
|
GetSystemInfo (&system_info);
|
||||||
|
if (0 < system_info.dwNumberOfProcessors)
|
||||||
|
return system_info.dwNumberOfProcessors;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse OMP environment variables without dependence on OMP.
|
||||||
|
Return 0 for invalid values. */
|
||||||
|
static unsigned long int
|
||||||
|
parse_omp_threads (char const* threads)
|
||||||
|
{
|
||||||
|
unsigned long int ret = 0;
|
||||||
|
|
||||||
|
if (threads == NULL)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* The OpenMP spec says that the value assigned to the environment variables
|
||||||
|
"may have leading and trailing white space". */
|
||||||
|
while (*threads != '\0' && c_isspace (*threads))
|
||||||
|
threads++;
|
||||||
|
|
||||||
|
/* Convert it from positive decimal to 'unsigned long'. */
|
||||||
|
if (c_isdigit (*threads))
|
||||||
|
{
|
||||||
|
char *endptr = NULL;
|
||||||
|
unsigned long int value = strtoul (threads, &endptr, 10);
|
||||||
|
|
||||||
|
if (endptr != NULL)
|
||||||
|
{
|
||||||
|
while (*endptr != '\0' && c_isspace (*endptr))
|
||||||
|
endptr++;
|
||||||
|
if (*endptr == '\0')
|
||||||
|
return value;
|
||||||
|
/* Also accept the first value in a nesting level,
|
||||||
|
since we can't determine the nesting level from env vars. */
|
||||||
|
else if (*endptr == ',')
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long int
|
||||||
|
num_processors (enum nproc_query query)
|
||||||
|
{
|
||||||
|
unsigned long int omp_env_limit = ULONG_MAX;
|
||||||
|
|
||||||
|
if (query == NPROC_CURRENT_OVERRIDABLE)
|
||||||
|
{
|
||||||
|
unsigned long int omp_env_threads;
|
||||||
|
/* Honor the OpenMP environment variables, recognized also by all
|
||||||
|
programs that are based on OpenMP. */
|
||||||
|
omp_env_threads = parse_omp_threads (getenv ("OMP_NUM_THREADS"));
|
||||||
|
omp_env_limit = parse_omp_threads (getenv ("OMP_THREAD_LIMIT"));
|
||||||
|
if (! omp_env_limit)
|
||||||
|
omp_env_limit = ULONG_MAX;
|
||||||
|
|
||||||
|
if (omp_env_threads)
|
||||||
|
return MIN (omp_env_threads, omp_env_limit);
|
||||||
|
|
||||||
|
query = NPROC_CURRENT;
|
||||||
|
}
|
||||||
|
/* Here query is one of NPROC_ALL, NPROC_CURRENT. */
|
||||||
|
{
|
||||||
|
unsigned long nprocs = num_processors_ignoring_omp (query);
|
||||||
|
return MIN (nprocs, omp_env_limit);
|
||||||
|
}
|
||||||
|
}
|
46
lib/nproc.h
Normal file
46
lib/nproc.h
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
/* Detect the number of processors.
|
||||||
|
|
||||||
|
Copyright (C) 2009-2021 Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
This file is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as
|
||||||
|
published by the Free Software Foundation; either version 2.1 of the
|
||||||
|
License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This file is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
/* Written by Glen Lenker and Bruno Haible. */
|
||||||
|
|
||||||
|
/* Allow the use in C++ code. */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* A "processor" in this context means a thread execution unit, that is either
|
||||||
|
- an execution core in a (possibly multi-core) chip, in a (possibly multi-
|
||||||
|
chip) module, in a single computer, or
|
||||||
|
- a thread execution unit inside a core
|
||||||
|
(hyper-threading, see <https://en.wikipedia.org/wiki/Hyper-threading>).
|
||||||
|
Which of the two definitions is used, is unspecified. */
|
||||||
|
|
||||||
|
enum nproc_query
|
||||||
|
{
|
||||||
|
NPROC_ALL, /* total number of processors */
|
||||||
|
NPROC_CURRENT, /* processors available to the current process */
|
||||||
|
NPROC_CURRENT_OVERRIDABLE /* likewise, but overridable through the
|
||||||
|
OMP_NUM_THREADS environment variable */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Return the total number of processors. The result is guaranteed to
|
||||||
|
be at least 1. */
|
||||||
|
extern unsigned long int num_processors (enum nproc_query query);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* C++ */
|
|
@ -3876,26 +3876,13 @@ processes from `comp-async-compilations'"
|
||||||
do (remhash file-name comp-async-compilations))
|
do (remhash file-name comp-async-compilations))
|
||||||
(hash-table-count comp-async-compilations))
|
(hash-table-count comp-async-compilations))
|
||||||
|
|
||||||
(declare-function w32-get-nproc "w32.c")
|
|
||||||
(defvar comp-num-cpus nil)
|
(defvar comp-num-cpus nil)
|
||||||
(defun comp-effective-async-max-jobs ()
|
(defun comp-effective-async-max-jobs ()
|
||||||
"Compute the effective number of async jobs."
|
"Compute the effective number of async jobs."
|
||||||
(if (zerop native-comp-async-jobs-number)
|
(if (zerop native-comp-async-jobs-number)
|
||||||
(or comp-num-cpus
|
(or comp-num-cpus
|
||||||
(setf comp-num-cpus
|
(setf comp-num-cpus
|
||||||
;; FIXME: we already have a function to determine
|
(max 1 (/ (num-processors) 2))))
|
||||||
;; the number of processors, see get_native_system_info in w32.c.
|
|
||||||
;; The result needs to be exported to Lisp.
|
|
||||||
(max 1 (/ (cond ((eq 'windows-nt system-type)
|
|
||||||
(w32-get-nproc))
|
|
||||||
((executable-find "nproc")
|
|
||||||
(string-to-number
|
|
||||||
(shell-command-to-string "nproc")))
|
|
||||||
((eq 'berkeley-unix system-type)
|
|
||||||
(string-to-number
|
|
||||||
(shell-command-to-string "sysctl -n hw.ncpu")))
|
|
||||||
(t 1))
|
|
||||||
2))))
|
|
||||||
native-comp-async-jobs-number))
|
native-comp-async-jobs-number))
|
||||||
|
|
||||||
(defvar comp-last-scanned-async-output nil)
|
(defvar comp-last-scanned-async-output nil)
|
||||||
|
|
|
@ -139,6 +139,7 @@ AC_DEFUN([gl_EARLY],
|
||||||
# Code from module mktime-internal:
|
# Code from module mktime-internal:
|
||||||
# Code from module multiarch:
|
# Code from module multiarch:
|
||||||
# Code from module nocrash:
|
# Code from module nocrash:
|
||||||
|
# Code from module nproc:
|
||||||
# Code from module nstrftime:
|
# Code from module nstrftime:
|
||||||
# Code from module open:
|
# Code from module open:
|
||||||
# Code from module openat-h:
|
# Code from module openat-h:
|
||||||
|
@ -413,6 +414,7 @@ AC_DEFUN([gl_INIT],
|
||||||
fi
|
fi
|
||||||
gl_TIME_MODULE_INDICATOR([mktime])
|
gl_TIME_MODULE_INDICATOR([mktime])
|
||||||
gl_MULTIARCH
|
gl_MULTIARCH
|
||||||
|
gl_NPROC
|
||||||
gl_FUNC_GNU_STRFTIME
|
gl_FUNC_GNU_STRFTIME
|
||||||
gl_PATHMAX
|
gl_PATHMAX
|
||||||
gl_FUNC_PIPE2
|
gl_FUNC_PIPE2
|
||||||
|
@ -1221,6 +1223,8 @@ AC_DEFUN([gl_FILE_LIST], [
|
||||||
lib/mkostemp.c
|
lib/mkostemp.c
|
||||||
lib/mktime-internal.h
|
lib/mktime-internal.h
|
||||||
lib/mktime.c
|
lib/mktime.c
|
||||||
|
lib/nproc.c
|
||||||
|
lib/nproc.h
|
||||||
lib/nstrftime.c
|
lib/nstrftime.c
|
||||||
lib/open.c
|
lib/open.c
|
||||||
lib/openat-priv.h
|
lib/openat-priv.h
|
||||||
|
@ -1370,6 +1374,7 @@ AC_DEFUN([gl_FILE_LIST], [
|
||||||
m4/mode_t.m4
|
m4/mode_t.m4
|
||||||
m4/multiarch.m4
|
m4/multiarch.m4
|
||||||
m4/nocrash.m4
|
m4/nocrash.m4
|
||||||
|
m4/nproc.m4
|
||||||
m4/nstrftime.m4
|
m4/nstrftime.m4
|
||||||
m4/off_t.m4
|
m4/off_t.m4
|
||||||
m4/open-cloexec.m4
|
m4/open-cloexec.m4
|
||||||
|
|
54
m4/nproc.m4
Normal file
54
m4/nproc.m4
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
# nproc.m4 serial 5
|
||||||
|
dnl Copyright (C) 2009-2021 Free Software Foundation, Inc.
|
||||||
|
dnl This file is free software; the Free Software Foundation
|
||||||
|
dnl gives unlimited permission to copy and/or distribute it,
|
||||||
|
dnl with or without modifications, as long as this notice is preserved.
|
||||||
|
|
||||||
|
AC_DEFUN([gl_NPROC],
|
||||||
|
[
|
||||||
|
gl_PREREQ_NPROC
|
||||||
|
])
|
||||||
|
|
||||||
|
# Prerequisites of lib/nproc.c.
|
||||||
|
AC_DEFUN([gl_PREREQ_NPROC],
|
||||||
|
[
|
||||||
|
dnl Persuade glibc <sched.h> to declare CPU_SETSIZE, CPU_ISSET etc.
|
||||||
|
AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
|
||||||
|
|
||||||
|
AC_CHECK_HEADERS([sys/pstat.h sys/sysmp.h sys/param.h],,,
|
||||||
|
[AC_INCLUDES_DEFAULT])
|
||||||
|
dnl <sys/sysctl.h> requires <sys/param.h> on OpenBSD 4.0.
|
||||||
|
AC_CHECK_HEADERS([sys/sysctl.h],,,
|
||||||
|
[AC_INCLUDES_DEFAULT
|
||||||
|
#if HAVE_SYS_PARAM_H
|
||||||
|
# include <sys/param.h>
|
||||||
|
#endif
|
||||||
|
])
|
||||||
|
|
||||||
|
AC_CHECK_FUNCS([sched_getaffinity sched_getaffinity_np \
|
||||||
|
pstat_getdynamic sysmp sysctl])
|
||||||
|
|
||||||
|
dnl Test whether sched_getaffinity has the expected declaration.
|
||||||
|
dnl glibc 2.3.[0-2]:
|
||||||
|
dnl int sched_getaffinity (pid_t, unsigned int, unsigned long int *);
|
||||||
|
dnl glibc 2.3.3:
|
||||||
|
dnl int sched_getaffinity (pid_t, cpu_set_t *);
|
||||||
|
dnl glibc >= 2.3.4:
|
||||||
|
dnl int sched_getaffinity (pid_t, size_t, cpu_set_t *);
|
||||||
|
if test $ac_cv_func_sched_getaffinity = yes; then
|
||||||
|
AC_CACHE_CHECK([for glibc compatible sched_getaffinity],
|
||||||
|
[gl_cv_func_sched_getaffinity3],
|
||||||
|
[AC_COMPILE_IFELSE(
|
||||||
|
[AC_LANG_PROGRAM(
|
||||||
|
[[#include <errno.h>
|
||||||
|
#include <sched.h>]],
|
||||||
|
[[sched_getaffinity (0, 0, (cpu_set_t *) 0);]])],
|
||||||
|
[gl_cv_func_sched_getaffinity3=yes],
|
||||||
|
[gl_cv_func_sched_getaffinity3=no])
|
||||||
|
])
|
||||||
|
if test $gl_cv_func_sched_getaffinity3 = yes; then
|
||||||
|
AC_DEFINE([HAVE_SCHED_GETAFFINITY_LIKE_GLIBC], [1],
|
||||||
|
[Define to 1 if sched_getaffinity has a glibc compatible declaration.])
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
])
|
|
@ -90,6 +90,7 @@ static struct rlimit nofile_limit;
|
||||||
|
|
||||||
#include <c-ctype.h>
|
#include <c-ctype.h>
|
||||||
#include <flexmember.h>
|
#include <flexmember.h>
|
||||||
|
#include <nproc.h>
|
||||||
#include <sig2str.h>
|
#include <sig2str.h>
|
||||||
#include <verify.h>
|
#include <verify.h>
|
||||||
|
|
||||||
|
@ -8212,6 +8213,20 @@ integer or floating point values.
|
||||||
return system_process_attributes (pid);
|
return system_process_attributes (pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFUN ("num-processors", Fnum_processors, Snum_processors, 0, 1, 0,
|
||||||
|
doc: /* Return the number of processors, a positive integer.
|
||||||
|
Each usable thread execution unit counts as a processor.
|
||||||
|
By default, count the number of available processors,
|
||||||
|
overridable via the OMP_NUM_THREADS environment variable.
|
||||||
|
If optional argument QUERY is `current', ignore OMP_NUM_THREADS.
|
||||||
|
If QUERY is `all', also count processors not available. */)
|
||||||
|
(Lisp_Object query)
|
||||||
|
{
|
||||||
|
return make_uint (num_processors (EQ (query, Qall) ? NPROC_ALL
|
||||||
|
: EQ (query, Qcurrent) ? NPROC_CURRENT
|
||||||
|
: NPROC_CURRENT_OVERRIDABLE));
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef subprocesses
|
#ifdef subprocesses
|
||||||
/* Arrange to catch SIGCHLD if this hasn't already been arranged.
|
/* Arrange to catch SIGCHLD if this hasn't already been arranged.
|
||||||
Invoke this after init_process_emacs, and after glib and/or GNUstep
|
Invoke this after init_process_emacs, and after glib and/or GNUstep
|
||||||
|
@ -8472,6 +8487,8 @@ syms_of_process (void)
|
||||||
DEFSYM (Qpcpu, "pcpu");
|
DEFSYM (Qpcpu, "pcpu");
|
||||||
DEFSYM (Qpmem, "pmem");
|
DEFSYM (Qpmem, "pmem");
|
||||||
DEFSYM (Qargs, "args");
|
DEFSYM (Qargs, "args");
|
||||||
|
DEFSYM (Qall, "all");
|
||||||
|
DEFSYM (Qcurrent, "current");
|
||||||
|
|
||||||
DEFVAR_BOOL ("delete-exited-processes", delete_exited_processes,
|
DEFVAR_BOOL ("delete-exited-processes", delete_exited_processes,
|
||||||
doc: /* Non-nil means delete processes immediately when they exit.
|
doc: /* Non-nil means delete processes immediately when they exit.
|
||||||
|
@ -8633,4 +8650,5 @@ amounts of data in one go. */);
|
||||||
defsubr (&Sprocess_inherit_coding_system_flag);
|
defsubr (&Sprocess_inherit_coding_system_flag);
|
||||||
defsubr (&Slist_system_processes);
|
defsubr (&Slist_system_processes);
|
||||||
defsubr (&Sprocess_attributes);
|
defsubr (&Sprocess_attributes);
|
||||||
|
defsubr (&Snum_processors);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3878,6 +3878,7 @@ w32_compare_strings (const char *s1, const char *s2, char *locname,
|
||||||
return val - 2;
|
return val - 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* FIXME: Remove, merging any of its special features into num-processors. */
|
||||||
DEFUN ("w32-get-nproc", Fw32_get_nproc,
|
DEFUN ("w32-get-nproc", Fw32_get_nproc,
|
||||||
Sw32_get_nproc, 0, 0, 0,
|
Sw32_get_nproc, 0, 0, 0,
|
||||||
doc: /* Return the number of system's processor execution units. */)
|
doc: /* Return the number of system's processor execution units. */)
|
||||||
|
|
|
@ -946,5 +946,11 @@ Return nil if FILENAME doesn't exist."
|
||||||
(when buf
|
(when buf
|
||||||
(kill-buffer buf)))))
|
(kill-buffer buf)))))
|
||||||
|
|
||||||
|
(ert-deftest process-num-processors ()
|
||||||
|
"Sanity checks for num-processors."
|
||||||
|
(should (equal (num-processors) (num-processors)))
|
||||||
|
(should (integerp (num-processors)))
|
||||||
|
(should (< 0 (num-processors))))
|
||||||
|
|
||||||
(provide 'process-tests)
|
(provide 'process-tests)
|
||||||
;;; process-tests.el ends here
|
;;; process-tests.el ends here
|
||||||
|
|
Loading…
Add table
Reference in a new issue