1from time import time 2 3 4class Timer: 5 def __init__(self, timer_name): 6 """ 7 Creates timer. Timer name is name that will be in logs. 8 """ 9 self.timer_name = timer_name 10 self.start_time = None 11 self.end_time = None 12 self.section_name = None 13 self.timers = [] 14 15 def stop(self, section_name=''): 16 """ 17 Stop timer if running. Specify section_name if want to override its name. 18 """ 19 if self.start_time: 20 self.end_time = time() 21 section_name = section_name or self.section_name 22 self.timers.append((section_name, (self.end_time - self.start_time) * 1000.0)) 23 self.start_time = None 24 self.section_name = None 25 26 def start(self, section_name): 27 """ 28 Stop prev timer if present and starts new. 29 """ 30 self.stop() 31 self.section_name = section_name 32 self.start_time = time() 33 34 def _print_timer_table(self, time_table): 35 """ 36 Print a header and a footer and fill it with the timing results from time_table. 37 """ 38 # TODO: Convert to use table code from here /python/common/print_utils.py#L116 39 40 if not time_table: 41 print("NOT Time Table") 42 return 43 max_header = max(len(x[0]) for x in time_table) 44 line_max_size = max_header + 14 45 print() 46 print('Timing for %s:' % self.timer_name) 47 print('=' * line_max_size) 48 49 for name, val in time_table: 50 print("%-*s %8d msec" % (max_header, name, val)) 51 52 print('-' * line_max_size) 53 print(("Total: %8d msec" % sum(x[1] for x in time_table)).rjust(line_max_size)) 54 55 def print_flat(self): 56 """ 57 Output result. 58 """ 59 self._print_timer_table(self.timers) 60 61 def print_aggregate(self): 62 """ 63 Print aggregated results for each section. 64 """ 65 accumulated_times = {} 66 ordered_names = [] 67 for name, val in self.timers: 68 if name not in accumulated_times: 69 ordered_names.append(name) 70 accumulated_times[name] = 0 71 accumulated_times[name] += val 72 time_table = [(name, accumulated_times[name]) for name in ordered_names] 73 74 self._print_timer_table(time_table) 75 76 def print_statistics(self): 77 """ 78 Print number of times, average, std, and max statistics for each section. 79 """ 80 # TODO: If conversion to python 3 happens, use statistics.pstdev() to compute statistics. 81 number_samples = {} 82 means = {} 83 stds = {} 84 maxes = {} 85 ordered_names = [] 86 for name, val in self.timers: 87 if name not in ordered_names: 88 ordered_names.append(name) 89 means[name] = 0 90 stds[name] = 0 91 number_samples[name] = 0 92 maxes[name] = val 93 means[name] += val 94 number_samples[name] += 1 95 maxes[name] = max(val, maxes[name]) 96 for name in ordered_names: 97 means[name] = means[name] / number_samples[name] 98 for name, val in self.timers: 99 stds[name] += (val - means[name]) ** 2.0 100 for name in ordered_names: 101 stds[name] = (stds[name] / number_samples[name]) ** 0.5 102 103 max_header = max(len(x) for x in ordered_names) 104 line_max_size = max_header + 70 105 print() 106 print('Timing statistics for %s:' % self.timer_name) 107 print('=' * line_max_size) 108 109 for name in ordered_names: 110 print(("{:<{name_width}} num: {:>6d}, mean: {:>6.2f} msec, std: {:>6.2f} msec, max: {:>6.2f} msec"). 111 format(name, number_samples[name], means[name], stds[name], maxes[name], name_width=max_header)) 112 113 print('=' * line_max_size) 114 115 def stop_and_print(self): 116 """ 117 Stop timer, output flat result. 118 """ 119 self.stop() 120 self.print_flat() 121 122 def clear_data(self): 123 """ 124 Clear timer data. 125 """ 126 self.timers = [] 127