summaryrefslogtreecommitdiffstats
path: root/testing/talos/talos/filter.py
diff options
context:
space:
mode:
Diffstat (limited to 'testing/talos/talos/filter.py')
-rw-r--r--testing/talos/talos/filter.py264
1 files changed, 264 insertions, 0 deletions
diff --git a/testing/talos/talos/filter.py b/testing/talos/talos/filter.py
new file mode 100644
index 0000000000..833553139f
--- /dev/null
+++ b/testing/talos/talos/filter.py
@@ -0,0 +1,264 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import math
+
+import six
+
+"""
+data filters:
+takes a series of run data and applies statistical transforms to it
+
+Each filter is a simple function, but it also have attached a special
+`prepare` method that create a tuple with one instance of a
+:class:`Filter`; this allow to write stuff like::
+
+ from talos import filter
+ filters = filter.ignore_first.prepare(1) + filter.median.prepare()
+
+ for filter in filters:
+ data = filter(data)
+ # data is filtered
+"""
+
+_FILTERS = {}
+
+
+class Filter(object):
+ def __init__(self, func, *args, **kwargs):
+ """
+ Takes a filter function, and save args and kwargs that
+ should be used when the filter is used.
+ """
+ self.func = func
+ self.args = args
+ self.kwargs = kwargs
+
+ def apply(self, data):
+ """
+ Apply the filter on the data, and return the new data
+ """
+ return self.func(data, *self.args, **self.kwargs)
+
+
+def define_filter(func):
+ """
+ decorator to attach the prepare method.
+ """
+
+ def prepare(*args, **kwargs):
+ return (Filter(func, *args, **kwargs),)
+
+ func.prepare = prepare
+ return func
+
+
+def register_filter(func):
+ """
+ all filters defined in this module
+ should be registered
+ """
+ global _FILTERS
+
+ _FILTERS[func.__name__] = func
+ return func
+
+
+def filters(*args):
+ global _FILTERS
+
+ filters_ = [_FILTERS[filter] for filter in args]
+ return filters_
+
+
+def apply(data, filters):
+ for filter in filters:
+ data = filter(data)
+
+ return data
+
+
+def parse(string_):
+ def to_number(string_number):
+ try:
+ return int(string_number)
+ except ValueError:
+ return float(string_number)
+
+ tokens = string_.split(":")
+
+ func = tokens[0]
+ digits = []
+ if len(tokens) > 1:
+ digits.extend(tokens[1].split(","))
+ digits = [to_number(digit) for digit in digits]
+
+ return [func, digits]
+
+
+# filters that return a scalar
+
+
+@register_filter
+@define_filter
+def mean(series):
+ """
+ mean of data; needs at least one data point
+ """
+ return sum(series) / float(len(series))
+
+
+@register_filter
+@define_filter
+def median(series):
+ """
+ median of data; needs at least one data point
+ """
+ series = sorted(series)
+ if len(series) % 2:
+ # odd
+ return series[int(len(series) / 2)]
+ else:
+ # even
+ middle = int(len(series) / 2) # the higher of the middle 2, actually
+ return 0.5 * (series[middle - 1] + series[middle])
+
+
+@register_filter
+@define_filter
+def variance(series):
+ """
+ variance: http://en.wikipedia.org/wiki/Variance
+ """
+
+ _mean = mean(series)
+ variance = sum([(i - _mean) ** 2 for i in series]) / float(len(series))
+ return variance
+
+
+@register_filter
+@define_filter
+def stddev(series):
+ """
+ standard deviation: http://en.wikipedia.org/wiki/Standard_deviation
+ """
+ return variance(series) ** 0.5
+
+
+@register_filter
+@define_filter
+def dromaeo(series):
+ """
+ dromaeo: https://wiki.mozilla.org/Dromaeo, pull the internal calculation
+ out
+ * This is for 'runs/s' based tests, not 'ms' tests.
+ * chunksize: defined in dromaeo: tests/dromaeo/webrunner.js#l8
+ """
+ means = []
+ chunksize = 5
+ series = list(dromaeo_chunks(series, chunksize))
+ for i in series:
+ means.append(mean(i))
+ return geometric_mean(means)
+
+
+@register_filter
+@define_filter
+def dromaeo_chunks(series, size):
+ for i in six.moves.range(0, len(series), size):
+ yield series[i : i + size]
+
+
+@register_filter
+@define_filter
+def geometric_mean(series):
+ """
+ geometric_mean: http://en.wikipedia.org/wiki/Geometric_mean
+ """
+ total = 0
+ for i in series:
+ total += math.log(i + 1)
+ # pylint --py3k W1619
+ return math.exp(total / len(series)) - 1
+
+
+# filters that return a list
+
+
+@register_filter
+@define_filter
+def ignore_first(series, number=1):
+ """
+ ignore first datapoint
+ """
+ if len(series) <= number:
+ # don't modify short series
+ return series
+ return series[number:]
+
+
+@register_filter
+@define_filter
+def ignore(series, function):
+ """
+ ignore the first value of a list given by function
+ """
+ if len(series) <= 1:
+ # don't modify short series
+ return series
+ series = series[:] # do not mutate the original series
+ value = function(series)
+ series.remove(value)
+ return series
+
+
+@register_filter
+@define_filter
+def ignore_max(series):
+ """
+ ignore maximum data point
+ """
+ return ignore(series, max)
+
+
+@register_filter
+@define_filter
+def ignore_min(series):
+ """
+ ignore minimum data point
+ """
+ return ignore(series, min)
+
+
+@register_filter
+@define_filter
+def v8_subtest(series, name):
+ """
+ v8 benchmark score - modified for no sub benchmarks.
+ * removed Crypto and kept Encrypt/Decrypt standalone
+ * removed EarlyBoyer and kept Earley/Boyer standalone
+
+ this is not 100% in parity but within .3%
+ """
+ reference = {
+ "Encrypt": 266181.0,
+ "Decrypt": 266181.0,
+ "DeltaBlue": 66118.0,
+ "Earley": 666463.0,
+ "Boyer": 666463.0,
+ "NavierStokes": 1484000.0,
+ "RayTrace": 739989.0,
+ "RegExp": 910985.0,
+ "Richards": 35302.0,
+ "Splay": 81491.0,
+ }
+
+ # pylint --py3k W1619
+ return reference[name] / geometric_mean(series)
+
+
+@register_filter
+@define_filter
+def responsiveness_Metric(val_list):
+ return sum([float(x) * float(x) / 1000000.0 for x in val_list])