classification
Title: add os.cpu_count()
Type: enhancement Stage: resolved
Components: 2to3 (2.x to 3.x conversion tool) Versions: Python 3.4
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: Nosy List: Yogesh.Chaudhari, dilettant, ezio.melotti, giampaolo.rodola, haypo, kushal.das, nedbat, neologix, pitrou, python-dev, r.david.murray, serhiy.storchaka, trent
Priority: normal Keywords: easy, patch

Created on 2013-05-06 11:06 by neologix, last changed 2013-06-28 18:21 by neologix. This issue is now closed.

Files
File name Uploaded Description Edit
issue17914.patch Yogesh.Chaudhari, 2013-05-11 11:34 Patch for adding os.cpu_count() review
issue17914-1.patch Yogesh.Chaudhari, 2013-05-11 17:30 Modified patch using C implementation of cpu_count() review
issue17914-2.patch Yogesh.Chaudhari, 2013-05-11 19:18 review
issue17914-3.patch Yogesh.Chaudhari, 2013-05-11 22:19 Modified patch to return None from C code review
issue17914-4.patch Yogesh.Chaudhari, 2013-05-12 20:01 Patch modified to use proper macro, remove os.py and skiptest buildbots review
cpu_count.patch haypo, 2013-05-12 23:56 review
issue17914-5.patch Yogesh.Chaudhari, 2013-05-13 09:26 removed os.py, tyepcasting and redundant comments from previous patch review
issue17914-6.patch Yogesh.Chaudhari, 2013-05-16 12:06 Change array size to 2, return value to 0(in C code), and removed IRIX review
issue17914-7.patch Yogesh.Chaudhari, 2013-05-16 12:56 review
use_cpu_count.diff neologix, 2013-05-20 12:57 review
Messages (57)
msg188506 - (view) Author: Charles-François Natali (neologix) * (Python committer) Date: 2013-05-06 11:06
multiprocessing.cpu_count() implementation should be made available in the os module, where it belongs.
msg188507 - (view) Author: Charles-François Natali (neologix) * (Python committer) Date: 2013-05-06 11:11
Note that I think it might be interesting to return 1 if the actual value cannot be determined, since that's a sensible default, and likely what the caller will do anyway. This contrasts with the current multiprocessing's implementation which raised NotImplementedError.
msg188509 - (view) Author: Ned Batchelder (nedbat) * Date: 2013-05-06 11:15
If you can't determine the number of CPUs, return a clear "can't determine" value, such as 0 or -1.  Returning 1 will hide information, and it's an easy default for the caller to apply if they want to.
msg188514 - (view) Author: Kushal Das (kushal.das) * (Python committer) Date: 2013-05-06 11:47
I am interested to submit a patch on this. Should I move the implementation to os module and made the multiprocessing one as an alias ? or keep it in both places ?

I prefer the idea of returning -1 instead of the current way of raising NotImplementedError in case we can not determine the number of CPU(s).
msg188515 - (view) Author: Charles-François Natali (neologix) * (Python committer) Date: 2013-05-06 11:52
> I am interested to submit a patch on this. Should I move the implementation to os module and made the multiprocessing one as an alias ? or keep it in both places ?

Yes, you should move it, add a corresponding documentation to
Doc/modules/os.rst (you can probably reuse the multiprocessing doc),
and add a test in Lib/test/test_os.py (you can also probably reuse the
multiprocessing test).

> I prefer the idea of returning -1 instead of the current way of raising NotImplementedError in case we can not determine the number of CPU(s).

Seriously, I don't see what this brings. Since the user can't do
anything except using 1 instead, why not do this in the library?
I've searched a bit, and other platforms (.e.g Java, Ruby) don't raise
an exception, and always return a positive value.
msg188516 - (view) Author: Ned Batchelder (nedbat) * Date: 2013-05-06 12:00
Seriously, return zero, and I can use it as: cpu_count = os.cpu_count() or 1

Why throw away information?
msg188522 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2013-05-06 12:29
Returning 0 or None sounds better to me than 1 or -1.
(I have a preference for None)
msg188605 - (view) Author: STINNER Victor (haypo) * (Python committer) Date: 2013-05-06 22:33
I also vote +1 for returning None when the information is unknown.

