blob: 79d249f8bb9c046252f23e27671eca1b2f3b3937 [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,
19 the module reverts to the highest resolution wall-time timer
20 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"""
34import time, sys, struct
35
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
51USE_CTYPES_GETPROCESSTIMES = 'cytpes GetProcessTimes() wrapper'
52USE_WIN32PROCESS_GETPROCESSTIMES = 'win32process.GetProcessTimes()'
53USE_RESOURCE_GETRUSAGE = 'resource.getrusage()'
54USE_PROCESS_TIME_CLOCK = 'time.clock() (process time)'
55USE_WALL_TIME_CLOCK = 'time.clock() (wall-time)'
56USE_WALL_TIME_TIME = 'time.time() (wall-time)'
57
58if sys.platform[:3] == 'win':
59 # Windows platform
60 try:
61 import win32process
62 except ImportError:
63 try:
64 import ctypes
65 except ImportError:
66 # Use the wall-time implementation time.clock(), since this
67 # 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:
94 # Use wall-time implementation time.time() since this provides
95 # 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
106def wall_time_clock_systimes():
107 return (time.clock(), 0.0)
108
109def wall_time_time_systimes():
110 return (time.time(), 0.0)
111
112# Number of clock ticks per second for the values returned
113# by GetProcessTimes() on Windows.
114#
115# Note: Ticks returned by GetProcessTimes() are micro-seconds on
116# Windows XP (though the docs say 100ns intervals)
117WIN32_PROCESS_TIMES_TICKS_PER_SECOND = 10e6
118
119def win32process_getprocesstimes_systimes():
120 d = win32process.GetProcessTimes(win32process.GetCurrentProcess())
121 # Note: I'm not sure whether KernelTime on Windows is the same as
122 # system time on Unix - I've yet to see a non-zero value for
123 # KernelTime on Windows.
124 return (d['UserTime'] / WIN32_PROCESS_TIMES_TICKS_PER_SECOND,
125 d['KernelTime'] / WIN32_PROCESS_TIMES_TICKS_PER_SECOND)
126
127def ctypes_getprocesstimes_systimes():
128 creationtime = ctypes.c_ulonglong()
129 exittime = ctypes.c_ulonglong()
130 kerneltime = ctypes.c_ulonglong()
131 usertime = ctypes.c_ulonglong()
132 rc = ctypes.windll.kernel32.GetProcessTimes(
133 ctypes.windll.kernel32.GetCurrentProcess(),
134 ctypes.byref(creationtime),
135 ctypes.byref(exittime),
136 ctypes.byref(kerneltime),
137 ctypes.byref(usertime))
138 if not rc:
139 raise TypeError('GetProcessTimes() returned an error')
140 return (usertime.value / WIN32_PROCESS_TIMES_TICKS_PER_SECOND,
141 kerneltime.value / WIN32_PROCESS_TIMES_TICKS_PER_SECOND)
142
143# Select the default for the systimes() function
144
145if SYSTIMES_IMPLEMENTATION is USE_RESOURCE_GETRUSAGE:
146 systimes = getrusage_systimes
147
148elif SYSTIMES_IMPLEMENTATION is USE_PROCESS_TIME_CLOCK:
149 systimes = process_time_clock_systimes
150
151elif SYSTIMES_IMPLEMENTATION is USE_WALL_TIME_CLOCK:
152 systimes = wall_time_clock_systimes
153
154elif SYSTIMES_IMPLEMENTATION is USE_WALL_TIME_TIME:
155 systimes = wall_time_time_systimes
156
157elif SYSTIMES_IMPLEMENTATION is USE_WIN32PROCESS_GETPROCESSTIMES:
158 systimes = win32process_getprocesstimes_systimes
159
160elif SYSTIMES_IMPLEMENTATION is USE_CTYPES_GETPROCESSTIMES:
161 systimes = ctypes_getprocesstimes_systimes
162
163else:
164 raise TypeError('no suitable systimes() implementation found')
165
166### Testing
167
168def some_workload():
169 x = 0L
170 for i in xrange(10000000L):
171 x = x + 1L
172
173def test_workload():
174 print 'Testing systimes() under load conditions'
175 t0 = systimes()
176 some_workload()
177 t1 = systimes()
178 print 'before:', t0
179 print 'after:', t1
180 print 'differences:', (t1[0] - t0[0], t1[1] - t0[1])
181 print
182
183def test_idle():
184 print 'Testing systimes() under idle conditions'
185 t0 = systimes()
186 time.sleep(1)
187 t1 = systimes()
188 print 'before:', t0
189 print 'after:', t1
190 print 'differences:', (t1[0] - t0[0], t1[1] - t0[1])
191 print
192
193if __name__ == '__main__':
194 print 'Using %s as timer' % SYSTIMES_IMPLEMENTATION
195 print
196 test_workload()
197 test_idle()