blob: a0f30668571cdab0d3ea1812f2e673bc73882642 [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
8 based on the platforma and available tools.
9
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"""
Christian Heimes05e8be12008-02-23 18:30:17 +000034import time, sys
Thomas Wouters4d70c3d2006-06-08 14:42:34 +000035
36#
37# Note: Please keep this module compatible to Python 1.5.2.
38#
39# TODOs:
40#
41# * Add ctypes wrapper for new clock_gettime() real-time POSIX APIs;
42# these will then provide nano-second resolution where available.
43#
44# * Add a function that returns the resolution of systimes()
45# values, ie. systimesres().
46#
47
48### Choose an implementation
49
50SYSTIMES_IMPLEMENTATION = None
Christian Heimes81ee3ef2008-05-04 22:42:01 +000051USE_CTYPES_GETPROCESSTIMES = 'ctypes GetProcessTimes() wrapper'
Thomas Wouters4d70c3d2006-06-08 14:42:34 +000052USE_WIN32PROCESS_GETPROCESSTIMES = 'win32process.GetProcessTimes()'
53USE_RESOURCE_GETRUSAGE = 'resource.getrusage()'
54USE_PROCESS_TIME_CLOCK = 'time.clock() (process time)'
Thomas Wouters0e3f5912006-08-11 14:57:12 +000055USE_WALL_TIME_CLOCK = 'time.clock() (wall-clock)'
56USE_WALL_TIME_TIME = 'time.time() (wall-clock)'
Thomas Wouters4d70c3d2006-06-08 14:42:34 +000057
58if sys.platform[:3] == 'win':
59 # Windows platform
60 try:
61 import win32process
62 except ImportError:
63 try:
64 import ctypes
65 except ImportError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +000066 # Use the wall-clock implementation time.clock(), since this
Thomas Wouters4d70c3d2006-06-08 14:42:34 +000067 # is the highest resolution clock available on Windows
68 SYSTIMES_IMPLEMENTATION = USE_WALL_TIME_CLOCK
69 else:
70 SYSTIMES_IMPLEMENTATION = USE_CTYPES_GETPROCESSTIMES
71 else:
72 SYSTIMES_IMPLEMENTATION = USE_WIN32PROCESS_GETPROCESSTIMES
73else:
74 # All other platforms
75 try:
76 import resource
77 except ImportError:
78 pass
79 else:
80 SYSTIMES_IMPLEMENTATION = USE_RESOURCE_GETRUSAGE
81
82# Fall-back solution
83if SYSTIMES_IMPLEMENTATION is None:
84 # Check whether we can use time.clock() as approximation
85 # for systimes()
86 start = time.clock()
87 time.sleep(0.1)
88 stop = time.clock()
89 if stop - start < 0.001:
90 # Looks like time.clock() is usable (and measures process
91 # time)
92 SYSTIMES_IMPLEMENTATION = USE_PROCESS_TIME_CLOCK
93 else:
Thomas Wouters0e3f5912006-08-11 14:57:12 +000094 # Use wall-clock implementation time.time() since this provides
Thomas Wouters4d70c3d2006-06-08 14:42:34 +000095 # the highest resolution clock on most systems
96 SYSTIMES_IMPLEMENTATION = USE_WALL_TIME_TIME
97
98### Implementations
99
100def getrusage_systimes():
101 return resource.getrusage(resource.RUSAGE_SELF)[:2]
102
103def process_time_clock_systimes():
104 return (time.clock(), 0.0)
105
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000106def wall_clock_clock_systimes():
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000107 return (time.clock(), 0.0)
108
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000109def wall_clock_time_systimes():
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000110 return (time.time(), 0.0)
111
112# Number of clock ticks per second for the values returned
113# by GetProcessTimes() on Windows.
114#
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000115# Note: Ticks returned by GetProcessTimes() are 100ns intervals on
116# Windows XP. However, the process times are only updated with every
117# clock tick and the frequency of these is somewhat lower: depending
118# on the OS version between 10ms and 15ms. Even worse, the process
119# time seems to be allocated to process currently running when the
120# clock interrupt arrives, ie. it is possible that the current time
121# slice gets accounted to a different process.
122
123WIN32_PROCESS_TIMES_TICKS_PER_SECOND = 1e7
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000124
125def win32process_getprocesstimes_systimes():
126 d = win32process.GetProcessTimes(win32process.GetCurrentProcess())
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000127 return (d['UserTime'] / WIN32_PROCESS_TIMES_TICKS_PER_SECOND,
128 d['KernelTime'] / WIN32_PROCESS_TIMES_TICKS_PER_SECOND)
129
130def ctypes_getprocesstimes_systimes():
131 creationtime = ctypes.c_ulonglong()
132 exittime = ctypes.c_ulonglong()
133 kerneltime = ctypes.c_ulonglong()
134 usertime = ctypes.c_ulonglong()
135 rc = ctypes.windll.kernel32.GetProcessTimes(
136 ctypes.windll.kernel32.GetCurrentProcess(),
137 ctypes.byref(creationtime),
138 ctypes.byref(exittime),
139 ctypes.byref(kerneltime),
140 ctypes.byref(usertime))
141 if not rc:
142 raise TypeError('GetProcessTimes() returned an error')
143 return (usertime.value / WIN32_PROCESS_TIMES_TICKS_PER_SECOND,
144 kerneltime.value / WIN32_PROCESS_TIMES_TICKS_PER_SECOND)
145
146# Select the default for the systimes() function
147
148if SYSTIMES_IMPLEMENTATION is USE_RESOURCE_GETRUSAGE:
149 systimes = getrusage_systimes
150
151elif SYSTIMES_IMPLEMENTATION is USE_PROCESS_TIME_CLOCK:
152 systimes = process_time_clock_systimes
153
154elif SYSTIMES_IMPLEMENTATION is USE_WALL_TIME_CLOCK:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000155 systimes = wall_clock_clock_systimes
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000156
157elif SYSTIMES_IMPLEMENTATION is USE_WALL_TIME_TIME:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000158 systimes = wall_clock_time_systimes
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000159
160elif SYSTIMES_IMPLEMENTATION is USE_WIN32PROCESS_GETPROCESSTIMES:
161 systimes = win32process_getprocesstimes_systimes
162
163elif SYSTIMES_IMPLEMENTATION is USE_CTYPES_GETPROCESSTIMES:
164 systimes = ctypes_getprocesstimes_systimes
165
166else:
167 raise TypeError('no suitable systimes() implementation found')
168
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000169def processtime():
170
171 """ Return the total time spent on the process.
172
173 This is the sum of user and system time as returned by
174 systimes().
175
176 """
177 user, system = systimes()
178 return user + system
179
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000180### Testing
181
182def some_workload():
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000183 x = 0
184 for i in range(10000000):
185 x = x + 1
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000186
187def test_workload():
Guido van Rossum486364b2007-06-30 05:01:58 +0000188 print('Testing systimes() under load conditions')
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000189 t0 = systimes()
190 some_workload()
191 t1 = systimes()
Guido van Rossum486364b2007-06-30 05:01:58 +0000192 print('before:', t0)
193 print('after:', t1)
194 print('differences:', (t1[0] - t0[0], t1[1] - t0[1]))
195 print()
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000196
197def test_idle():
Guido van Rossum486364b2007-06-30 05:01:58 +0000198 print('Testing systimes() under idle conditions')
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000199 t0 = systimes()
200 time.sleep(1)
201 t1 = systimes()
Guido van Rossum486364b2007-06-30 05:01:58 +0000202 print('before:', t0)
203 print('after:', t1)
204 print('differences:', (t1[0] - t0[0], t1[1] - t0[1]))
205 print()
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000206
207if __name__ == '__main__':
Guido van Rossum486364b2007-06-30 05:01:58 +0000208 print('Using %s as timer' % SYSTIMES_IMPLEMENTATION)
209 print()
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000210 test_workload()
211 test_idle()