Just write "os.cpu_count() or 1" if you need 1 when the count is unknown ;-)
msg188606 - (view) Author: STINNER Victor (haypo) * (Python committer) Date: 2013-05-06 22:35
See also #17444, Trent Nelson wrote an implementation of os.cpu_count().
msg188624 - (view) Author: Charles-François Natali (neologix) * (Python committer) Date: 2013-05-07 06:48
> I also vote +1 for returning None when the information is unknown.

I still don't like it.
If a function returns a number of CPU, it should either return an
integer >= 1, or raise an exception.
None is *not* an integer.

And returning an exception is IMO useles, since the user can't do
anything with anyway, other than fallback to 1.

> Just write "os.cpu_count() or 1" if you need 1 when the count is unknown ;-)

os.cpu_count() or 1 is an ugly idiom.

> See also #17444, Trent Nelson wrote an implementation of os.cpu_count().

I don't see exactly what this C implementation brings over the one in
multiprocessing (which is written in Python)?
msg188626 - (view) Author: STINNER Victor (haypo) * (Python committer) Date: 2013-05-07 07:17
> I don't see exactly what this C implementation brings over the one
> in multiprocessing (which is written in Python)?

multiprocessing.cpu_count() creates a subprocess on BSD and Darwin to get the number of CPU. Calling sysctl() or sysctlnametomib() should be faster and use less memory.

On Windows, GetSystemInfo() is called instead of reading an environment variable. I suppose that this function is more reliable.

Trent's os.cpu_count() returns -1 if the count cannot be read, multiprocessing.cpu_count() raises NotImplementedError.
msg188627 - (view) Author: Charles-François Natali (neologix) * (Python committer) Date: 2013-05-07 07:22
Fair enough, I guess we should use it then.

We just have to agree on the value to return when the number of CPUs
can't be determined ;-)
msg188628 - (view) Author: Ezio Melotti (ezio.melotti) * (Python committer) Date: 2013-05-07 07:28
Returning None sounds reasonable to me.
Raising an exception pretty much means that the function should always be called in a try/except (unless you are sure that the code is running on an OS that knows the number of CPUs).  Returning -1 is not very Pythonic, and between 0 and None I prefer the latter, since it's IMHO a clearer indication that the value couldn't be determined.
msg188644 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2013-05-07 12:34
As for why to not return 1, I can imagine code that checks cpu_count, and only if it returns the "don't know" result would it invoke some more expensive method of determining the CPU count on platforms that cpu_count doesn't support.  Since the os module is the home for "close to the metal" (well, OS) functions, I agree that it does not make sense to throw away the information that cpu_count can't actually determine the CPU count.  Contrawise, I could see the multiprocessing version returning 1, since it is a higher level API and os.cpu_count would be available for those wanting the "don't know" info.
msg188905 - (view) Author: Yogesh Chaudhari (Yogesh.Chaudhari) * Date: 2013-05-11 11:34
Based on the conversation and the particular inputs to the thread form neologix and ezio, I would like to submit this patch. 

It probably needs modification(s) as I am not sure what to do with the implementation that is already present in multiprocessing. This patch simply calls the os.cpu_count() from multiprocessing now and behaves as it would have previously.

The test cases are also added to test_os similar to ones from multiprocessing.
msg188906 - (view) Author: Charles-François Natali (neologix) * (Python committer) Date: 2013-05-11 11:50
> Based on the conversation and the particular inputs to the thread form neologix and ezio, I would like to submit this patch.
>
> It probably needs modification(s) as I am not sure what to do with the implementation that is already present in multiprocessing. This patch simply calls the os.cpu_count() from multiprocessing now and behaves as it would have previously.

Thanks, but it would be better to reuse Trent's C implementation
instead of multiprocessing's:
http://hg.python.org/sandbox/trent/file/dd1c2fd3aa31/Modules/posixmodule.c#l10213
msg188907 - (view) Author: Ned Batchelder (nedbat) * Date: 2013-05-11 11:51
A few small points:

Use `num is None` instead of `num == None`.

Use `isinstance(cpus, int)` rather than `type(cpus) is int`.

And this I think will throw an exception in Python 3: `cpus >= 1 or cpus == None`, because you can't compare None to 1.
msg188909 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2013-05-11 12:13
I think the idiom `os.cpu_count() or 1` should be mentioned in the documentation an officially recommended. Otherwise people will produce a non-portable code which works on their developer's computers but not on exotic platforms.

