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