Revert "fix(jobspec): Delete ipsec nfv density tests"
[csit.git] / resources / libraries / bash / entry / bisect.sh
1 #!/usr/bin/env bash
2
3 # Copyright (c) 2023 Cisco and/or its affiliates.
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at:
7 #
8 #     http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15
16 set -exuo pipefail
17
18 # This entry script does not change which CSIT branch is used,
19 # use "with_oper_for_vpp.sh" wrapper for that.
20 #
21 # This script is to be used for locating performance regressions
22 # (or breakages, or progressions, or fixes).
23 # It uses "git bisect" commands on the VPP repository,
24 # between the triggered VPP patch and a commit specified in the first argument
25 # of the gerrit comment text.
26 # The other arguments are used as tag expressions for selecting tests as usual.
27 # Many different result types are supported.
28 #
29 # Logs are present in the archive directory, but usually the main output
30 # is the offending commit as identified by "git bisect", visible in console.
31 #
32 # While selecting just one testcase is the intended use,
33 # this script should be able to deal with multiple testcases as well,
34 # grouping all the values together. This usually inflates
35 # the standard deviation, but it is not clear how that affects the bisection.
36 #
37 # For the bisection decision, jumpavg library is used,
38 # deciding whether shorter description is achieved by forcefully grouping
39 # the middle results with the old, or with the new ones.
40 # If the shortest description is achieved with 3 separate groups,
41 # bisect interval focuses on biggest relative change
42 # (with respect to pairwise maximum).
43 #
44 # If a test fails, an artificial result is used to distinguish
45 # from normal results. Currently, the value 1.0, with the multiplicity of 4.
46 #
47 # Note that if there was a VPP API change that affects tests in the interval,
48 # there frequently is no good way for single CSIT commit to work there.
49 # You can try manually reverting the CSIT changes to make tests pass,
50 # possibly needing to search over multiple subintervals.
51 # Using and older CSIT commit (possibly cherry-picking the bisect Change
52 # if it was not present in CSIT compatible with old enough VPP builds)
53 # is the fastest solution; but beware of CSIT-induced performance effects
54 # (e.g. TRex settings).
55 #
56 # If a regression happens during a subinterval where the test fails
57 # due to a bug in VPP, you may try to create a new commit chain
58 # with the fix cherry-picked to the start of the interval.
59 # Do not do that as a chain in Gerrit, it would be long and Gerrit will refuse
60 # edits of already merged Changes.
61 # Instead, add a block of bash code to do the manipulation
62 # on local git history between checkout and bisect.
63 #
64 # At the start, the script executes first bisect iteration in an attempt
65 # to avoid work if the search interval has only one commit (or is invalid).
66 # Only when the work is needed, earliest and latest commits are built
67 # and tested. Branches "earliest", "middle" and "latest" are temporarily created
68 # as a way to remember which commits to check out.
69 #
70 # Test results are parsed from json files,
71 # symlinks are used to tell python script which results to compare.
72 #
73 # Assumptions:
74 # + There is a directory holding VPP repo with patch under test checked out.
75 # + It contains csit subdirectory with CSIT code to use (this script is there).
76 # + Everything needed to build VPP is already installed locally.
77 # Consequences:
78 # + Working directory is switched to the VPP repo root.
79 # + At the end, VPP repo has checked out and built some commit,
80 #   as chosen by "git bisect".
81 # + Directories build_root, build and csit are reset during the run.
82 # + The following directories (relative to VPP repo) are (re)created:
83 # ++ csit_{earliest,middle,latest}, build_{earliest,latest},
84 # ++ archive, csit/archive, csit/download_dir.
85 # + Symlinks csit_{early,late,mid} are also created.
86 # Arguments:
87 # - ${1} - If present, override JOB_NAME to simplify manual usage.
88
89 # "set -eu" handles failures from the following two lines.
90 BASH_ENTRY_DIR="$(dirname $(readlink -e "${BASH_SOURCE[0]}"))"
91 BASH_FUNCTION_DIR="$(readlink -e "${BASH_ENTRY_DIR}/../function")"
92 source "${BASH_FUNCTION_DIR}/common.sh" || {
93     echo "Source failed." >&2
94     exit 1
95 }
96 source "${BASH_FUNCTION_DIR}/per_patch.sh" || die "Source failed."
97 # Cleanup needs ansible.
98 source "${BASH_FUNCTION_DIR}/ansible.sh" || die "Source failed."
99 common_dirs || die
100 check_prerequisites || die
101 set_perpatch_vpp_dir || die
102 get_test_code "${1-}" || die
103 get_test_tag_string || die
104 # Unfortunately, git bisect only works at the top of the repo.
105 cd "${VPP_DIR}" || die
106
107 # Save the current commit.
108 git checkout -b "latest"
109 # Save the lower bound commit.
110 git checkout -b "earliest"
111 git reset --hard "${GIT_BISECT_FROM}"
112
113 # This is the place for custom code manipulating local git history.
114
115 #git checkout -b "alter"
116 #...
117 #git checkout "latest"
118 #git rebase "alter" || git rebase --skip
119 #git branch -D "alter"
120
121 git bisect start || die
122 # TODO: Can we add a trap for "git bisect reset" or even "deactivate",
123 # without affecting the inner trap for unreserve and cleanup?
124 git checkout "latest"
125 git status || die
126 git describe || die
127 git bisect new || die
128 # Performing first iteration early to avoid testing or even building.
129 git checkout "earliest" || die "Failed to checkout earliest commit."
130 git status || die
131 git describe || die
132 # The first iteration.
133 git bisect old | tee "git.log" || die "Invalid bisect interval?"
134 git checkout -b "middle" || die "Failed to create branch: middle"
135 git status || die
136 git describe || die
137 if head -n 1 "git.log" | cut -b -11 | fgrep -q "Bisecting:"; then
138     echo "Building and testing initial bounds."
139 else
140     echo "Single commit, no work needed."
141     exit 0
142 fi
143 # Building latest first, good for avoiding DPDK rebuilds.
144 git checkout "latest" || die "Failed to checkout latest commit."
145 build_vpp_ubuntu "LATEST" || die
146 set_aside_build_artifacts "latest" || die
147 git checkout "earliest" || die "Failed to checkout earliest commit."
148 git status || die
149 git describe || die
150 build_vpp_ubuntu "EARLIEST" || die
151 set_aside_build_artifacts "earliest" || die
152 git checkout "middle" || die "Failed to checkout middle commit."
153 git branch -D "earliest" "latest" || die "Failed to remove branches."
154 # Done with repo manipulation for now, testing commences.
155 initialize_csit_dirs "earliest" "middle" "latest" || die
156 set_perpatch_dut || die
157 select_topology || die
158 select_arch_os || die
159 activate_virtualenv "${VPP_DIR}" || die
160 generate_tests || die
161 archive_tests || die
162
163 # TODO: Does it matter which build is tested first?
164
165 select_build "build_earliest" || die
166 check_download_dir || die
167 reserve_and_cleanup_testbed || die
168 run_robot || die
169 move_test_results "csit_earliest" || die
170 ln -s -T "csit_earliest" "csit_early" || die
171
172 # Explicit cleanup, in case the previous test left the testbed in a bad shape.
173 ansible_playbook "cleanup"
174
175 select_build "build_latest" || die
176 check_download_dir || die
177 run_robot || die
178 move_test_results "csit_latest" || die
179 ln -s -T "csit_latest" "csit_late" || die
180 untrap_and_unreserve_testbed || die
181
182 # See function documentation for the logic in the loop.
183 main_bisect_loop || die
184 # In worst case, the middle branch is still checked out.
185 # TODO: Is there a way to ensure "middle" branch is always deleted?
186 git branch -D "middle" || true
187 # Delete symlinks to prevent duplicate archiving.
188 rm -vrf "csit_early" "csit_late" "csit_mid"