diff -r 6f4627a65c0a Doc/library/os.rst --- a/Doc/library/os.rst Sun May 05 08:14:53 2013 +0200 +++ b/Doc/library/os.rst Sat May 11 13:14:08 2013 -0400 @@ -3155,9 +3155,10 @@ Return the set of CPUs the process with PID *pid* (or the current process if zero) is restricted to. - .. seealso:: - :func:`multiprocessing.cpu_count` returns the number of CPUs in the - system. + +.. function:: cpu_count() + + Return the number of CPUs in the system. Returns None if undetermined. .. _os-path: diff -r 6f4627a65c0a Lib/multiprocessing/__init__.py --- a/Lib/multiprocessing/__init__.py Sun May 05 08:14:53 2013 +0200 +++ b/Lib/multiprocessing/__init__.py Sat May 11 13:14:08 2013 -0400 @@ -85,30 +85,11 @@ ''' Returns the number of CPUs in the system ''' - if sys.platform == 'win32': - try: - num = int(os.environ['NUMBER_OF_PROCESSORS']) - except (ValueError, KeyError): - num = 0 - elif 'bsd' in sys.platform or sys.platform == 'darwin': - comm = '/sbin/sysctl -n hw.ncpu' - if sys.platform == 'darwin': - comm = '/usr' + comm - try: - with os.popen(comm) as p: - num = int(p.read()) - except ValueError: - num = 0 + num = os.cpu_count() + if num == None: + raise NotImplementedError('cannot determine number of cpus') else: - try: - num = os.sysconf('SC_NPROCESSORS_ONLN') - except (ValueError, OSError, AttributeError): - num = 0 - - if num >= 1: return num - else: - raise NotImplementedError('cannot determine number of cpus') def freeze_support(): ''' diff -r 6f4627a65c0a Lib/os.py --- a/Lib/os.py Sun May 05 08:14:53 2013 +0200 +++ b/Lib/os.py Sat May 11 13:14:08 2013 -0400 @@ -25,6 +25,7 @@ import sys, errno import stat as st +import posix _names = sys.builtin_module_names @@ -32,7 +33,7 @@ __all__ = ["altsep", "curdir", "pardir", "sep", "pathsep", "linesep", "defpath", "name", "path", "devnull", "SEEK_SET", "SEEK_CUR", "SEEK_END", "fsencode", "fsdecode", "get_exec_path", "fdopen", - "popen", "extsep"] + "popen", "extsep", "cpu_count"] def _exists(name): return name in globals() @@ -1016,3 +1017,12 @@ raise TypeError("invalid fd type (%s, expected integer)" % type(fd)) import io return io.open(fd, *args, **kwargs) + +def cpu_count(): + ''' + Returns the number of CPUs in the system + ''' + num = posix.cpu_count() + if num == -1: + num = None + return num diff -r 6f4627a65c0a Lib/test/test_os.py --- a/Lib/test/test_os.py Sun May 05 08:14:53 2013 +0200 +++ b/Lib/test/test_os.py Sat May 11 13:14:08 2013 -0400 @@ -2216,6 +2216,13 @@ else: self.fail("No exception thrown by {}".format(func)) +class CPUCountTests(unittest.TestCase): + def test_cpu_count(self): + cpus = os.cpu_count() + self.assertTrue(isinstance(cpus, int) or (cpus is None)) + self.assertTrue(cpus != 0) + self.assertTrue((cpus >= 1) or (cpus is None)) + @support.reap_threads def test_main(): support.run_unittest( @@ -2246,6 +2253,7 @@ TermsizeTests, OSErrorTests, RemoveDirsTests, + CPUCountTests, ) if __name__ == "__main__": diff -r 6f4627a65c0a Misc/NEWS --- a/Misc/NEWS Sun May 05 08:14:53 2013 +0200 +++ b/Misc/NEWS Sat May 11 13:14:08 2013 -0400 @@ -69,6 +69,8 @@ Library ------- +- Issue #17914: Add os.cpu_count() + - Issue #14173: Avoid crashing when reading a signal handler during interpreter shutdown. diff -r 6f4627a65c0a Modules/posixmodule.c --- a/Modules/posixmodule.c Sun May 05 08:14:53 2013 +0200 +++ b/Modules/posixmodule.c Sat May 11 13:14:08 2013 -0400 @@ -113,6 +113,18 @@ #include #endif +#ifdef __hpux +#include +#endif + +#if defined(__DragonFly__) || \ + defined(__OpenBSD__) || \ + defined(__FreeBSD__) || \ + defined(__NetBSD__) || \ + defined(__APPLE__) +#include +#endif + #if defined(MS_WINDOWS) # define TERMSIZE_USE_CONIO #elif defined(HAVE_SYS_IOCTL_H) @@ -10299,6 +10311,68 @@ } #endif /* defined(TERMSIZE_USE_CONIO) || defined(TERMSIZE_USE_IOCTL) */ +PyDoc_STRVAR(posix_cpu_count__doc__, +"cpu_count() -> integer\n\n\ +Return an integer representing the number of online logical CPUs,\n\ +or -1 if this value cannot be established."); + +#if defined(__DragonFly__) || \ + defined(__OpenBSD__) || \ + defined(__FreeBSD__) || \ + defined(__NetBSD__) || \ + defined(__APPLE__) +static int +_bsd_cpu_count(void) +{ + int err = -1; + int ncpu = -1; + int mib[4]; + size_t len = sizeof(int); + mib[0] = CTL_HW; + mib[1] = HW_NCPU; + err = sysctl(mib, 2, &ncpu, &len, NULL, 0); + if (!err) + return ncpu; + else + return -1; +} +#endif + +static PyObject * +posix_cpu_count(PyObject *self) +{ +#ifdef MS_WINDOWS + SYSTEM_INFO sysinfo; + GetSystemInfo(&sysinfo); + return PyLong_FromLong(sysinfo.dwNumberOfProcessors); +#elif __hpux + return PyLong_FromLong(mpctl(MPC_GETNUMSPUS, NULL, NULL)); +#ifndef _SC_NPROCESSORS_ONLN +#ifdef _SC_NPROC_ONLN /* IRIX */ +#define _SC_NPROCESSORS_ONLN _SC_NPROC_ONLN +#endif +#endif /* ! defined(_SC_NPROCESSORS_ONLN) */ +#elif defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN) + return PyLong_FromLong(sysconf(_SC_NPROCESSORS_ONLN)); +#elif __APPLE__ + int err = -1; + int ncpu = -1; + size_t len = sizeof(int); + err = sysctlnametomib("hw.logicalcpu", &ncpu, &len, NULL, 0); + if (!err) + return PyLong_FromLong(ncpu); + else + return PyLong_FromLong(_bsd_cpu_count()); +#elif defined(__DragonFly__) || \ + defined(__OpenBSD__) || \ + defined(__FreeBSD__) || \ + defined(__NetBSD__) + return PyLong_FromLong(_bsd_cpu_count()); +#else + return PyLong_FromLong(-1); +#endif +} + static PyMethodDef posix_methods[] = { {"access", (PyCFunction)posix_access, @@ -10744,6 +10818,8 @@ #if defined(TERMSIZE_USE_CONIO) || defined(TERMSIZE_USE_IOCTL) {"get_terminal_size", get_terminal_size, METH_VARARGS, termsize__doc__}, #endif + {"cpu_count", (PyCFunction)posix_cpu_count, + METH_NOARGS, posix_cpu_count__doc__}, {NULL, NULL} /* Sentinel */ };