I have added some other comments on Rietveld.
msg188910 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2013-05-11 12:17
I agree with Charles-François. An approach using C library functions is far superior to launching external commands.
msg188911 - (view) Author: Charles-François Natali (neologix) * (Python committer) Date: 2013-05-11 12:24
> I think the idiom `os.cpu_count() or 1` should be mentioned in the documentation an officially recommended. Otherwise people will produce a non-portable code which works on their developer's computers but not on exotic platforms.

And I maintain it's an ugly idiom ;-)
Since the user can't do anything except falling back to 1,
os.cpu_count() should always return a positive number (1 by default).
That's AFAICT what all other platforms (Java, Ruby, etc) do, because
it makes sense.
msg188912 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2013-05-11 12:26
> And I maintain it's an ugly idiom ;-)
> Since the user can't do anything except falling back to 1,
> os.cpu_count() should always return a positive number (1 by default).

The user can also raise an error. For example, if I'm writing a
benchmark to measure per-core scaling performance, I would like to bail
out if I can't calculate the number of cores (rather than report
incorrect results).
msg188918 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2013-05-11 13:10
> Since the user can't do anything except falling back to 1,
> os.cpu_count() should always return a positive number (1 by default).

In general I agree with you. Actually the os module should contains two functions: cpu_count() which fallbacks to 1 and is_cpu_counting_supported() for rare need. But this looks even more ugly and I choose single function even if in most cases I need use strange idiom.
msg188934 - (view) Author: Yogesh Chaudhari (Yogesh.Chaudhari) * Date: 2013-05-11 17:30
Appreciate everyone's feedback. I have modified the patch based on further messages in the thread.

@Neologix
modified posixmodule according to one in Trent's branch and used that for cpu_count(). Kindly suggest improvements/changes if any.

@Ned:
Thanks for the suggestions. I have applied them wherever applicable. However regarding 
"And this I think will throw an exception in Python 3: `cpus >= 1 or cpus == None`, because you can't compare None to 1."
It does not throw any exceptions as of now.
msg188944 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2013-05-11 18:44
Yogesh, didn't you notice comments on Rietveld?
msg188949 - (view) Author: Yogesh Chaudhari (Yogesh.Chaudhari) * Date: 2013-05-11 19:18
@Serhiy
Sorry, I missed your comments in the thread. I have made 2 changes and ignored the cpu_count() returning 0, because it returns -1 on failure, else give the number of CPUs. Also the test_os, checks for 0 return if that was to e the case.
msg188951 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2013-05-11 20:03
Now we have three cpu_count() functions: multiprocessing.cpu_count() raises an exception on failure, posix.cpu_count() returns -1, and os.cpu_count() returns None. It will be easy to get rid of Python wrapper in the os module and return None directly from C code.
msg188953 - (view) Author: Yogesh Chaudhari (Yogesh.Chaudhari) * Date: 2013-05-11 20:08
Returning None from C code sounds reasonable to me. Anyone else wants to pitch in with suggestions for/against this?
msg188957 - (view) Author: Charles-François Natali (neologix) * (Python committer) Date: 2013-05-11 21:38
> Returning None from C code sounds reasonable to me. Anyone else wants to pitch in with suggestions for/against this?

Go for it ;-)
msg188961 - (view) Author: Yogesh Chaudhari (Yogesh.Chaudhari) * Date: 2013-05-11 22:19
Modified patch to return None from C code
msg188963 - (view) Author: Ned Batchelder (nedbat) * Date: 2013-05-11 22:24
@Yogesh:  if cpus is None, then this will raise an exception in Python 3: `cpus >= 1 or cpus == None`  Perhaps you don't have enough test cases yet.
msg188967 - (view) Author: Yogesh Chaudhari (Yogesh.Chaudhari) * Date: 2013-05-11 22:46
@Ned:
if cpus is None, then this will raise an exception in Python 3: `cpus >= 1 or cpus == None`

I understand that cpus >= INTEGER will raise an exception and have already modified the condition to remove that kind of check. 

I was merely stating that equality checks do not raise exception. 
eg:
>>> cpus = None
>>> cpus == 1
False
>>> cpus == None
True
>>>

