blob: b3b82f094ab6a966cb48608b44f4f0affccdb3c5 [file] [log] [blame]
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)