From: Paul Eggert Date: Sun, 10 Oct 2021 20:59:16 +0000 (-0700) Subject: New function num-processors X-Git-Tag: emacs-28.0.90~331 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=96278de8ac;p=emacs.git 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. --- diff --git a/admin/merge-gnulib b/admin/merge-gnulib index 886f37e28cc..c9fe3b2f95a 100755 --- a/admin/merge-gnulib +++ b/admin/merge-gnulib @@ -39,7 +39,8 @@ GNULIB_MODULES=' free-posix fstatat fsusage fsync futimens getloadavg getopt-gnu getrandom gettime gettimeofday gitlog-to-changelog 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 qcopy-acl readlink readlinkat regex sig2str sigdescr_np socklen stat-time std-gnu11 stdalign stddef stdio diff --git a/doc/lispref/processes.texi b/doc/lispref/processes.texi index 90c42156372..d90097d0b03 100644 --- a/doc/lispref/processes.texi +++ b/doc/lispref/processes.texi @@ -1047,6 +1047,19 @@ This function returns a list of all processes that have not been deleted. @end smallexample @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 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 diff --git a/etc/NEWS b/etc/NEWS index 09537d7d313..791248f7dc4 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -4094,6 +4094,10 @@ Parse a string as a mail address-like string. ** New function 'make-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'. This function returns a copy of the list of intervals (i.e., text diff --git a/lib/gnulib.mk.in b/lib/gnulib.mk.in index e9a1a5dc028..c7c7eb455be 100644 --- a/lib/gnulib.mk.in +++ b/lib/gnulib.mk.in @@ -129,6 +129,7 @@ # minmax \ # mkostemp \ # mktime \ +# nproc \ # nstrftime \ # pathmax \ # pipe2 \ @@ -2378,6 +2379,16 @@ EXTRA_libgnu_a_SOURCES += mktime.c endif ## 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 ifeq (,$(OMIT_GNULIB_MODULE_nstrftime)) diff --git a/lib/nproc.c b/lib/nproc.c new file mode 100644 index 00000000000..a9e369dd3f7 --- /dev/null +++ b/lib/nproc.c @@ -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 . */ + +/* Written by Glen Lenker and Bruno Haible. */ + +#include +#include "nproc.h" + +#include +#include +#include + +#if HAVE_PTHREAD_GETAFFINITY_NP && 0 +# include +# include +#endif +#if HAVE_SCHED_GETAFFINITY_LIKE_GLIBC || HAVE_SCHED_GETAFFINITY_NP +# include +#endif + +#include + +#if HAVE_SYS_PSTAT_H +# include +#endif + +#if HAVE_SYS_SYSMP_H +# include +#endif + +#if HAVE_SYS_PARAM_H +# include +#endif + +#if HAVE_SYS_SYSCTL_H && ! defined __GLIBC__ +# include +#endif + +#if defined _WIN32 && ! defined __CYGWIN__ +# define WIN32_LEAN_AND_MEAN +# include +#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 (), + 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); + } +} diff --git a/lib/nproc.h b/lib/nproc.h new file mode 100644 index 00000000000..d7659a5cad3 --- /dev/null +++ b/lib/nproc.h @@ -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 . */ + +/* 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 ). + 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++ */ diff --git a/lisp/emacs-lisp/comp.el b/lisp/emacs-lisp/comp.el index 63d4a74b546..0052fd0f8db 100644 --- a/lisp/emacs-lisp/comp.el +++ b/lisp/emacs-lisp/comp.el @@ -3876,26 +3876,13 @@ processes from `comp-async-compilations'" do (remhash file-name comp-async-compilations)) (hash-table-count comp-async-compilations)) -(declare-function w32-get-nproc "w32.c") (defvar comp-num-cpus nil) (defun comp-effective-async-max-jobs () "Compute the effective number of async jobs." (if (zerop native-comp-async-jobs-number) (or comp-num-cpus (setf comp-num-cpus - ;; FIXME: we already have a function to determine - ;; 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)))) + (max 1 (/ (num-processors) 2)))) native-comp-async-jobs-number)) (defvar comp-last-scanned-async-output nil) diff --git a/m4/gnulib-comp.m4 b/m4/gnulib-comp.m4 index a795fe76518..e314edcfb53 100644 --- a/m4/gnulib-comp.m4 +++ b/m4/gnulib-comp.m4 @@ -139,6 +139,7 @@ AC_DEFUN([gl_EARLY], # Code from module mktime-internal: # Code from module multiarch: # Code from module nocrash: + # Code from module nproc: # Code from module nstrftime: # Code from module open: # Code from module openat-h: @@ -413,6 +414,7 @@ AC_DEFUN([gl_INIT], fi gl_TIME_MODULE_INDICATOR([mktime]) gl_MULTIARCH + gl_NPROC gl_FUNC_GNU_STRFTIME gl_PATHMAX gl_FUNC_PIPE2 @@ -1221,6 +1223,8 @@ AC_DEFUN([gl_FILE_LIST], [ lib/mkostemp.c lib/mktime-internal.h lib/mktime.c + lib/nproc.c + lib/nproc.h lib/nstrftime.c lib/open.c lib/openat-priv.h @@ -1370,6 +1374,7 @@ AC_DEFUN([gl_FILE_LIST], [ m4/mode_t.m4 m4/multiarch.m4 m4/nocrash.m4 + m4/nproc.m4 m4/nstrftime.m4 m4/off_t.m4 m4/open-cloexec.m4 diff --git a/m4/nproc.m4 b/m4/nproc.m4 new file mode 100644 index 00000000000..887c66bee81 --- /dev/null +++ b/m4/nproc.m4 @@ -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 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 requires on OpenBSD 4.0. + AC_CHECK_HEADERS([sys/sysctl.h],,, + [AC_INCLUDES_DEFAULT + #if HAVE_SYS_PARAM_H + # include + #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 + #include ]], + [[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 +]) diff --git a/src/process.c b/src/process.c index 221d4c7f6c3..746cdc0428a 100644 --- a/src/process.c +++ b/src/process.c @@ -90,6 +90,7 @@ static struct rlimit nofile_limit; #include #include +#include #include #include @@ -8212,6 +8213,20 @@ integer or floating point values. 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 /* Arrange to catch SIGCHLD if this hasn't already been arranged. Invoke this after init_process_emacs, and after glib and/or GNUstep @@ -8472,6 +8487,8 @@ syms_of_process (void) DEFSYM (Qpcpu, "pcpu"); DEFSYM (Qpmem, "pmem"); DEFSYM (Qargs, "args"); + DEFSYM (Qall, "all"); + DEFSYM (Qcurrent, "current"); DEFVAR_BOOL ("delete-exited-processes", delete_exited_processes, 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 (&Slist_system_processes); defsubr (&Sprocess_attributes); + defsubr (&Snum_processors); } diff --git a/src/w32proc.c b/src/w32proc.c index 702ea122e65..3b7d92a2aa8 100644 --- a/src/w32proc.c +++ b/src/w32proc.c @@ -3878,6 +3878,7 @@ w32_compare_strings (const char *s1, const char *s2, char *locname, return val - 2; } +/* FIXME: Remove, merging any of its special features into num-processors. */ DEFUN ("w32-get-nproc", Fw32_get_nproc, Sw32_get_nproc, 0, 0, 0, doc: /* Return the number of system's processor execution units. */) diff --git a/test/src/process-tests.el b/test/src/process-tests.el index e39f57d23be..44f3ea2fbb4 100644 --- a/test/src/process-tests.el +++ b/test/src/process-tests.el @@ -946,5 +946,11 @@ Return nil if FILENAME doesn't exist." (when 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) ;;; process-tests.el ends here