Spaces:
Running
Running
File size: 5,470 Bytes
33ba306 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | """
ScriptTime class
records timepoints in a python script
new:
functional
added periter to print the average time per supplied number of iterations
created formattime to handle times less than 1 ms
removed secondstostr and replaced all calls with formattime
added function profiling
added toggle for profiling
changed from time.time() to time.clock() which seems to give much higher resolution
---1.0---
removed timepoint function (now redundant with profiling capability)
updated print profile data function to be more detailed and easier to read
---1.1---
---1.2
to add:
use time.time() in unix and time.clock() in windows
"""
import sys
import time
import numpy as np
import datetime
class ScriptTime(object):
def __init__(self, profile=False):
"""
Class for storing timepoints in a python script
profile toggles whether the profiling functionality of the class will operate
"""
self._start_seconds = time.time() # start time (seconds since epoch)
self._end_seconds = None # end time (seconds since epoch)
self._start_clock = time.localtime() # start clock time
self._end_clock = None # end clock time
self.profile = profile # toggle for profiling functions
self.profiles = {}
def __str__(self):
"""The string that is returned when printed"""
return f'{self.__class__.__name__} initiated at {self.start_time}'
def __repr__(self):
"""The representation that is returned"""
return f'{self.__class__.__name__}({self.start_time})'
@property
def start_time(self):
return time.strftime("%I:%M:%S %p", self._start_clock)
@property
def end_time(self):
if self._end_clock is None:
return None
return time.strftime("%I:%M:%S %p", self._end_clock)
@property
def elapsed_time(self):
if self._end_seconds is None:
return time.time() - self._start_seconds
return self._end_seconds - self._start_seconds
def clearprofiles(self):
"""clears the profile data"""
self.profiles = {}
def formattime(self, t):
"""
Formats a time value in seconds to the appropriate string. This is now included for legacy support.
roughly based on formattime
"""
return str(datetime.timedelta(t))
def periter(self, num):
"""
calculated elapsed time per unit iteration (designed for timing scripts)
"""
sys.stdout.write('Average time per iteration: %s\n' % (self.formattime(self.elapsed_time / float(num))))
def printelapsed(self):
"""prints the elapsed time of the object"""
if self._end_seconds is None:
self.triggerend()
sys.stdout.write(f'Elapsed time: {datetime.timedelta(seconds=self.elapsed_time)}\n')
def printend(self):
"""prints the end time and the elapsed time of the object"""
if self._end_seconds is None:
self.triggerend()
sys.stdout.write(f'End time: {self.end_time} (elapsed: {datetime.timedelta(seconds=self.elapsed_time)})\n')
def printprofiles(self):
"""prints the data for the profiled functions"""
sys.stdout.write('\nFunction profile data:\n')
sys.stdout.write(
'%15s %6s %13s %13s %13s %13s\n' % ('function', 'called', 'avg', 'standard_deviation', 'max', 'min'))
for fname, data in self.profiles.items():
avg = sum(data[1]) / len(data[1])
sys.stdout.write('%15s %6d %13s %13s %13s %13s\n' % (
fname,
data[0],
self.formattime(avg),
self.formattime(np.sqrt(sum((i - avg) ** 2 for i in data[1]) / (len(data[1]) - 1))),
self.formattime(max(data[1])),
self.formattime(min(data[1]))
))
def printstart(self):
"""prints the start (trigger) time of the object"""
sys.stdout.write('Start time: %s\n' % (time.strftime('%I:%M:%S %p', self._start_clock)))
def profilefn(self, fn):
"""generates a profiled version of the supplied function"""
# from functools import wraps # unsure why these lines are present
# @wraps(fn)
def with_profiling(*args, **kwargs):
"""decorates function with profiling commands"""
start_time = time.perf_counter() # time that the function was called
ret = fn(*args, **kwargs) # calls the function
elapsed_time = time.perf_counter() - start_time # end time of the function
if fn.__name__ not in self.profiles: # generates a dictionary key based on the function name if not present
self.profiles[fn.__name__] = [0, []] # [number of times called, [list of durations]]
self.profiles[fn.__name__][0] += 1
self.profiles[fn.__name__][1].append(elapsed_time)
return ret # returns the calculated call of the function
if self.profile is True:
return with_profiling # returns the decorated function
else:
return fn
def triggerend(self):
"""triggers endpoint and calculates elapsed time since start"""
self._end_seconds = time.time()
self._end_clock = time.localtime()
if __name__ == '__main__':
st = ScriptTime()
time.sleep(2.)
st.triggerend()
st.printend()
|