Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add os.cpu_count() #62114

Closed
neologix mannequin opened this issue May 6, 2013 · 60 comments
Closed

add os.cpu_count() #62114

neologix mannequin opened this issue May 6, 2013 · 60 comments
Labels
easy topic-2to3 type-feature A feature request or enhancement

Comments

@neologix
Copy link
Mannequin

neologix mannequin commented May 6, 2013

BPO 17914
Nosy @pitrou, @vstinner, @giampaolo, @nedbat, @mark-summerfield, @tpn, @ezio-melotti, @bitdancer, @serhiy-storchaka, @kushaldas, @sdrees
Files
  • issue17914.patch: Patch for adding os.cpu_count()
  • issue17914-1.patch: Modified patch using C implementation of cpu_count()
  • issue17914-2.patch
  • issue17914-3.patch: Modified patch to return None from C code
  • issue17914-4.patch: Patch modified to use proper macro, remove os.py and skiptest buildbots
  • cpu_count.patch
  • issue17914-5.patch: removed os.py, tyepcasting and redundant comments from previous patch
  • issue17914-6.patch: Change array size to 2, return value to 0(in C code), and removed IRIX
  • issue17914-7.patch
  • use_cpu_count.diff
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = None
    closed_at = <Date 2013-06-28.18:21:53.122>
    created_at = <Date 2013-05-06.11:06:47.771>
    labels = ['easy', 'type-feature', 'expert-2to3']
    title = 'add os.cpu_count()'
    updated_at = <Date 2014-12-12.12:36:49.737>
    user = 'https://bugs.python.org/neologix'

    bugs.python.org fields:

    activity = <Date 2014-12-12.12:36:49.737>
    actor = 'mark'
    assignee = 'none'
    closed = True
    closed_date = <Date 2013-06-28.18:21:53.122>
    closer = 'neologix'
    components = ['2to3 (2.x to 3.x conversion tool)']
    creation = <Date 2013-05-06.11:06:47.771>
    creator = 'neologix'
    dependencies = []
    files = ['30217', '30220', '30223', '30226', '30236', '30241', '30246', '30282', '30284', '30319']
    hgrepos = []
    issue_num = 17914
    keywords = ['patch', 'easy']
    message_count = 60.0
    messages = ['188506', '188507', '188509', '188514', '188515', '188516', '188522', '188605', '188606', '188624', '188626', '188627', '188628', '188644', '188905', '188906', '188907', '188909', '188910', '188911', '188912', '188918', '188934', '188944', '188949', '188951', '188953', '188957', '188961', '188963', '188967', '188968', '189053', '189058', '189076', '189079', '189098', '189099', '189104', '189112', '189169', '189170', '189173', '189179', '189180', '189184', '189199', '189360', '189372', '189381', '189654', '189656', '189658', '189670', '189672', '189673', '192005', '232524', '232529', '232541']
    nosy_count = 14.0
    nosy_names = ['pitrou', 'vstinner', 'giampaolo.rodola', 'nedbat', 'mark', 'trent', 'ezio.melotti', 'r.david.murray', 'neologix', 'python-dev', 'serhiy.storchaka', 'kushal.das', 'dilettant', 'Yogesh.Chaudhari']
    pr_nums = []
    priority = 'normal'
    resolution = 'fixed'
    stage = 'resolved'
    status = 'closed'
    superseder = None
    type = 'enhancement'
    url = 'https://bugs.python.org/issue17914'
    versions = ['Python 3.4']

    @neologix
    Copy link
    Mannequin Author

    neologix mannequin commented May 6, 2013

    multiprocessing.cpu_count() implementation should be made available in the os module, where it belongs.

    @neologix neologix mannequin added easy type-feature A feature request or enhancement labels May 6, 2013
    @neologix
    Copy link
    Mannequin Author

    neologix mannequin commented May 6, 2013

    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.

    @nedbat
    Copy link
    Member

    nedbat commented May 6, 2013

    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.

    @kushaldas
    Copy link
    Member

    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).

    @neologix
    Copy link
    Mannequin Author

    neologix mannequin commented May 6, 2013

    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.

    @nedbat
    Copy link
    Member

    nedbat commented May 6, 2013

    Seriously, return zero, and I can use it as: cpu_count = os.cpu_count() or 1

    Why throw away information?

    @pitrou
    Copy link
    Member

    pitrou commented May 6, 2013

    Returning 0 or None sounds better to me than 1 or -1.
    (I have a preference for None)

    @vstinner
    Copy link
    Member

    vstinner commented May 6, 2013

    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 ;-)

    @vstinner
    Copy link
    Member

    vstinner commented May 6, 2013

    See also bpo-17444, Trent Nelson wrote an implementation of os.cpu_count().

    @neologix
    Copy link
    Mannequin Author

    neologix mannequin commented May 7, 2013

    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 bpo-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)?

    @vstinner
    Copy link
    Member

    vstinner commented May 7, 2013

    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.

    @neologix
    Copy link
    Mannequin Author

    neologix mannequin commented May 7, 2013

    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 ;-)

    @ezio-melotti
    Copy link
    Member

    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.

    @bitdancer
    Copy link
    Member

    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.

    @YogeshChaudhari
    Copy link
    Mannequin

    YogeshChaudhari mannequin commented May 11, 2013

    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.

    @YogeshChaudhari YogeshChaudhari mannequin added the topic-2to3 label May 11, 2013
    @neologix
    Copy link
    Mannequin Author

    neologix mannequin commented May 11, 2013

    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

    @nedbat
    Copy link
    Member

    nedbat commented May 11, 2013

    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.

    @serhiy-storchaka
    Copy link
    Member

    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.

    @pitrou
    Copy link
    Member

    pitrou commented May 11, 2013

    I agree with Charles-François. An approach using C library functions is far superior to launching external commands.

    @neologix
    Copy link
    Mannequin Author

    neologix mannequin commented May 11, 2013

    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.

    @pitrou
    Copy link
    Member

    pitrou commented May 11, 2013

    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).

    @serhiy-storchaka
    Copy link
    Member

    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.

    @YogeshChaudhari
    Copy link
    Mannequin

    YogeshChaudhari mannequin commented May 11, 2013

    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.

    @serhiy-storchaka
    Copy link
    Member

    Yogesh, didn't you notice comments on Rietveld?

    @YogeshChaudhari
    Copy link
    Mannequin

    YogeshChaudhari mannequin commented May 11, 2013

    @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.

    @serhiy-storchaka
    Copy link
    Member

    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.

    @YogeshChaudhari
    Copy link
    Mannequin

    YogeshChaudhari mannequin commented May 11, 2013

    Returning None from C code sounds reasonable to me. Anyone else wants to pitch in with suggestions for/against this?

    @YogeshChaudhari
    Copy link
    Mannequin

    YogeshChaudhari mannequin commented May 12, 2013

    Modified patch based on review by neologix

    @vstinner
    Copy link
    Member

    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 bpo-17914-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.

    @vstinner
    Copy link
    Member

    The return type of the C function sysconf() is long, but Python uses int: I opened the issue bpo-17964 to track this bug. (os.cpu_count() uses sysconf()).

    @neologix
    Copy link
    Mannequin Author

    neologix mannequin commented May 13, 2013

    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.

    @pitrou
    Copy link
    Member

    pitrou commented May 13, 2013

    • 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.

    @YogeshChaudhari
    Copy link
    Mannequin

    YogeshChaudhari mannequin commented May 13, 2013

    @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()

    1. +1 to Antoine on last comment ;-)

    @YogeshChaudhari
    Copy link
    Mannequin

    YogeshChaudhari mannequin commented May 13, 2013

    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

    @neologix
    Copy link
    Mannequin Author

    neologix mannequin commented May 13, 2013

    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!)

    @pitrou
    Copy link
    Member

    pitrou commented May 13, 2013

    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>

    @nedbat
    Copy link
    Member

    nedbat commented May 13, 2013

    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.

    @neologix
    Copy link
    Mannequin Author

    neologix mannequin commented May 13, 2013

    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...

    @pitrou
    Copy link
    Member

    pitrou commented May 13, 2013

    > 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.

    @YogeshChaudhari
    Copy link
    Mannequin

    YogeshChaudhari mannequin commented May 13, 2013

    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).

    @neologix
    Copy link
    Mannequin Author

    neologix mannequin commented May 14, 2013

    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!

    @YogeshChaudhari
    Copy link
    Mannequin

    YogeshChaudhari mannequin commented May 16, 2013

    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

    @YogeshChaudhari
    Copy link
    Mannequin

    YogeshChaudhari mannequin commented May 16, 2013

    Typo fix

    @python-dev
    Copy link
    Mannequin

    python-dev mannequin commented May 20, 2013

    New changeset 5e0c56557390 by Charles-Francois Natali in branch 'default':
    Issue bpo-17914: Add os.cpu_count(). Patch by Yogesh Chaudhari, based on an
    http://hg.python.org/cpython/rev/5e0c56557390

    @neologix
    Copy link
    Mannequin Author

    neologix mannequin commented May 20, 2013

    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.

    @vstinner
    Copy link
    Member

    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.

    @python-dev
    Copy link
    Mannequin

    python-dev mannequin commented May 20, 2013

    New changeset a85ac58e9eaf by Charles-Francois Natali in branch 'default':
    Issue bpo-17914: Remove OS-X special-case, and use the correct int type.
    http://hg.python.org/cpython/rev/a85ac58e9eaf

    @python-dev
    Copy link
    Mannequin

    python-dev mannequin commented May 20, 2013

    New changeset f9d815522cdb by Charles-Francois Natali in branch 'default':
    Issue bpo-17914: We can now inline _bsd_cpu_count().
    http://hg.python.org/cpython/rev/f9d815522cdb

    @neologix
    Copy link
    Mannequin Author

    neologix mannequin commented May 20, 2013

    • 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).

    @python-dev
    Copy link
    Mannequin

    python-dev mannequin commented Jun 28, 2013

    New changeset 6a0437adafbd by Charles-François Natali in branch 'default':
    Issue bpo-17914: Use os.cpu_count() instead of multiprocessing.cpu_count() where
    http://hg.python.org/cpython/rev/6a0437adafbd

    @neologix neologix mannequin closed this as completed Jun 28, 2013
    @mark-summerfield
    Copy link
    Mannequin

    mark-summerfield mannequin commented Dec 12, 2014

    In message
    http://bugs.python.org/issue17914#msg188626
    Victor Stenner says

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

    From my reading, and based on feedback from one of my customers, I believe he is correct and that GetSystemInfo() ought to be used on Windows. (It is available in pywin32 win32api.)

    @vstinner
    Copy link
    Member

    From my reading, and based on feedback from one of my customers, I believe he is correct and that GetSystemInfo() ought to be used on Windows. (It is available in pywin32 win32api.)

    Please open a new issue to suggest this enhancement, this issue is closed.

    @mark-summerfield
    Copy link
    Mannequin

    mark-summerfield mannequin commented Dec 12, 2014

    Since this is closed I've created a new issue as requested:
    http://bugs.python.org/issue23037

    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    easy topic-2to3 type-feature A feature request or enhancement
    Projects
    None yet
    Development

    No branches or pull requests

    8 participants