Thanks for pointing me out in the right direction to remove those invalid checks and showing the use of proper alternatives at other places in the patch
msg188968 - (view) Author: STINNER Victor (haypo) * (Python committer) Date: 2013-05-11 23:09
Not being able to decide for the default value is not a problem: just an
optional "default" argument, which is 1 by default (most convinient value),
return default on error. os.get_terminal_size() has a similar API for
example.
msg189053 - (view) Author: Yogesh Chaudhari (Yogesh.Chaudhari) * Date: 2013-05-12 18:53
@STINNER:
I don't understand. Where exactly should the patch handle this?
msg189058 - (view) Author: Yogesh Chaudhari (Yogesh.Chaudhari) * Date: 2013-05-12 20:01
Modified patch based on review by neologix
msg189076 - (view) Author: STINNER Victor (haypo) * (Python committer) Date: 2013-05-12 23:56
Here is a new patch (cpu_count.patch) with a different approach:

 * add a os.cpu_count() which returns the raw value (may be zero or negative if the OS returns a dummy value) and raise an OSError on error
 * os.cpu_count() is not available on all platforms
 * shutil.cpu_count() is the high level API using 1 as a fallback. The fallback value (which is 1 by default) is configurable, ex: shutil.cpu_count(fallback=None) returns None on os.cpu_count() error.
 * multiprocessing.cpu_count() simply reuses shutil.cpu_count()

So os.cpu_count() as a well defined behaviour, and shutil.cpu_count() is the convinient API.

My patch is based on issue17914-4.patch and so also on Trent Nelson's code.

I only tested my patch on Linux. It must be tested on other platforms. If nobody tests the patch on HPUX, it would be safer to remove HPUX support.

It looks like Trent's code was not tested, I don't think that his code works on platforms other than Windows.

test_os will fail if os.cpu_count() fails. The test should be fixed to handle failures, but I prefer to start with a failing test to check if the error case occurs on a buildbot.
msg189079 - (view) Author: STINNER Victor (haypo) * (Python committer) Date: 2013-05-13 00:00
The return type of the C function sysconf() is long, but Python uses int: I opened the issue #17964 to track this bug. (os.cpu_count() uses sysconf()).
msg189098 - (view) Author: Charles-François Natali (neologix) * (Python committer) Date: 2013-05-13 05:52
> Here is a new patch (cpu_count.patch) with a different approach:
>
>  * add a os.cpu_count() which returns the raw value (may be zero or negative if the OS returns a dummy value) and raise an OSError on error
>  * os.cpu_count() is not available on all platforms
>  * shutil.cpu_count() is the high level API using 1 as a fallback. The fallback value (which is 1 by default) is configurable, ex: shutil.cpu_count(fallback=None) returns None on os.cpu_count() error.
>  * multiprocessing.cpu_count() simply reuses shutil.cpu_count()

Do we really need cpu_count() in three places with different semantics?
Also, it doesn't belong to shutil(), which stands for shell utilities IIRC.

IMO just one version in Modules/posixmodule.c is enough (with
multiprocessing's version as an alias), there's no need to
over-engineer this.
It can return None, that's fine with me now at this point.

> I only tested my patch on Linux. It must be tested on other platforms. If nobody tests the patch on HPUX, it would be safer to remove HPUX support.

Well, HP-UX isn't officially supported, so that's reasonable.

> test_os will fail if os.cpu_count() fails. The test should be fixed to handle failures, but I prefer to start with a failing test to check if the error case occurs on a buildbot.

That's reasonable.
msg189099 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2013-05-13 05:57
>  * add a os.cpu_count() which returns the raw value (may be zero or
> negative if the OS returns a dummy value) and raise an OSError on
> error
>  * os.cpu_count() is not available on all platforms
>  * shutil.cpu_count() is the high level API using 1 as a fallback. The
> fallback value (which is 1 by default) is configurable, ex:
> shutil.cpu_count(fallback=None) returns None on os.cpu_count() error.

-1. This is simply too complicated for a simple API. Just let
os.cpu_count() return None.
msg189104 - (view) Author: Yogesh Chaudhari (Yogesh.Chaudhari) * Date: 2013-05-13 08:15
@Stinner:

1. While I agree with your idea of what you have done in test_os, (particularly, for determining if platform is supported or not) there seems to be no reason(AFAIK) to have a shutil for cpu_count. I agree with neologox there.

2. Also I am not comfortable with the idea of having multiple 'implementations' of cpu_count. 
"There should be one-- and preferably only one --obvious way to do it."

3. The idea of returning 1 by default does not seem to serve a useful purpose. It should be left to the end-user to decide what needs to be done based on error/actual_value received from system. (+1 to Antoine and nedbat)
For eg,

a. Let's say someone works on scheduling and power managment modules. It is important to know that the platform does not support providing cpu_count() instead of giving 1. This will ensure that they don't go about erroneously setting wrong options for scheduler and/or overclocking the CPU too much(or too little).

b. On the other hand if another user just wants to use a cpu_count number from a his application to determine the number of threads to spawn he can set 
th = cpu_count() or 1 
(on a side note: *usually* for programs that are non IO intensive and require no/little synchronization it is best to spawn cpu_count() number of threads) 

These are just 2 examples to demonstrate that it must be the end-user who decides what to do with the proper_value or reasonable_error_value given by cpu_count()

4. +1 to Antoine on last comment ;-)
msg189112 - (view) Author: Yogesh Chaudhari (Yogesh.Chaudhari) * Date: 2013-05-13 09:26
Modified patch based on further comments and review. 
1. Removed *everything* from os.py
2. removed typecasting for ncpu where not required.
3. removed redundant comments
msg189169 - (view) Author: Charles-François Natali (neologix) * (Python committer) Date: 2013-05-13 19:50
Just for giggles, here's the glibc default implementation on non Linux
platforms:
http://sourceware.org/git/?p=glibc.git;a=blob;f=misc/getsysstats.c;hb=HEAD
"""
int
__get_nprocs ()
{
  /* We don't know how to determine the number.  Simply return always 1.  */
  return 1;
}
"""

