NucleoSpec / lib /pythoms /scripttime.py
viviandlin
Initial release of NucleoSpec
33ba306
Raw
History Blame Contribute Delete
5.47 kB
"""
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()