aboutsummaryrefslogtreecommitdiffstats
path: root/bench/bench_util.py
diff options
context:
space:
mode:
Diffstat (limited to 'bench/bench_util.py')
-rw-r--r--bench/bench_util.py178
1 files changed, 178 insertions, 0 deletions
diff --git a/bench/bench_util.py b/bench/bench_util.py
new file mode 100644
index 0000000..e36e6c6
--- /dev/null
+++ b/bench/bench_util.py
@@ -0,0 +1,178 @@
+'''
+Created on May 19, 2011
+
+@author: bungeman
+'''
+
+import re
+import math
+
+class BenchDataPoint:
+ """A single data point produced by bench.
+
+ (str, str, str, float, {str:str})"""
+ def __init__(self, bench, config, time_type, time, settings):
+ self.bench = bench
+ self.config = config
+ self.time_type = time_type
+ self.time = time
+ self.settings = settings
+
+ def __repr__(self):
+ return "BenchDataPoint(%s, %s, %s, %s, %s)" % (
+ str(self.bench),
+ str(self.config),
+ str(self.time_type),
+ str(self.time),
+ str(self.settings),
+ )
+
+class _ExtremeType(object):
+ """Instances of this class compare greater or less than other objects."""
+ def __init__(self, cmpr, rep):
+ object.__init__(self)
+ self._cmpr = cmpr
+ self._rep = rep
+
+ def __cmp__(self, other):
+ if isinstance(other, self.__class__) and other._cmpr == self._cmpr:
+ return 0
+ return self._cmpr
+
+ def __repr__(self):
+ return self._rep
+
+Max = _ExtremeType(1, "Max")
+Min = _ExtremeType(-1, "Min")
+
+def parse(settings, lines):
+ """Parses bench output into a useful data structure.
+
+ ({str:str}, __iter__ -> str) -> [BenchDataPoint]"""
+
+ benches = []
+ current_bench = None
+ setting_re = '([^\s=]+)(?:=(\S+))?'
+ settings_re = 'skia bench:((?:\s+' + setting_re + ')*)'
+ bench_re = 'running bench (?:\[\d+ \d+\] )?\s*(\S+)'
+ time_re = '(?:(\w*)msecs = )?\s*(\d+\.\d+)'
+ config_re = '(\S+): ((?:' + time_re + '\s+)+)'
+
+ for line in lines:
+
+ #see if this line is a settings line
+ settingsMatch = re.search(settings_re, line)
+ if (settingsMatch):
+ settings = dict(settings)
+ for settingMatch in re.finditer(setting_re, settingsMatch.group(1)):
+ if (settingMatch.group(2)):
+ settings[settingMatch.group(1)] = settingMatch.group(2)
+ else:
+ settings[settingMatch.group(1)] = True
+
+ #see if this line starts a new bench
+ new_bench = re.search(bench_re, line)
+ if new_bench:
+ current_bench = new_bench.group(1)
+
+ #add configs on this line to the current bench
+ if current_bench:
+ for new_config in re.finditer(config_re, line):
+ current_config = new_config.group(1)
+ times = new_config.group(2)
+ for new_time in re.finditer(time_re, times):
+ current_time_type = new_time.group(1)
+ current_time = float(new_time.group(2))
+ benches.append(BenchDataPoint(
+ current_bench
+ , current_config
+ , current_time_type
+ , current_time
+ , settings))
+
+ return benches
+
+class LinearRegression:
+ """Linear regression data based on a set of data points.
+
+ ([(Number,Number)])
+ There must be at least two points for this to make sense."""
+ def __init__(self, points):
+ n = len(points)
+ max_x = Min
+ min_x = Max
+
+ Sx = 0.0
+ Sy = 0.0
+ Sxx = 0.0
+ Sxy = 0.0
+ Syy = 0.0
+ for point in points:
+ x = point[0]
+ y = point[1]
+ max_x = max(max_x, x)
+ min_x = min(min_x, x)
+
+ Sx += x
+ Sy += y
+ Sxx += x*x
+ Sxy += x*y
+ Syy += y*y
+
+ B = (n*Sxy - Sx*Sy) / (n*Sxx - Sx*Sx)
+ a = (1.0/n)*(Sy - B*Sx)
+
+ se2 = 0
+ sB2 = 0
+ sa2 = 0
+ if (n >= 3):
+ se2 = (1.0/(n*(n-2)) * (n*Syy - Sy*Sy - B*B*(n*Sxx - Sx*Sx)))
+ sB2 = (n*se2) / (n*Sxx - Sx*Sx)
+ sa2 = sB2 * (1.0/n) * Sxx
+
+
+ self.slope = B
+ self.intercept = a
+ self.serror = math.sqrt(max(0, se2))
+ self.serror_slope = math.sqrt(max(0, sB2))
+ self.serror_intercept = math.sqrt(max(0, sa2))
+ self.max_x = max_x
+ self.min_x = min_x
+
+ def __repr__(self):
+ return "LinearRegression(%s, %s, %s, %s, %s)" % (
+ str(self.slope),
+ str(self.intercept),
+ str(self.serror),
+ str(self.serror_slope),
+ str(self.serror_intercept),
+ )
+
+ def find_min_slope(self):
+ """Finds the minimal slope given one standard deviation."""
+ slope = self.slope
+ intercept = self.intercept
+ error = self.serror
+ regr_start = self.min_x
+ regr_end = self.max_x
+ regr_width = regr_end - regr_start
+
+ if slope < 0:
+ lower_left_y = slope*regr_start + intercept - error
+ upper_right_y = slope*regr_end + intercept + error
+ return min(0, (upper_right_y - lower_left_y) / regr_width)
+
+ elif slope > 0:
+ upper_left_y = slope*regr_start + intercept + error
+ lower_right_y = slope*regr_end + intercept - error
+ return max(0, (lower_right_y - upper_left_y) / regr_width)
+
+ return 0
+
+def CreateRevisionLink(revision_number):
+ """Returns HTML displaying the given revision number and linking to
+ that revision's change page at code.google.com, e.g.
+ http://code.google.com/p/skia/source/detail?r=2056
+ """
+ return '<a href="http://code.google.com/p/skia/source/detail?r=%s">%s</a>'%(
+ revision_number, revision_number)