import numpy import re def IsFloat(text): if text is None: return False try: float(text) return True except ValueError: return False def RemoveTrailingZeros(x): ret = x ret = re.sub('\.0*$', '', ret) ret = re.sub('(\.[1-9]*)0+$', '\\1', ret) return ret def HumanizeFloat(x, n=2): if not IsFloat(x): return x digits = re.findall('[0-9.]', str(x)) decimal_found = False ret = '' sig_figs = 0 for digit in digits: if digit == '.': decimal_found = True elif sig_figs != 0 or digit != '0': sig_figs += 1 if decimal_found and sig_figs >= n: break ret += digit return ret def GetNSigFigs(x, n=2): if not IsFloat(x): return x my_fmt = '%.' + str(n - 1) + 'e' x_string = my_fmt % x f = float(x_string) return f def GetFormattedPercent(baseline, other, bad_result='--'): result = '%8s' % GetPercent(baseline, other, bad_result) return result def GetPercent(baseline, other, bad_result='--'): result = bad_result if IsFloat(baseline) and IsFloat(other): try: pct = (float(other) / float(baseline) - 1) * 100 result = '%+1.1f' % pct except ZeroDivisionError: pass return result def FitString(text, length): if len(text) == length: return text elif len(text) > length: return text[-length:] else: fmt = '%%%ds' % length return fmt % text class TableFormatter(object): def __init__(self): self.d = '\t' self.bad_result = 'x' def GetTablePercents(self, table): # Assumes table is not transposed. pct_table = [] pct_table.append(table[0]) for i in range(1, len(table)): row = [] row.append(table[i][0]) for j in range(1, len(table[0])): c = table[i][j] b = table[i][1] p = GetPercent(b, c, self.bad_result) row.append(p) pct_table.append(row) return pct_table def FormatFloat(self, c, max_length=8): if not IsFloat(c): return c f = float(c) ret = HumanizeFloat(f, 4) ret = RemoveTrailingZeros(ret) if len(ret) > max_length: ret = '%1.1ef' % f return ret def TransposeTable(self, table): transposed_table = [] for i in range(len(table[0])): row = [] for j in range(len(table)): row.append(table[j][i]) transposed_table.append(row) return transposed_table def GetTableLabels(self, table): ret = '' header = table[0] for i in range(1, len(header)): ret += '%d: %s\n' % (i, header[i]) return ret def GetFormattedTable(self, table, transposed=False, first_column_width=30, column_width=14, percents_only=True, fit_string=True): o = '' pct_table = self.GetTablePercents(table) if transposed == True: table = self.TransposeTable(table) pct_table = self.TransposeTable(table) for i in range(0, len(table)): for j in range(len(table[0])): if j == 0: width = first_column_width else: width = column_width c = table[i][j] p = pct_table[i][j] # Replace labels with numbers: 0... n if IsFloat(c): c = self.FormatFloat(c) if IsFloat(p) and not percents_only: p = '%s%%' % p # Print percent values side by side. if j != 0: if percents_only: c = '%s' % p else: c = '%s (%s)' % (c, p) if i == 0 and j != 0: c = str(j) if fit_string: o += FitString(c, width) + self.d else: o += c + self.d o += '\n' return o def GetGroups(self, table): labels = table[0] groups = [] group_dict = {} for i in range(1, len(labels)): label = labels[i] stripped_label = self.GetStrippedLabel(label) if stripped_label not in group_dict: group_dict[stripped_label] = len(groups) groups.append([]) groups[group_dict[stripped_label]].append(i) return groups def GetSummaryTableValues(self, table): # First get the groups groups = self.GetGroups(table) summary_table = [] labels = table[0] summary_labels = ['Summary Table'] for group in groups: label = labels[group[0]] stripped_label = self.GetStrippedLabel(label) group_label = '%s (%d runs)' % (stripped_label, len(group)) summary_labels.append(group_label) summary_table.append(summary_labels) for i in range(1, len(table)): row = table[i] summary_row = [row[0]] for group in groups: group_runs = [] for index in group: group_runs.append(row[index]) group_run = self.AggregateResults(group_runs) summary_row.append(group_run) summary_table.append(summary_row) return summary_table # Drop N% slowest and M% fastest numbers, and return arithmean of # the remaining. @staticmethod def AverageWithDrops(numbers, slow_percent=20, fast_percent=20): sorted_numbers = list(numbers) sorted_numbers.sort() num_slow = int(slow_percent / 100.0 * len(sorted_numbers)) num_fast = int(fast_percent / 100.0 * len(sorted_numbers)) sorted_numbers = sorted_numbers[num_slow:] if num_fast: sorted_numbers = sorted_numbers[:-num_fast] return numpy.average(sorted_numbers) @staticmethod def AggregateResults(group_results): ret = '' if not group_results: return ret all_floats = True all_passes = True all_fails = True for group_result in group_results: if not IsFloat(group_result): all_floats = False if group_result != 'PASSED': all_passes = False if group_result != 'FAILED': all_fails = False if all_floats == True: float_results = [float(v) for v in group_results] ret = '%f' % TableFormatter.AverageWithDrops(float_results) # Add this line for standard deviation. ### ret += " %f" % numpy.std(float_results) elif all_passes == True: ret = 'ALL_PASS' elif all_fails == True: ret = 'ALL_FAILS' return ret @staticmethod def GetStrippedLabel(label): return re.sub('\s*\S+:\S+\s*', '', label) ### return re.sub("\s*remote:\S*\s*i:\d+$", "", label) @staticmethod def GetLabelWithIteration(label, iteration): return '%s i:%d' % (label, iteration)