1import numpy 2import re 3 4 5def IsFloat(text): 6 if text is None: 7 return False 8 try: 9 float(text) 10 return True 11 except ValueError: 12 return False 13 14 15def RemoveTrailingZeros(x): 16 ret = x 17 ret = re.sub('\.0*$', '', ret) 18 ret = re.sub('(\.[1-9]*)0+$', '\\1', ret) 19 return ret 20 21 22def HumanizeFloat(x, n=2): 23 if not IsFloat(x): 24 return x 25 digits = re.findall('[0-9.]', str(x)) 26 decimal_found = False 27 ret = '' 28 sig_figs = 0 29 for digit in digits: 30 if digit == '.': 31 decimal_found = True 32 elif sig_figs != 0 or digit != '0': 33 sig_figs += 1 34 if decimal_found and sig_figs >= n: 35 break 36 ret += digit 37 return ret 38 39 40def GetNSigFigs(x, n=2): 41 if not IsFloat(x): 42 return x 43 my_fmt = '%.' + str(n - 1) + 'e' 44 x_string = my_fmt % x 45 f = float(x_string) 46 return f 47 48 49def GetFormattedPercent(baseline, other, bad_result='--'): 50 result = '%8s' % GetPercent(baseline, other, bad_result) 51 return result 52 53 54def GetPercent(baseline, other, bad_result='--'): 55 result = bad_result 56 if IsFloat(baseline) and IsFloat(other): 57 try: 58 pct = (float(other) / float(baseline) - 1) * 100 59 result = '%+1.1f' % pct 60 except ZeroDivisionError: 61 pass 62 return result 63 64 65def FitString(text, length): 66 if len(text) == length: 67 return text 68 elif len(text) > length: 69 return text[-length:] 70 else: 71 fmt = '%%%ds' % length 72 return fmt % text 73 74 75class TableFormatter(object): 76 77 def __init__(self): 78 self.d = '\t' 79 self.bad_result = 'x' 80 81 def GetTablePercents(self, table): 82 # Assumes table is not transposed. 83 pct_table = [] 84 85 pct_table.append(table[0]) 86 for i in range(1, len(table)): 87 row = [] 88 row.append(table[i][0]) 89 for j in range(1, len(table[0])): 90 c = table[i][j] 91 b = table[i][1] 92 p = GetPercent(b, c, self.bad_result) 93 row.append(p) 94 pct_table.append(row) 95 return pct_table 96 97 def FormatFloat(self, c, max_length=8): 98 if not IsFloat(c): 99 return c 100 f = float(c) 101 ret = HumanizeFloat(f, 4) 102 ret = RemoveTrailingZeros(ret) 103 if len(ret) > max_length: 104 ret = '%1.1ef' % f 105 return ret 106 107 def TransposeTable(self, table): 108 transposed_table = [] 109 for i in range(len(table[0])): 110 row = [] 111 for j in range(len(table)): 112 row.append(table[j][i]) 113 transposed_table.append(row) 114 return transposed_table 115 116 def GetTableLabels(self, table): 117 ret = '' 118 header = table[0] 119 for i in range(1, len(header)): 120 ret += '%d: %s\n' % (i, header[i]) 121 return ret 122 123 def GetFormattedTable(self, 124 table, 125 transposed=False, 126 first_column_width=30, 127 column_width=14, 128 percents_only=True, 129 fit_string=True): 130 o = '' 131 pct_table = self.GetTablePercents(table) 132 if transposed == True: 133 table = self.TransposeTable(table) 134 pct_table = self.TransposeTable(table) 135 136 for i in range(0, len(table)): 137 for j in range(len(table[0])): 138 if j == 0: 139 width = first_column_width 140 else: 141 width = column_width 142 143 c = table[i][j] 144 p = pct_table[i][j] 145 146 # Replace labels with numbers: 0... n 147 if IsFloat(c): 148 c = self.FormatFloat(c) 149 150 if IsFloat(p) and not percents_only: 151 p = '%s%%' % p 152 153 # Print percent values side by side. 154 if j != 0: 155 if percents_only: 156 c = '%s' % p 157 else: 158 c = '%s (%s)' % (c, p) 159 160 if i == 0 and j != 0: 161 c = str(j) 162 163 if fit_string: 164 o += FitString(c, width) + self.d 165 else: 166 o += c + self.d 167 o += '\n' 168 return o 169 170 def GetGroups(self, table): 171 labels = table[0] 172 groups = [] 173 group_dict = {} 174 for i in range(1, len(labels)): 175 label = labels[i] 176 stripped_label = self.GetStrippedLabel(label) 177 if stripped_label not in group_dict: 178 group_dict[stripped_label] = len(groups) 179 groups.append([]) 180 groups[group_dict[stripped_label]].append(i) 181 return groups 182 183 def GetSummaryTableValues(self, table): 184 # First get the groups 185 groups = self.GetGroups(table) 186 187 summary_table = [] 188 189 labels = table[0] 190 191 summary_labels = ['Summary Table'] 192 for group in groups: 193 label = labels[group[0]] 194 stripped_label = self.GetStrippedLabel(label) 195 group_label = '%s (%d runs)' % (stripped_label, len(group)) 196 summary_labels.append(group_label) 197 summary_table.append(summary_labels) 198 199 for i in range(1, len(table)): 200 row = table[i] 201 summary_row = [row[0]] 202 for group in groups: 203 group_runs = [] 204 for index in group: 205 group_runs.append(row[index]) 206 group_run = self.AggregateResults(group_runs) 207 summary_row.append(group_run) 208 summary_table.append(summary_row) 209 210 return summary_table 211 212 # Drop N% slowest and M% fastest numbers, and return arithmean of 213 # the remaining. 214 @staticmethod 215 def AverageWithDrops(numbers, slow_percent=20, fast_percent=20): 216 sorted_numbers = list(numbers) 217 sorted_numbers.sort() 218 num_slow = int(slow_percent / 100.0 * len(sorted_numbers)) 219 num_fast = int(fast_percent / 100.0 * len(sorted_numbers)) 220 sorted_numbers = sorted_numbers[num_slow:] 221 if num_fast: 222 sorted_numbers = sorted_numbers[:-num_fast] 223 return numpy.average(sorted_numbers) 224 225 @staticmethod 226 def AggregateResults(group_results): 227 ret = '' 228 if not group_results: 229 return ret 230 all_floats = True 231 all_passes = True 232 all_fails = True 233 for group_result in group_results: 234 if not IsFloat(group_result): 235 all_floats = False 236 if group_result != 'PASSED': 237 all_passes = False 238 if group_result != 'FAILED': 239 all_fails = False 240 if all_floats == True: 241 float_results = [float(v) for v in group_results] 242 ret = '%f' % TableFormatter.AverageWithDrops(float_results) 243 # Add this line for standard deviation. 244 ### ret += " %f" % numpy.std(float_results) 245 elif all_passes == True: 246 ret = 'ALL_PASS' 247 elif all_fails == True: 248 ret = 'ALL_FAILS' 249 return ret 250 251 @staticmethod 252 def GetStrippedLabel(label): 253 return re.sub('\s*\S+:\S+\s*', '', label) 254### return re.sub("\s*remote:\S*\s*i:\d+$", "", label) 255 256 @staticmethod 257 def GetLabelWithIteration(label, iteration): 258 return '%s i:%d' % (label, iteration) 259