You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
time.perf_counter() should state more clearly (or deny) that it is monotonic #115637
I was trying to figure out the distinction between perf_counter and monotonic, and it's not entirely clear to me, even after reading PEP 418. I think it is monotonic, but I'm not sure.
So I'm invoking the Python gods here: what's the actual wanted behavior here? And why isn't it more clearly stated in the docs?
From my personal opinion, the fact that it is currently monotonic, does not mean that we should document it and make a promise about it. We already promised one thing about perf_counter() - it'll be the most precise timer on the system. If we make another promise that this'll be monotonic, then what happens if a system comes up with the most precise timer not being monotonic? We can't keep both promises anymore. That's probably just a imaginary scenario and one may argue that all the platforms we support at this time have the most precise timers as monotonic, which might be the real case at least for now.
On Windows, QueryPerformanceCounter() is implemented by reading x86 TSC. Ten years ago, TSC causes issues when the CPU frequency changed: recent CPU now have a TSC which is no longer related to the CPU frequency. There were also a few issues related to virtualization.
it does look like on everything but MS_WINDOWS, it defers to _PyTime_GetMonotonicClockWithInfo, so it's not only monotonic, it's exactly like time.monotonic().
But those are implementation details: i think the fundamental question here is whether or not the plan was to have the performance counter be monotonic in the first place, or, if that's the requirement anyway.
Looking at it from a library consumer perspective, i'm looking at the codetiming package and it's implemented with perf_counter. it's exactly the kind of module I would expect perf_counter to be used for, but I would also be extremely surprised if the counter would go backwards on time shifts, for example.
So I would personnally argue that perf_counter() is a superset of monotonic(). But I would understand if it would make things more complicated for implementers and if it wasn't the original intention of PEP418. But then I really wonder how one would be supposed to implement codetiming then: should it avoid using perf_counter() because it could eventually go backwards? or should it use both perf_counter() and monotonic and fallback on the latter if the former goes backwards? iffy...
Reacted by Thomas B. Brunner, Alexandre Morignot, Kasisnu, Árpád Goretity and NTFSvolume
Activity
AlexWaygood commentedon Feb 18, 2024
@vstinner, I think you might be the expert here? :)
anarcat commentedon Feb 18, 2024
alright, i guess #115638 should fix the docs then. :)
gaogaotiantian commentedon Feb 18, 2024
From my personal opinion, the fact that it is currently monotonic, does not mean that we should document it and make a promise about it. We already promised one thing about
perf_counter()- it'll be the most precise timer on the system. If we make another promise that this'll be monotonic, then what happens if a system comes up with the most precise timer not being monotonic? We can't keep both promises anymore. That's probably just a imaginary scenario and one may argue that all the platforms we support at this time have the most precise timers as monotonic, which might be the real case at least for now.vstinner commentedon Feb 19, 2024
I'm not 100% sure that perf_counter() is always monotonic in all cases on all platforms. It would help to have some evidence on Linux, Windows, macOS.
vstinner commentedon Feb 19, 2024
See also #88494
On Windows, QueryPerformanceCounter() is implemented by reading x86 TSC. Ten years ago, TSC causes issues when the CPU frequency changed: recent CPU now have a TSC which is no longer related to the CPU frequency. There were also a few issues related to virtualization.
Today, Windows documentation just says: https://learn.microsoft.com/en-us/windows/win32/sysinfo/acquiring-high-resolution-time-stamps
where QPC stands for QueryPerformanceCounter().
Linux supports multiple clock sources and can switch to the next one at runtime if Linux decides that a clock is not reliable. Example on my laptop:
TSC and ACPI PM are available and TSC is the current clock source.
vstinner commentedon Feb 19, 2024
PyTime_PerfCounter()has these implementations:Oh, in fact, Python
time.get_clock_info('perf_counter')announcesmonotonic=Trueon all platforms! Example on Linux:anarcat commentedon Feb 19, 2024
from what i can tell in the Fine Source Code:
cpython/Python/pytime.c
Lines 1327 to 1335 in aa8c1a0
it does look like on everything but
MS_WINDOWS, it defers to_PyTime_GetMonotonicClockWithInfo, so it's not only monotonic, it's exactly liketime.monotonic().But those are implementation details: i think the fundamental question here is whether or not the plan was to have the performance counter be monotonic in the first place, or, if that's the requirement anyway.
Looking at it from a library consumer perspective, i'm looking at the codetiming package and it's implemented with perf_counter. it's exactly the kind of module I would expect perf_counter to be used for, but I would also be extremely surprised if the counter would go backwards on time shifts, for example.
So I would personnally argue that
perf_counter()is a superset ofmonotonic(). But I would understand if it would make things more complicated for implementers and if it wasn't the original intention of PEP418. But then I really wonder how one would be supposed to implementcodetimingthen: should it avoid usingperf_counter()because it could eventually go backwards? or should it use both perf_counter() and monotonic and fallback on the latter if the former goes backwards? iffy...StanFromIreland commentedon Jun 5, 2026
Closing, this was documented in 846ad5a.