And on Linux, 1 is returned as a fallback when you don't have the
right /sys or /proc entry:
http://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/getsysstats.c

(The enum discussion enlighted me, endless discussions are so fun!)
msg189170 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2013-05-13 19:57
> And on Linux, 1 is returned as a fallback when you don't have the
> right /sys or /proc entry:
> http://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/getsysstats.c
> 
> (The enum discussion enlighted me, endless discussions are so fun!)

Do you want cpu_count() to return an enum?

>>> os.cpu_count()
<CPUCount.Four: 4>
msg189173 - (view) Author: Ned Batchelder (nedbat) * Date: 2013-05-13 20:05
Python's goal is not to emulate the suboptimal parts of other languages.  We have dynamic typing, and so can return None from the same function that returns 1.  And we have compact expressions like `cpu_count() or 1`, so we don't have to make unfortunate compromises.
msg189179 - (view) Author: Charles-François Natali (neologix) * (Python committer) Date: 2013-05-13 21:15
> Python's goal is not to emulate the suboptimal parts of other languages.

Well, I'm sure they could have returned -1 or 0, which are valid C
long distinct from any valid integer representing a number of CPUs. If
the libc guys (and many other APIs out there ), chose to return 1 as
default, there's a reason.

Furthermore, you're missing the point: since the underlying libraries
os.cpu_count() rely on return 1 when they can't determine the number
of CPUs, why complicate the API by pretending to return None in that
case, since you can't detect it in the first place?

>  We have dynamic typing, and so can return None from the same function that returns 1.  And we have compact expressions like `cpu_count() or 1`, so we don't have to make unfortunate compromises.

That's not because it's feasible that it's a good idea.

Dynamic typing is different from no typing: the return type of a
function is part of its API. You can't return None when you're
supposed to return an int. If I go to a coffee machine to get some
chocolate and there's no chocolate left, I don't want it to return me
a coffee instead.

What's looks more natural
if os.cpu_count() is None
or
if os.cpu_count() >= 1

Even in dynamic typing, it's always a good thing to be consistent in
parameter and return value type.

Why?
For example, PEP 362 formalizes function signatures.

With a os.cpu_count() returning a number (or eventually raising an
exception), the signature is:

def cpu_count() -> int
   [...]

What does it become if you can return None instead?

For example, there's some discussion to use such signatures or other
DSL to automatically generate the glue code needed to parse arguments
and return values from C extension modules (PEP 436 and 437).

Basically, you just implement:

/*
** [annotation]
** @return int
*/
long cpu_count_impl(void)
{
    long result = 1;
#ifdef _SC_NPROCESSORS_CONF
    long = sysconf(_SC_NPROCESSORS_ONL);
[...]
#fi
    return result;
}

And the DSL processor takes care of the rest.

What does this become if your return object isn't typed?

Really, typing is of paramount importance, even in a dynamically typed language.

