GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | ||||||||||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | ||||||||||||||||||||||||||||
GeezerVison is showing github.com — gh-109649: Add os.process_cpu_count() function by vstinner · Pull Request #109907 · python/cpython Conversation
|
|
Adding a new process_cpu_count() makes it easier to extend the function later for new use cases, instead of modifying the existing os.cpu_count():
About the pid parameter. First, I would like to implement this function on Windows (get process affinity), and then check if it would be possible to get the CPU affinity of another process on Windows, before considering to add a pid parameter. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
In psutil, this function is called Process.cpu_affinity(): https://psutil.readthedocs.io/en/latest/#psutil.Process.cpu_affinity |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
69c8bf4 to
7832caa
Compare
|
I prefer adding a new
|
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
|
I will take a look at it by tomorrow! |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
|
@gpshead: I updated my PR to reimplement os.process_cpu_count() in Python. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
cpu_set = sched_getaffinity(0) num_cpus = cpu_count() return min(len(cpu_set), num_cpus) if cpu_set else num_cpus Why do you want to return cpu_count() if it's smaller than len(sched_getaffinity(0))? It should not happen. If it happens, I would prefer to not workaround bugs, but fix the OS instead. For me, it should not happen.
When I added I recall that Python detects broken poll() implementation on macOS. In that case, we go further: we remove the function at runtime! (at Python startup) I prefer to not make assumptions about hypothetical bugs, but wait until we get real concrete bug reports, and then decide how to deal with them. Anyway, thanks for thinking about all corner cases, it's a good thing! |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
If we pass the -Xcpu_count= |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Overall LGTM, for the detail, I will delegate it to @gpshead
Sorry, something went wrong.
There was an error while loading. Please reload this page.
I would prefer that the discussion separately the implementation and the expected behavior. Also, can we discussion -Xcpu_count later? This PR is about adding process_cpu_count(), nothing more. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
|
||
| .. function:: process_cpu_count() | ||
|
|
||
| Get the number of logical CPUs usable by the current process. Returns |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
It is probably more accurate to say "usable by the calling thread of the current process". I believe each thread can have its own affinity.
(For parallelism planning purposes, the main thread prior to spawning others is likely what people would be calling this from anyways)
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Sadly, you're right. I updated the doc.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
One documentation improvement suggested but otherwise good.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
@gpshead is right, the number of CPUs is "per thread" in thread. Example: import os import threading def sched_remove_one_cpu(): mask = os.sched_getaffinity(0) mask.pop() os.sched_setaffinity(0, mask) def set_affinity(): tid = threading.get_native_id() print(f"thread {tid}: remove a second CPU") sched_remove_one_cpu() print(f"thread {tid}: {os.process_cpu_count()=}") tid = threading.get_native_id() print(f"main thread {tid}: remove a CPU") sched_remove_one_cpu() print(f"main thread {tid} before: {os.cpu_count()=}") print(f"main thread {tid} before: {os.process_cpu_count()=}") print() thread = threading.Thread(target=set_affinity) thread.start() thread.join() print() print(f"main thread {tid} after: {os.cpu_count()=}") print(f"main thread {tid} after: {os.process_cpu_count()=}") Output on Linux: You can see that the main thread loses a CPU when sched_remove_one_cpu() is called: os.process_cpu_count() is affected, but os.cpu_count() is not affected. When a thread removes a second CPU, it affects os.process_cpu_count() in the thread, but the second CPU removal does not affected the main thread. New thread inherit the mask of the caller thread, but a change in a child thread does not affect the parent thread. Well, that's the expected behavior. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
* Refactor os_sched_getaffinity_impl(): move variable definitions to their first assignment. * Fix test_posix.test_sched_getaffinity(): restore the old CPU mask when the test completes! * Doc: Specify that os.cpu_count() counts *logicial* CPUs. * Doc: Specify that os.sched_getaffinity(0) is related to the calling thread.
803f717 to
74ed3db
Compare
|
I made a few further changes to clarify differences between cpu_count(), process_cpu_count() and sched_affinity(). |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
I created issue GH-110160 for this bug. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Unrelated CI failures:
|
Sorry, something went wrong.
There was an error while loading. Please reload this page.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
if you're inclined to do so, the documentation improvements to the existing APIs in this PR would be worthwhile backporting to the 3.12 branch so that they show up on the default /3/ docs on python.org soon. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
It makes sense. I wrote PR gh-110169 for Python 3.12 (and added "backport to 3.11" label). |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
* Refactor os_sched_getaffinity_impl(): move variable definitions to their first assignment. * Fix test_posix.test_sched_getaffinity(): restore the old CPU mask when the test completes! * Doc: Specify that os.cpu_count() counts *logicial* CPUs. * Doc: Specify that os.sched_getaffinity(0) is related to the calling thread.
There was an error while loading. Please reload this page.
Successfully merging this pull request may close these issues.
There was an error while loading. Please reload this page.