1# Copyright 2015 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Contains experimental alerting functions."""
6
7from dashboard import find_change_points
8from dashboard.models import anomaly_config
9
10
11def RunFindChangePoints(
12    test, series, find_change_points_func=find_change_points.FindChangePoints,
13    **kwargs):
14  """Runs an change-point-finding function on part of a data series.
15
16  This function will be repeatedly called by SimulateAlertProcessingPipeline
17  in the bench_find_change_points module with the same Test entity but with more
18  and more points added to the end.
19
20  This is meant to imitate the current behavior of FindChangePoints on the perf
21  dashboard.
22
23  Args:
24    test: A graph_data.Test entity.
25    series: A list of ordered (x, y) pairs.
26    find_change_points_func: A function that has the same interface as
27        find_change_points.FindChangePoints.
28    **kwargs: Extra parameters to add to the anomaly config dict.
29
30  Returns:
31    A list of objects with the property x_value.
32  """
33  # The anomaly threshold config dictionary determines how many points are
34  # analyzed and how far apart alerts should be, as well as other thresholds.
35  config = anomaly_config.GetAnomalyConfigDict(test)
36  config.update(kwargs)
37
38  # |series| contains all data so far in the Test, but typically when
39  # a test is processed (in find_anomalies.ProcessTest) only the last "window"
40  # of points is looked at. This window size depends on the test. To get the
41  # same behavior as the current default, we take only the last window.
42  series = _GetLastWindow(series, config.get('max_window_size'))
43  if len(series) < 2:
44    return []
45
46  # Find anomalies for the requested test.
47  change_points = find_change_points_func(series, **config)
48
49  return _RemoveKnownAnomalies(test, change_points)
50
51
52def _GetLastWindow(series, window_size):
53  """Returns the last "window" of points in the data series."""
54  if not window_size:
55    return series
56  return series[-window_size:]
57
58
59def _RemoveKnownAnomalies(test, change_points):
60  """Removes some anomalies and updates the given Test entity.
61
62  Args:
63    test: A Test entity, which has a property last_alerted_revision.
64        This property will be updated when this function is called.
65    change_points: A list of find_change_points.ChangePoint objects. It is
66        assumed that this list is sorted by the x_value property.
67
68  Returns:
69    A list of objects with the property x_value.
70  """
71  # Avoid duplicates.
72  if test.last_alerted_revision:
73    change_points = [c for c in change_points
74                     if c.x_value > test.last_alerted_revision]
75
76  if change_points:
77    # No need to call put(). The given Test entity will be re-used and we don't
78    # want to modify Test entity in the datastore.
79    test.last_alerted_revision = change_points[-1].x_value
80
81  return change_points
82
83
84def FindChangePointsWithAbsoluteChangeThreshold(test, series):
85  """Runs FindChangePoints, always setting an absolute change threshold."""
86  return RunFindChangePoints(
87      test, series,
88      max_window_size=50,
89      multiple_of_std_dev=3.5,
90      min_relative_change=0.1,
91      min_absolute_change=1.0,
92      min_segment_size=6)
93