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""" 34 35from __future__ import print_function 36 37import time, sys 38 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 54USE_CTYPES_GETPROCESSTIMES = 'ctypes GetProcessTimes() wrapper' 55USE_WIN32PROCESS_GETPROCESSTIMES = 'win32process.GetProcessTimes()' 56USE_RESOURCE_GETRUSAGE = 'resource.getrusage()' 57USE_PROCESS_TIME_CLOCK = 'time.clock() (process time)' 58USE_WALL_TIME_CLOCK = 'time.clock() (wall-clock)' 59USE_WALL_TIME_TIME = 'time.time() (wall-clock)' 60 61if sys.platform[:3] == 'win': 62 # Windows platform 63 try: 64 import win32process 65 except ImportError: 66 try: 67 import ctypes 68 except ImportError: 69 # Use the wall-clock implementation time.clock(), since this 70 # 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: 97 # Use wall-clock implementation time.time() since this provides 98 # 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 109def wall_clock_clock_systimes(): 110 return (time.clock(), 0.0) 111 112def wall_clock_time_systimes(): 113 return (time.time(), 0.0) 114 115# Number of clock ticks per second for the values returned 116# by GetProcessTimes() on Windows. 117# 118# 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 127 128def win32process_getprocesstimes_systimes(): 129 d = win32process.GetProcessTimes(win32process.GetCurrentProcess()) 130 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: 158 systimes = wall_clock_clock_systimes 159 160elif SYSTIMES_IMPLEMENTATION is USE_WALL_TIME_TIME: 161 systimes = wall_clock_time_systimes 162 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 172def 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 183### Testing 184 185def some_workload(): 186 x = 0 187 for i in range(10000000): 188 x = x + 1 189 190def test_workload(): 191 print('Testing systimes() under load conditions') 192 t0 = systimes() 193 some_workload() 194 t1 = systimes() 195 print('before:', t0) 196 print('after:', t1) 197 print('differences:', (t1[0] - t0[0], t1[1] - t0[1])) 198 print() 199 200def test_idle(): 201 print('Testing systimes() under idle conditions') 202 t0 = systimes() 203 time.sleep(1) 204 t1 = systimes() 205 print('before:', t0) 206 print('after:', t1) 207 print('differences:', (t1[0] - t0[0], t1[1] - t0[1])) 208 print() 209 210if __name__ == '__main__': 211 print('Using %s as timer' % SYSTIMES_IMPLEMENTATION) 212 print() 213 test_workload() 214 test_idle() 215