And pretending to return a distinct value is pretty much useless,
since the underlying platform will always return a default value of 1.
Plus `cpu_count() or 1` is really ugly.

Now I hope I made my point, but honestly at this point I don't care
anymore, since in practice it should never return None. Documenting
the None return value is just noise in the API...
msg189180 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2013-05-13 21:21
> > Python's goal is not to emulate the suboptimal parts of other languages.
> 
> Well, I'm sure they could have returned -1 or 0, which are valid C
> long distinct from any valid integer representing a number of CPUs. If
> the libc guys (and many other APIs out there ), chose to return 1 as
> default, there's a reason.

Well, they can be wrong sometimes, too :-)

> Furthermore, you're missing the point: since the underlying libraries
> os.cpu_count() rely on return 1 when they can't determine the number
> of CPUs, why complicate the API by pretending to return None in that
> case, since you can't detect it in the first place?

The patch doesn't seem to rely on the glibc, so we are fine here.
Or do the other libs work likewise?

> And the DSL processor takes care of the rest.
> 
> What does this become if your return object isn't typed?

It's typed, just the type is "int or None". I'm sure some
statically-typed languages are able to express this (OCaml? Haskell?).

Anyway, I don't mind whether it's None or 0 or -42. But let's not hide
the information.
msg189184 - (view) Author: Yogesh Chaudhari (Yogesh.Chaudhari) * Date: 2013-05-13 22:01
Based on the last 3 messages by Ned, Charles and Antoine, I keep thinking that arguments made by Charles are very valid ones and that it would be better to return 1. I say this (partly from the 'type' argument, but), mainly, *if* its known that the underlying libraries are returning 1 on failure. *If* that is the case I see no reason try to return None (which, btw, will never happen if none of the calls return non-positive values ever).
msg189199 - (view) Author: Charles-François Natali (neologix) * (Python committer) Date: 2013-05-14 05:36
> Well, they can be wrong sometimes, too :-)

Indeed, as can I ;-)

> The patch doesn't seem to rely on the glibc, so we are fine here.
> Or do the other libs work likewise?

sysconf(_SC_NPROCESSORS_CONF) is implemented with the above function
in the glibc.

For other Unix systems apparently they use the sysctl() syscall, and I
don't *think* it can fail to return the number of CPUs. So the only
platforms where it could in theory fail are things like Cygwin, etc.

>
>> And the DSL processor takes care of the rest.
>>
>> What does this become if your return object isn't typed?
>
> It's typed, just the type is "int or None". I'm sure some
> statically-typed languages are able to express this (OCaml? Haskell?).

I recently started learning Haskell. You have Either and Maybe that
could fall into that category.

> Anyway, I don't mind whether it's None or 0 or -42. But let's not hide
> the information.

I liked your suggestion of making it an enum:

>>> os.cpu_count()
<CPUCount.UnknownCount: 42>

Nah, None is fine to me!
msg189360 - (view) Author: Yogesh Chaudhari (Yogesh.Chaudhari) * Date: 2013-05-16 12:06
Minor modifications based on review comments.
1. Change mib array size to 2, 
2. return value set to 0 consistently (in C code), and 
3. removed IRIX #defines
msg189372 - (view) Author: Yogesh Chaudhari (Yogesh.Chaudhari) * Date: 2013-05-16 12:56
Typo fix
msg189381 - (view) Author: Giampaolo Rodola' (giampaolo.rodola) * (Python committer) Date: 2013-05-16 13:39
+1 for returning None.
I haven't looked into patches but if needed feel free to borrow some code from psutil:

Linux:
https://code.google.com/p/psutil/source/browse/psutil/_pslinux.py?spec=svn30f3c67322f99ab30ed87205245dc8394f89f0ac&r=c970f35bc9640ac32eb9f09de8c230e7f86a2466#44

BSD / OSX:
https://code.google.com/p/psutil/source/browse/psutil/_psutil_bsd.c?spec=svn30f3c67322f99ab30ed87205245dc8394f89f0ac&r=9b6e780ea6b598a785670c2626c7557f9fef9238#486

Windows:
https://code.google.com/p/psutil/source/browse/psutil/_psutil_mswindows.c?spec=svn30f3c67322f99ab30ed87205245dc8394f89f0ac&r=4d5b0de27024e9d3cd6a3573a493290498afa9c2#426

