blob: 5e00891feeda1a6f416a2087fcca87db598e7e02 [file] [log] [blame]
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001#!/usr/bin/env python
2
3""" systimes() user and system timer implementations for use by
4 pybench.
5
6 This module implements various different strategies for measuring
7 performance timings. It tries to choose the best available method
Ezio Melotti7c4a7e62013-08-26 01:32:56 +03008 based on the platform and available tools.
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00009
10 On Windows, it is recommended to have the Mark Hammond win32
11 package installed. Alternatively, the Thomas Heller ctypes
12 packages can also be used.
13
14 On Unix systems, the standard resource module provides the highest
15 resolution timings. Unfortunately, it is not available on all Unix
16 platforms.
17
18 If no supported timing methods based on process time can be found,
Thomas Wouters0e3f5912006-08-11 14:57:12 +000019 the module reverts to the highest resolution wall-clock timer
Thomas Wouters4d70c3d2006-06-08 14:42:34 +000020 instead. The system time part will then always be 0.0.
21
22 The module exports one public API:
23
24 def systimes():
25
26 Return the current timer values for measuring user and system
27 time as tuple of seconds (user_time, system_time).
28
29 Copyright (c) 2006, Marc-Andre Lemburg (mal@egenix.com). See the
30 documentation for further information on copyrights, or contact
31 the author. All Rights Reserved.
32
33"""
Antoine Pitrou8a681222009-02-07 17:13:31 +000034
35from __future__ import print_function
36
Christian Heimes05e8be12008-02-23 18:30:17 +000037import time, sys
Thomas Wouters4d70c3d2006-06-08 14:42:34 +000038
39#
40# Note: Please keep this module compatible to Python 1.5.2.
41#
42# TODOs:
43#
44# * Add ctypes wrapper for new clock_gettime() real-time POSIX APIs;
45# these will then provide nano-second resolution where available.
46#
47# * Add a function that returns the resolution of systimes()
48# values, ie. systimesres().
49#
50
51### Choose an implementation
52
53SYSTIMES_IMPLEMENTATION = None
Christian Heimes81ee3ef2008-05-04 22:42:01 +000054USE_CTYPES_GETPROCESSTIMES = 'ctypes GetProcessTimes() wrapper'
Thomas Wouters4d70c3d2006-06-08 14:42:34 +000055USE_WIN32PROCESS_GETPROCESSTIMES = 'win32process.GetProcessTimes()'
56USE_RESOURCE_GETRUSAGE = 'resource.getrusage()'
57USE_PROCESS_TIME_CLOCK = 'time.clock() (process time)'
Thomas Wouters0e3f5912006-08-11 14:57:12 +000058USE_WALL_TIME_CLOCK = 'time.clock() (wall-clock)'
59USE_WALL_TIME_TIME = 'time.time() (wall-clock)'
Thomas Wouters4d70c3d2006-06-08 14:42:34 +000060
61if sys.platform[:3] == 'win':
62 # Windows platform
63 try:
64 import win32process
65 except ImportError:
66 try:
67 import ctypes
68 except ImportError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +000069 # Use the wall-clock implementation time.clock(), since this
Thomas Wouters4d70c3d2006-06-08 14:42:34 +000070 # is the highest resolution clock available on Windows
71 SYSTIMES_IMPLEMENTATION = USE_WALL_TIME_CLOCK
72 else:
73 SYSTIMES_IMPLEMENTATION = USE_CTYPES_GETPROCESSTIMES
74 else:
75 SYSTIMES_IMPLEMENTATION = USE_WIN32PROCESS_GETPROCESSTIMES
76else:
77 # All other platforms
78 try:
79 import resource
80 except ImportError:
81 pass
82 else:
83 SYSTIMES_IMPLEMENTATION = USE_RESOURCE_GETRUSAGE
84
85# Fall-back solution
86if SYSTIMES_IMPLEMENTATION is None:
87 # Check whether we can use time.clock() as approximation
88 # for systimes()
89 start = time.clock()
90 time.sleep(0.1)
91 stop = time.clock()
92 if stop - start < 0.001:
93 # Looks like time.clock() is usable (and measures process
94 # time)
95 SYSTIMES_IMPLEMENTATION = USE_PROCESS_TIME_CLOCK
96 else:
Thomas Wouters0e3f5912006-08-11 14:57:12 +000097 # Use wall-clock implementation time.time() since this provides
Thomas Wouters4d70c3d2006-06-08 14:42:34 +000098 # the highest resolution clock on most systems
99 SYSTIMES_IMPLEMENTATION = USE_WALL_TIME_TIME
100
101### Implementations
102
103def getrusage_systimes():
104 return resource.getrusage(resource.RUSAGE_SELF)[:2]
105
106def process_time_clock_systimes():
107 return (time.clock(), 0.0)
108
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000109def wall_clock_clock_systimes():
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000110 return (time.clock(), 0.0)
111
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000112def wall_clock_time_systimes():
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000113 return (time.time(), 0.0)
114
115# Number of clock ticks per second for the values returned
116# by GetProcessTimes() on Windows.
117#
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000118# Note: Ticks returned by GetProcessTimes() are 100ns intervals on
119# Windows XP. However, the process times are only updated with every
120# clock tick and the frequency of these is somewhat lower: depending
121# on the OS version between 10ms and 15ms. Even worse, the process
122# time seems to be allocated to process currently running when the
123# clock interrupt arrives, ie. it is possible that the current time
124# slice gets accounted to a different process.
125
126WIN32_PROCESS_TIMES_TICKS_PER_SECOND = 1e7
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000127
128def win32process_getprocesstimes_systimes():
129 d = win32process.GetProcessTimes(win32process.GetCurrentProcess())
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000130 return (d['UserTime'] / WIN32_PROCESS_TIMES_TICKS_PER_SECOND,
131 d['KernelTime'] / WIN32_PROCESS_TIMES_TICKS_PER_SECOND)
132
133def ctypes_getprocesstimes_systimes():
134 creationtime = ctypes.c_ulonglong()
135 exittime = ctypes.c_ulonglong()
136 kerneltime = ctypes.c_ulonglong()
137 usertime = ctypes.c_ulonglong()
138 rc = ctypes.windll.kernel32.GetProcessTimes(
139 ctypes.windll.kernel32.GetCurrentProcess(),
140 ctypes.byref(creationtime),
141 ctypes.byref(exittime),
142 ctypes.byref(kerneltime),
143 ctypes.byref(usertime))
144 if not rc:
145 raise TypeError('GetProcessTimes() returned an error')
146 return (usertime.value / WIN32_PROCESS_TIMES_TICKS_PER_SECOND,
147 kerneltime.value / WIN32_PROCESS_TIMES_TICKS_PER_SECOND)
148
149# Select the default for the systimes() function
150
151if SYSTIMES_IMPLEMENTATION is USE_RESOURCE_GETRUSAGE:
152 systimes = getrusage_systimes
153
154elif SYSTIMES_IMPLEMENTATION is USE_PROCESS_TIME_CLOCK:
155 systimes = process_time_clock_systimes
156
157elif SYSTIMES_IMPLEMENTATION is USE_WALL_TIME_CLOCK:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000158 systimes = wall_clock_clock_systimes
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000159
160elif SYSTIMES_IMPLEMENTATION is USE_WALL_TIME_TIME:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000161 systimes = wall_clock_time_systimes
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000162
163elif SYSTIMES_IMPLEMENTATION is USE_WIN32PROCESS_GETPROCESSTIMES:
164 systimes = win32process_getprocesstimes_systimes
165
166elif SYSTIMES_IMPLEMENTATION is USE_CTYPES_GETPROCESSTIMES:
167 systimes = ctypes_getprocesstimes_systimes
168
169else:
170 raise TypeError('no suitable systimes() implementation found')
171
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000172def processtime():
173
174 """ Return the total time spent on the process.
175
176 This is the sum of user and system time as returned by
177 systimes().
178
179 """
180 user, system = systimes()
181 return user + system
182
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000183### Testing
184
185def some_workload():
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000186 x = 0
187 for i in range(10000000):
188 x = x + 1
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000189
190def test_workload():
Guido van Rossum486364b2007-06-30 05:01:58 +0000191 print('Testing systimes() under load conditions')
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000192 t0 = systimes()
193 some_workload()
194 t1 = systimes()
Guido van Rossum486364b2007-06-30 05:01:58 +0000195 print('before:', t0)
196 print('after:', t1)
197 print('differences:', (t1[0] - t0[0], t1[1] - t0[1]))
198 print()
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000199
200def test_idle():
Guido van Rossum486364b2007-06-30 05:01:58 +0000201 print('Testing systimes() under idle conditions')
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000202 t0 = systimes()
203 time.sleep(1)
204 t1 = systimes()
Guido van Rossum486364b2007-06-30 05:01:58 +0000205 print('before:', t0)
206 print('after:', t1)
207 print('differences:', (t1[0] - t0[0], t1[1] - t0[1]))
208 print()
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000209
210if __name__ == '__main__':
Guido van Rossum486364b2007-06-30 05:01:58 +0000211 print('Using %s as timer' % SYSTIMES_IMPLEMENTATION)
212 print()
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000213 test_workload()
214 test_idle()