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 resources.libraries.python import jumpavg
32 """Return middle two quartiles, hoping to reduce influence of outliers.
34 Currently "middle two" is "all", but that can change in future.
36 :param value_list: List to pick subset from.
37 :type value_list: list of float
38 :returns: New list containing middle values.
41 tmp = sorted(value_list)
43 ret = tmp[3*eight:-eight]
48 parent_iterations = list()
49 current_iterations = list()
54 current_lines = list()
55 filename = f"csit_parent/{iteration}/results.txt"
57 with open(filename) as parent_file:
58 parent_lines = parent_file.readlines()
61 num_lines = len(parent_lines)
62 filename = f"csit_current/{iteration}/results.txt"
63 with open(filename) as current_file:
64 current_lines = current_file.readlines()
65 if num_lines != len(current_lines):
66 print(f"Number of tests does not match within iteration {iteration}")
70 elif num_tests != num_lines:
72 f"Number of tests does not match previous at iteration {iteration}"
75 parent_iterations.append(parent_lines)
76 current_iterations.append(current_lines)
78 for test_index in range(num_tests):
79 parent_values = list()
80 current_values = list()
81 for iteration_index in range(len(parent_iterations)):
83 json.loads(parent_iterations[iteration_index][test_index])
85 current_values.extend(
86 json.loads(current_iterations[iteration_index][test_index])
88 print(f"Time-ordered MRR values for parent build: {parent_values}")
89 print(f"Time-ordered MRR values for current build: {current_values}")
90 parent_values = hack(parent_values)
91 current_values = hack(current_values)
92 max_value = max([1.0] + parent_values + current_values)
93 parent_stats = jumpavg.AvgStdevStats.for_runs(parent_values)
94 current_stats = jumpavg.AvgStdevStats.for_runs(current_values)
95 parent_group_list = jumpavg.BitCountingGroupList(
96 max_value=max_value).append_group_of_runs([parent_stats])
97 combined_group_list = parent_group_list.copy().extend_runs_to_last_group(
99 separated_group_list = parent_group_list.append_group_of_runs(
101 print(f"Value-ordered MRR values for parent build: {parent_values}")
102 print(f"Value-ordered MRR values for current build: {current_values}")
103 avg_diff = (current_stats.avg - parent_stats.avg) / parent_stats.avg
104 print(f"Difference of averages relative to parent: {100 * avg_diff}%")
105 print(f"Jumpavg representation of parent group: {parent_stats}")
106 print(f"Jumpavg representation of current group: {current_stats}")
108 f"Jumpavg representation of both as one group:"
109 f" {combined_group_list[0].stats}"
111 bits_diff = separated_group_list.bits - combined_group_list.bits
112 compared = u"longer" if bits_diff >= 0 else u"shorter"
114 f"Separate groups are {compared} than single group"
115 f" by {abs(bits_diff)} bits"
117 # TODO: Version of classify that takes max_value and list of stats?
118 # That matters if only stats (not list of floats) are given.
119 classified_list = jumpavg.classify([parent_values, current_values])
120 if len(classified_list) < 2:
121 print(f"Test test_index {test_index}: normal (no anomaly)")
123 anomaly = classified_list[1].comment
124 if anomaly == u"regression":
125 print(f"Test test_index {test_index}: anomaly regression")
126 exit_code = 3 # 1 or 2 can be caused by other errors
128 print(f"Test test_index {test_index}: anomaly {anomaly}")
129 print(f"Exit code: {exit_code}")