SunOS:
https://code.google.com/p/psutil/source/browse/psutil/_pssunos.py?spec=svnff76a4e33da359162c28f8c7478f9e6c6dff347b&name=sunos&r=d53e11edfbe18d22f4e08168f72b1952cfaef373#27
msg189654 - (view) Author: Roundup Robot (python-dev) Date: 2013-05-20 12:41
New changeset 5e0c56557390 by Charles-Francois Natali in branch 'default':
Issue #17914: Add os.cpu_count(). Patch by Yogesh Chaudhari, based on an
http://hg.python.org/cpython/rev/5e0c56557390
msg189656 - (view) Author: Charles-François Natali (neologix) * (Python committer) Date: 2013-05-20 12:57
Alright, committed.
Yogesh, thanks for the patch!

I'm attaching a patch to replace several occurrences of
multiprocessing.cpu_count() by os.cpu_count() in the stdlib/test
suite.
msg189658 - (view) Author: STINNER Victor (haypo) * (Python committer) Date: 2013-05-20 13:08
In my patch cpu_count.patch, I changed posix_cpu_count():

 * rewrite Mac OS X implementation: code in 5e0c56557390 looks wrong. It gets a MIB but then don't use it when calling _bsd_cpu_count(). But I didn't check my patch nor the commit version on Mac OS X.
 * use "int ncpu;" instead of "long ncpu;" when calling mpctl() and sysctl(). For mpctl(), ncpu is used to store the result, so a wide type is ok. But for sysctl(), we pass a pointer. What happens if sysctl() expects int whereas we pass a pointer to a long? We announce sizeof(int)!?
 * inline _bsd_cpu_count()

Sorry for this late review.
msg189670 - (view) Author: Roundup Robot (python-dev) Date: 2013-05-20 15:31
New changeset a85ac58e9eaf by Charles-Francois Natali in branch 'default':
Issue #17914: Remove OS-X special-case, and use the correct int type.
http://hg.python.org/cpython/rev/a85ac58e9eaf
msg189672 - (view) Author: Roundup Robot (python-dev) Date: 2013-05-20 15:41
New changeset f9d815522cdb by Charles-Francois Natali in branch 'default':
Issue #17914: We can now inline _bsd_cpu_count().
http://hg.python.org/cpython/rev/f9d815522cdb
msg189673 - (view) Author: Charles-François Natali (neologix) * (Python committer) Date: 2013-05-20 15:43
>  * rewrite Mac OS X implementation: code in 5e0c56557390 looks wrong. It
> gets a MIB but then don't use it when calling _bsd_cpu_count(). But I didn't
> check my patch nor the commit version on Mac OS X.

Indeed.
I just removed the OS-X special case altogether.
Apparently, the standard sysctl is supposed to work os OS-X.
We'll see what happens.

>  * use "int ncpu;" instead of "long ncpu;" when calling mpctl() and
> sysctl(). For mpctl(), ncpu is used to store the result, so a wide type is
> ok. But for sysctl(), we pass a pointer. What happens if sysctl() expects
> int whereas we pass a pointer to a long? We announce sizeof(int)!?

Ouch. This was overlooked when the type was changed to long.
I fixed this.

>  * inline _bsd_cpu_count()

Done in a subsequent commit (especially since the OS-X special case
has been removed).
msg192005 - (view) Author: Roundup Robot (python-dev) Date: 2013-06-28 17:26
New changeset 6a0437adafbd by Charles-François Natali in branch 'default':
Issue #17914: Use os.cpu_count() instead of multiprocessing.cpu_count() where
http://hg.python.org/cpython/rev/6a0437adafbd
History
Date User Action Args
2013-06-28 18:21:53neologixsetstatus: open -> closed
resolution: fixed
stage: patch review -> resolved
2013-06-28 17:26:30python-devsetmessages: + msg192005
2013-05-21 09:16:27neologixsetstage: needs patch -> patch review
2013-05-20 15:43:00neologixsetmessages: + msg189673
2013-05-20 15:41:22python-devsetmessages: + msg189672
2013-05-20 15:31:29python-devsetmessages: + msg189670
2013-05-20 13:08:15hayposetmessages: + msg189658
2013-05-20 12:57:01neologixsetfiles: + use_cpu_count.diff

messages: + msg189656
2013-05-20 12:41:53python-devsetnosy: + python-dev
messages: + msg189654
2013-05-16 13:39:20giampaolo.rodolasetnosy: + giampaolo.rodola
messages: + msg189381
2013-05-16 12:56:53Yogesh.Chaudharisetfiles: + issue17914-7.patch

