• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/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 platform 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-clock 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
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 = 'ctypes 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-clock)'
56USE_WALL_TIME_TIME = 'time.time() (wall-clock)'
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-clock 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-clock 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_clock_clock_systimes():
107    return (time.clock(), 0.0)
108
109def wall_clock_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 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
124
125def win32process_getprocesstimes_systimes():
126    d = win32process.GetProcessTimes(win32process.GetCurrentProcess())
127    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:
155    systimes = wall_clock_clock_systimes
156
157elif SYSTIMES_IMPLEMENTATION is USE_WALL_TIME_TIME:
158    systimes = wall_clock_time_systimes
159
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
169def 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
180### Testing
181
182def some_workload():
183    x = 0L
184    for i in xrange(10000000L):
185        x = x + 1L
186
187def test_workload():
188    print 'Testing systimes() under load conditions'
189    t0 = systimes()
190    some_workload()
191    t1 = systimes()
192    print 'before:', t0
193    print 'after:', t1
194    print 'differences:', (t1[0] - t0[0], t1[1] - t0[1])
195    print
196
197def test_idle():
198    print 'Testing systimes() under idle conditions'
199    t0 = systimes()
200    time.sleep(1)
201    t1 = systimes()
202    print 'before:', t0
203    print 'after:', t1
204    print 'differences:', (t1[0] - t0[0], t1[1] - t0[1])
205    print
206
207if __name__ == '__main__':
208    print 'Using %s as timer' % SYSTIMES_IMPLEMENTATION
209    print
210    test_workload()
211    test_idle()
212