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

time.process_time() constant / erratic on Windows #82040

Closed
RedGlyph mannequin opened this issue Aug 14, 2019 · 6 comments
Closed

time.process_time() constant / erratic on Windows #82040

RedGlyph mannequin opened this issue Aug 14, 2019 · 6 comments
Labels
3.7 (EOL) end of life 3.8 (EOL) end of life OS-windows stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error

Comments

@RedGlyph
Copy link
Mannequin

RedGlyph mannequin commented Aug 14, 2019

BPO 37859
Nosy @pfmoore, @vstinner, @tjguk, @zware, @eryksun, @zooba

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 2019-08-14.20:48:14.849>
created_at = <Date 2019-08-14.20:32:41.783>
labels = ['type-bug', '3.8', 'invalid', '3.7', 'library', 'OS-windows']
title = 'time.process_time() constant / erratic on Windows'
updated_at = <Date 2019-08-14.21:54:45.041>
user = 'https://bugs.python.org/RedGlyph'

bugs.python.org fields:

activity = <Date 2019-08-14.21:54:45.041>
actor = 'vstinner'
assignee = 'none'
closed = True
closed_date = <Date 2019-08-14.20:48:14.849>
closer = 'zach.ware'
components = ['Library (Lib)', 'Windows']
creation = <Date 2019-08-14.20:32:41.783>
creator = 'Red Glyph'
dependencies = []
files = []
hgrepos = []
issue_num = 37859
keywords = []
message_count = 6.0
messages = ['349745', '349746', '349748', '349759', '349762', '349763']
nosy_count = 7.0
nosy_names = ['paul.moore', 'vstinner', 'tim.golden', 'zach.ware', 'eryksun', 'steve.dower', 'Red Glyph']
pr_nums = []
priority = 'normal'
resolution = 'not a bug'
stage = 'resolved'
status = 'closed'
superseder = None
type = 'behavior'
url = 'https://bugs.python.org/issue37859'
versions = ['Python 3.7', 'Python 3.8']

@RedGlyph
Copy link
Mannequin Author

RedGlyph mannequin commented Aug 14, 2019

Tested with

  • Python 3.7.4, 64-bit, Windows version (installer version)
  • python-3.8.0b3-embed-amd64.zip
  • python-3.7.2.post1-embed-amd64.zip
    on Windows 7 x64 Professional

time.process_time() always returns the same value. If I check the value of time.process_time_ns(), sometimes it is constant, sometimes I observe a few changes, then it becomes constant too.

Here is a log of an example session, I'm waiting at least 1-2 seconds between each command:

Python 3.7.4 (tags/v3.7.4:e09359112e, Jul  8 2019, 20:34:20) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license()" for more information.
>>> import time
>>> time.process_time()
0.1092007
>>> time.process_time()
0.1092007
>>> time.process_time_ns()
109200700
>>> time.process_time_ns()
124800800
>>> time.process_time_ns()
124800800
>>> time.process_time()
0.1248008
>>> time.process_time()
0.1248008
>>> time.process_time()
0.1248008
>>> time.process_time_ns()
124800800
>>> time.process_time_ns()
124800800
>>> time.process_time_ns()
124800800
>>> time.process_time_ns()
124800800
>>> time.clock()

Warning (from warnings module):
  File "__main__", line 1
DeprecationWarning: time.clock has been deprecated in Python 3.3 and will be removed from Python 3.8: use time.perf_counter or time.process_time instead
77.006126126
>>> time.clock()
79.245575778
>>> time.clock()
80.801103036
>>> time.process_time()
0.1248008
>>>

@RedGlyph RedGlyph mannequin added 3.7 (EOL) end of life 3.8 (EOL) end of life stdlib Python modules in the Lib dir OS-windows type-bug An unexpected behavior, bug, or error labels Aug 14, 2019
@RedGlyph RedGlyph mannequin closed this as completed Aug 14, 2019
@RedGlyph RedGlyph mannequin added the invalid label Aug 14, 2019
@zware
Copy link
Member

zware commented Aug 14, 2019

Try this:

while time.process_time() < 0.5:
    print('.', flush=True, end='')

Or:

>>> time.process_time()
0.03125
>>> len(str(2**500_000))
150515
>>> time.process_time()
0.484375

Basically, process_time() (and process_time_ns()) measure CPU time used by the process, and you aren't making the CPU do anything between your checks.

@zware zware reopened this Aug 14, 2019
@zware zware removed the invalid label Aug 14, 2019
@zware zware closed this as completed Aug 14, 2019
@zware zware added the invalid label Aug 14, 2019
@RedGlyph
Copy link
Mannequin Author

RedGlyph mannequin commented Aug 14, 2019

I see that now. The behaviour was different in Linux, though, I suppose it may benefit from a more precise counter, but since in Windows it also has a precise counter with time.perf_counter_ns(), I was expecting to see that value change, but it was mainly a confusion with the older time.clock().

Thanks!

@eryksun
Copy link
Contributor

eryksun commented Aug 14, 2019

I suppose it may benefit from a more precise counter, but since in
Windows it also has a precise counter with time.perf_counter_ns(),
I was expecting to see that value change, but it was mainly a
confusion with the older time.clock().

Don't read too much into the clock info here:

    >>> time.get_clock_info('process_time').resolution
    1e-07

Process times [1] are stored as a 64-bit integer in units of 100 ns (1e-7). But the kernel schedules threads based on a timer that ticks every 15.625 ms by default. It can be lowered to about 0.5 ms, but this degrades battery life.

[1] https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getprocesstimes

@vstinner
Copy link
Member

Process times [1] are stored as a 64-bit integer in units of 100 ns (1e-7). But the kernel schedules threads based on a timer that ticks every 15.625 ms by default. It can be lowered to about 0.5 ms, but this degrades battery life.

Patches are welcome to enhance time.get_clock_info() :-)

Don't rely too much on time.get_clock_info() on Linux neither: it basically always say 1 ns, even if the effective resolution is way worse.

See the PEP-418 for some numbers:
https://www.python.org/dev/peps/pep-0418/#process-time

I wrote these programs to write this PEP ;-)

https://github.com/python/peps/tree/master/pep-0418

@vstinner
Copy link
Member

I see that now. The behaviour was different in Linux, though, I suppose it may benefit from a more precise counter, but since in Windows it also has a precise counter with time.perf_counter_ns(), I was expecting to see that value change, but it was mainly a confusion with the older time.clock().

On Windows, time.clock() was implemented with QueryPerformanceCounter(). This function became time.perf_counter() in Python 3.4. time.clock() was removed. Use time.get_clock_info('perf_counter') ;-)

The PEP-418 introduces new well defined clocks, since time.clock() was not portable.

perf_counter and process_time have very different properties. process_time is stopped when the process sleeps, for example.

https://docs.python.org/dev/library/time.html#time.perf_counter
https://docs.python.org/dev/library/time.html#time.process_time

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3.7 (EOL) end of life 3.8 (EOL) end of life OS-windows stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

No branches or pull requests

3 participants