messages: + msg189372
2013-05-16 12:06:19Yogesh.Chaudharisetfiles: + issue17914-6.patch

messages: + msg189360
2013-05-14 05:36:54neologixsetmessages: + msg189199
2013-05-13 22:01:42Yogesh.Chaudharisetmessages: + msg189184
2013-05-13 21:21:23pitrousetmessages: + msg189180
2013-05-13 21:15:53neologixsetmessages: + msg189179
2013-05-13 20:05:29nedbatsetmessages: + msg189173
2013-05-13 19:57:04pitrousetmessages: + msg189170
2013-05-13 19:50:28neologixsetmessages: + msg189169
2013-05-13 09:26:00Yogesh.Chaudharisetfiles: + issue17914-5.patch

messages: + msg189112
2013-05-13 08:15:46Yogesh.Chaudharisetmessages: + msg189104
2013-05-13 05:57:19pitrousetmessages: + msg189099
2013-05-13 05:52:06neologixsetmessages: + msg189098
2013-05-13 00:00:03hayposetmessages: + msg189079
2013-05-12 23:56:11hayposetfiles: + cpu_count.patch

messages: + msg189076
2013-05-12 20:01:53Yogesh.Chaudharisetfiles: + issue17914-4.patch

messages: + msg189058
2013-05-12 18:53:30Yogesh.Chaudharisetmessages: + msg189053
2013-05-12 16:13:06dilettantsetnosy: + dilettant
2013-05-11 23:09:53hayposetmessages: + msg188968
2013-05-11 22:46:06Yogesh.Chaudharisetmessages: + msg188967
2013-05-11 22:24:20nedbatsetmessages: + msg188963
2013-05-11 22:19:08Yogesh.Chaudharisetfiles: + issue17914-3.patch

messages: + msg188961
2013-05-11 21:38:39neologixsetmessages: + msg188957
2013-05-11 20:08:30Yogesh.Chaudharisetmessages: + msg188953
2013-05-11 20:03:12serhiy.storchakasetmessages: + msg188951
2013-05-11 19:18:45Yogesh.Chaudharisetfiles: + issue17914-2.patch

messages: + msg188949
2013-05-11 18:44:37serhiy.storchakasetmessages: + msg188944
2013-05-11 17:30:08Yogesh.Chaudharisetfiles: + issue17914-1.patch

messages: + msg188934
2013-05-11 13:10:34serhiy.storchakasetmessages: + msg188918
2013-05-11 12:26:33pitrousetmessages: + msg188912
2013-05-11 12:24:49neologixsetmessages: + msg188911
2013-05-11 12:17:18pitrousetmessages: + msg188910
2013-05-11 12:13:54serhiy.storchakasetnosy: + serhiy.storchaka
messages: + msg188909
2013-05-11 11:51:08nedbatsetmessages: + msg188907
2013-05-11 11:50:08neologixsetmessages: + msg188906
2013-05-11 11:34:24Yogesh.Chaudharisetfiles: + issue17914.patch

nosy: + Yogesh.Chaudhari
messages: + msg188905

components: + 2to3 (2.x to 3.x conversion tool)
keywords: + patch
2013-05-07 12:34:39r.david.murraysetnosy: + r.david.murray
messages: + msg188644
2013-05-07 07:28:13ezio.melottisetnosy: + ezio.melotti
messages: + msg188628
2013-05-07 07:22:12neologixsetmessages: + msg188627
2013-05-07 07:17:17hayposetmessages: + msg188626
2013-05-07 06:48:45neologixsetmessages: + msg188624
2013-05-06 22:35:48hayposetnosy: + trent
messages: + msg188606
2013-05-06 22:33:14hayposetnosy: + haypo
messages: + msg188605
2013-05-06 12:29:31pitrousetnosy: + pitrou
messages: + msg188522
2013-05-06 12:00:06nedbatsetmessages: + msg188516
2013-05-06 11:52:15neologixsetmessages: + msg188515
2013-05-06 11:47:49kushal.dassetnosy: + kushal.das
messages: + msg188514
2013-05-06 11:15:15nedbatsetnosy: + nedbat
messages: + msg188509
2013-05-06 11:11:52neologixsetmessages: + msg188507
2013-05-06 11:06:47neologixcreate