1 # Copyright (c) 2019 Cisco and/or its affiliates.
2 # Licensed under the Apache License, Version 2.0 (the "License");
3 # you may not use this file except in compliance with the License.
4 # You may obtain a copy of the License at:
6 # http://www.apache.org/licenses/LICENSE-2.0
8 # Unless required by applicable law or agreed to in writing, software
9 # distributed under the License is distributed on an "AS IS" BASIS,
10 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 # See the License for the specific language governing permissions and
12 # limitations under the License.
14 """Script for determining whether per-patch perf test votes -1.
16 This script assumes there exist two text files with processed BMRR results,
17 located at hardcoded relative paths (subdirs thereof), having several lines
18 of json-parseable lists of float values, corresponding to testcase results.
19 This script then uses jumpavg library to determine whether there was
20 a regression, progression or no change for each testcase.
21 If number of tests does not match, or there was a regression,
22 this script votes -1 (by exiting with code 1), otherwise it votes +1 (exit 0).
28 from jumpavg.BitCountingMetadataFactory import BitCountingMetadataFactory
29 from jumpavg.BitCountingClassifier import BitCountingClassifier
33 """Return middle two quartiles, hoping to reduce influence of outliers.
35 Currently "middle two" is "all", but that can change in future.
37 :param value_list: List to pick subset from.
38 :type value_list: list of float
39 :returns: New list containing middle values.
42 tmp = sorted(value_list)
44 ret = tmp[3*eight:-eight]
49 parent_iterations = list()
50 current_iterations = list()
55 current_lines = list()
56 filename = f"csit_parent/{iteration}/results.txt"
58 with open(filename) as parent_file:
59 parent_lines = parent_file.readlines()
62 num_lines = len(parent_lines)
63 filename = f"csit_current/{iteration}/results.txt"
64 with open(filename) as current_file:
65 current_lines = current_file.readlines()
66 if num_lines != len(current_lines):
67 print(f"Number of tests does not match within iteration {iteration}")
71 elif num_tests != num_lines:
73 f"Number of tests does not match previous at iteration {iteration}"
76 parent_iterations.append(parent_lines)
77 current_iterations.append(current_lines)
78 classifier = BitCountingClassifier()
80 for test_index in range(num_tests):
82 parent_values = list()
83 current_values = list()
84 for iteration_index in range(len(parent_iterations)):
86 json.loads(parent_iterations[iteration_index][test_index])
88 current_values.extend(
89 json.loads(current_iterations[iteration_index][test_index])
91 print(f"Time-ordered MRR values for parent build: {parent_values}")
92 print(f"Time-ordered MRR values for current build: {current_values}")
93 parent_values = hack(parent_values)
94 current_values = hack(current_values)
95 parent_max = BitCountingMetadataFactory.find_max_value(parent_values)
96 current_max = BitCountingMetadataFactory.find_max_value(current_values)
97 val_max = max(val_max, parent_max, current_max)
98 factory = BitCountingMetadataFactory(val_max)
99 parent_stats = factory.from_data(parent_values)
100 current_factory = BitCountingMetadataFactory(val_max, parent_stats.avg)
101 current_stats = current_factory.from_data(current_values)
102 both_stats = factory.from_data(parent_values + current_values)
103 print(f"Value-ordered MRR values for parent build: {parent_values}")
104 print(f"Value-ordered MRR values for current build: {current_values}")
105 difference = (current_stats.avg - parent_stats.avg) / parent_stats.avg
106 print(f"Difference of averages relative to parent: {100 * difference}%")
107 print(f"Jumpavg representation of parent group: {parent_stats}")
108 print(f"Jumpavg representation of current group: {current_stats}")
109 print(f"Jumpavg representation of both as one group: {both_stats}")
110 bits = parent_stats.bits + current_stats.bits - both_stats.bits
111 compared = u"longer" if bits >= 0 else u"shorter"
113 f"Separate groups are {compared} than single group by {abs(bits)} bits"
115 classified_list = classifier.classify([parent_stats, current_stats])
116 if len(classified_list) < 2:
117 print(f"Test test_index {test_index}: normal (no anomaly)")
119 anomaly = classified_list[1].metadata.classification
120 if anomaly == u"regression":
121 print(f"Test test_index {test_index}: anomaly regression")
124 print(f"Test test_index {test_index}: anomaly {anomaly}")
125 print(f"Exit code {exit_code}")