blob: 2157a4304facadec2a0e29f6b93193ded7f8dc4e [file] [log] [blame]
# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Functions called to analyze perf data for regressions."""
import logging
import external.stats as stats
from dash_view import AutotestDashView
class StatsFunctions(object):
"""Class to contain and invoke statistics functions."""
def __init__(self):
self._dash_view = AutotestDashView()
def Invoke(self, function_name, params, vals, build):
"""Dispatch function and return True if failed."""
if not hasattr(self, function_name):
logging.debug('Stats function %s not found.', function_name)
return False
if build not in vals:
logging.debug('Build %s not found in vals %s.', build, vals.keys())
return False
return getattr(self, function_name)(params, vals, build)
def _Averages(self, vals, build):
"""Calculate averages for one build and all days."""
build_mean = 0.0
build_nsamples = 0
previous_mean = 0.0
previous_nsamples = 0
mean_list = []
sum_nsamples = 0
# Loop through each build with values.
for seq in vals:
value_list = vals[seq][0]
mean_value = stats.lmean(value_list)
if build == seq:
build_mean = mean_value
build_nsamples = len(value_list)
else:
mean_list.append(mean_value)
sum_nsamples += len(value_list)
# Average over all builds prior to and not including this build.
if mean_list:
historical_mean = stats.lmean(mean_list)
historical_samples = sum_nsamples / len(mean_list)
else:
historical_mean = 0.0
historical_samples = 0
results = {
'build_mean': build_mean,
'build_samples': build_nsamples,
'historical_mean': historical_mean,
'historical_samples': historical_samples}
return results
def PrintAverages(self, params, vals, build):
"""Always returns True - for regular summaries."""
data_statistics = self._Averages(vals, build)
return True, data_statistics
def PrintStats(self, params, vals, build):
"""Always returns True - for detailed summaries."""
value_list = vals[build][0]
stats_lstdev = 0.0
stats_lmed = value_list[0]
if len(value_list) > 1:
stats_lstdev = stats.lstdev(value_list)
stats_lmed = stats.lmedianscore(value_list)
# This is a 'sample standard deviation'.
data_statistics = {
'build_sample_stdev': stats_lstdev,
'build_median_value': stats_lmed}
return True, data_statistics
def PrintHistogram(self, params, vals, build):
"""Always returns True - for detailed summaries."""
numbins = params['numbins']
limits = params['limits']
bins, lowbin, binsize, lowpoints, highpoints = stats.lhistogram(
vals[build][0], numbins, limits)
data_array = []
if lowpoints:
data_array.append((lowpoints, 0, round(lowbin, 2)))
for i in xrange(len(bins)):
data_array.append((
bins[i],
round(lowbin+(binsize*i), 2),
round(lowbin+(binsize*i)+binsize, 2)))
if highpoints:
data_array.append((highpoints, lowbin+binsize*len(bins), '...'))
data_statistics = {
'histogram': {
'data': data_array,
'height': params['height'],
'width': params['width']}}
return True, data_statistics
def PrintIterations(self, params, vals, build):
"""Always returns True - for detailed summaries."""
value_list = vals[build][0]
test_idxes = vals[build][1]
if len(value_list) <= 1:
return False, {}
iterations = vals[build][2]
list_len = len(value_list)
if not list_len == len(iterations):
logging.warning('KeyVals without matching iterations on build %s.', build)
return False, {}
previous_iteration = 0 # Autotest iterations are 1-based.
i = 1
column_array = [(
vals[build][3][0],
self._dash_view.GetTestFromIdx(test_idxes[0])['tag'])]
value_array = []
known_iterations = set()
for j in xrange(list_len):
iteration = iterations[j]
value = value_list[j]
if iteration <= previous_iteration:
i += 1
column_array.append((
vals[build][3][j],
self._dash_view.GetTestFromIdx(test_idxes[j])['tag']))
if not iteration in known_iterations:
value_array.append((iteration-1, 0, iteration))
known_iterations.add(iteration)
value_array.append((iteration-1, i, value))
previous_iteration = iteration
data_statistics = {
'values': {
'column_names': column_array,
'rowcount': len(known_iterations),
'data': value_array,
'height': params['height'],
'width': params['width']}}
return True, data_statistics
def OverAverage(self, params, vals, build):
"""Returns True if build average is > overall average."""
data_statistics = self._Averages(vals, build)
build_avg, _, overall_avg, _ = data_statistics
return build_avg > overall_avg, data_statistics
def OverThreshhold(self, params, vals, build):
"""Returns True if latest build is > threshhold."""
data_statistics = self._Averages(vals, build)
build_avg, _, _, _ = data_statistics
return build_avg > float(params), data_statistics
def UnderThreshhold(self, params, vals, build):
"""Returns True if latest build is < threshhold."""
data_statistics = self._Averages(vals, build)
build_avg, _, _, _ = data_statistics
return build_avg < float(params), data_statistics