-
-
Notifications
You must be signed in to change notification settings - Fork 31.1k
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
time.perf_counter() is not system-wide on Windows, in disagreement with documentation #81386
Comments
The documentation for time.perf_counter() indicates it should return a system-wide value: https://docs.python.org/3/library/time.html#time.perf_counter This is not true on Windows, as a process-specific offset is subtracted from the underlying QueryPerformanceCounter() value. The code comments indicate this is to reduce precision loss: https://github.com/python/cpython/blob/master/Python/pytime.c#L995-L997 This is relevant in multiprocess applications, where accurate timing is required across multiple processes. Here is a simple test case: ----------------------------------------------------------- import concurrent.futures
import time
def worker():
return time.perf_counter()
if __name__ == '__main__':
pool = concurrent.futures.ProcessPoolExecutor()
futures = []
for i in range(3):
print('Submitting worker {:d} at time.perf_counter() == {:.3f}'.format(i, time.perf_counter()))
futures.append(pool.submit(worker))
time.sleep(1)
for i, f in enumerate(futures):
print('Worker {:d} started at time.perf_counter() == {:.3f}'.format(i, f.result())) Output: C:\...>Python37\python.exe perf_counter_across_processes.py See my stackoverflow question for a comparison with Linux: https://stackoverflow.com/questions/56502111/should-time-perf-counter-be-consistent-across-processes-in-python-on-windows |
Note that this offset subtraction behavior appears to be inherited from time.clock(), which did not make any guarantees about returning a system-wide value: |
Hi Terry, I'm new to this so apologies in advance if this is a silly question...can you explain why you removed 3.5 and 3.6 from the versions list? I have tested that the issue is present in 3.6 and the offending code has been present since time.perf_counter() was introduced in 3.3. It it because these versions are in maintenance-only status or similar, such that this type of bug fix would not be considered? Thanks, |
3.5 and 3.6 are closed for regular bug fix maintenance. We're only fixing issues in 3.7 and 3.8 now. Only security fixes will be applied to 3.5 or 3.6, and this issue is not considered a security issue. More details in https://devguide.python.org/#status-of-python-branches |
I'm actually surprised that this problem gets so little interest. It's probably so obscure that most people don't even realize it. Why isn't it implemented using winapi calls for the windows platform? I took inspiration from this SO thread https://stackoverflow.com/questions/56502111/should-time-perf-counter-be-consistent-across-processes-in-python-on-windows and came up with this function for 64 bit Python (a few more lines would be needed for error checking) #include <windows.h>
static PyObject* perf_counter(PyObject* self, PyObject* args)
{
PyObject* ret;
QueryPerformanceFrequency(lpFrequency);
QueryPerformanceCounter(lpPerformanceCount);
ret = PyFloat_FromDouble(((double) lpPerformanceCount->QuadPart ) / lpFrequency->QuadPart);
return ret;
} |
Since I added time.perf_counter_ns() to Python 3.7, it would be acceptable to reduce the "t0" variable and suggest to use time.perf_counter_ns() instead of time.perf_counter() for best precision. |
That would be perfect and would help a lot with timings/synchronization across multiple processes. Which Pyhton version will get this fix? |
Under the hood perf_counter_ns already uses the two winapi calls (see Line 970 in 4176193
|
I wrote PR 23284 to make time.perf_counter() on Windows and time.monotonic() on macOS system-wide (remove the offset computed at startup). I also suggested the usage of the _ns() variant functions in the documentation. |
I close the issue, it's now fixed in master. Thanks for the bug report Ken Healy. While Python 3.8 and 3.9 are also affected, I prefer to leave them unchanged to avoid bad surprises during a minor update (3.x.y bugfix release). If you disagree, please speak up! The regression was introduced in Python 3.7 by: commit bdaeb7d
This change was related to the implementation of the PEP-564. If you are curious about this work, I wrote two articles: |
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:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: