Spaces:
Running
Running
| """ | |
| 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})' | |
| def start_time(self): | |
| return time.strftime("%I:%M:%S %p", self._start_clock) | |
| def end_time(self): | |
| if self._end_clock is None: | |
| return None | |
| return time.strftime("%I:%M:%S %p", self._end_clock) | |
| 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() | |