xref: /aosp_15_r20/external/toolchain-utils/binary_search_tool/MAINTENANCE (revision 760c253c1ed00ce9abd48f8546f08516e57485fe)
1*760c253cSXin Li# Copyright 2020 The ChromiumOS Authors
2*760c253cSXin Li# Use of this source code is governed by a BSD-style license that can be
3*760c253cSXin Li# found in the LICENSE file.
4*760c253cSXin Li
5*760c253cSXin LiThis document is for future maintainers of the binary search/bisection tools.
6*760c253cSXin Li
7*760c253cSXin LiAuthors:
8*760c253cSXin Li  * Original Tool: asharif@, llozano@, cmtice@
9*760c253cSXin Li  * Updates after May 2016: cburden@
10*760c253cSXin Li  * chromeos-toolchain@
11*760c253cSXin Li
12*760c253cSXin LiThe following are good reference materials on how the tool works:
13*760c253cSXin Li  * Ahmad's original presentation:
14*760c253cSXin Li    https://goto.google.com/zxdfyi
15*760c253cSXin Li
16*760c253cSXin Li  * Bisection tool update design doc:
17*760c253cSXin Li    https://goto.google.com/zcwei
18*760c253cSXin Li
19*760c253cSXin Li  * Bisection tool webpage:
20*760c253cSXin Li    https://goto.google.com/ruwpyi
21*760c253cSXin Li
22*760c253cSXin Li  * Compiler wrapper webpage:
23*760c253cSXin Li    https://goto.google.com/xossn
24*760c253cSXin Li
25*760c253cSXin Li
26*760c253cSXin LiTESTING:
27*760c253cSXin LiAll unit tests live under the ./test directory. However, these tests
28*760c253cSXin Lispecifically test binary_search_state.py, binary_search_perforce.py,
29*760c253cSXin Lirun_bisect.py.
30*760c253cSXin Li
31*760c253cSXin LiThese unit tests will not test the specific logic for ChromeOS/Android
32*760c253cSXin Libisection. To test the ChromeOS/Android bisectors, use the common/hash_test.sh
33*760c253cSXin Litest. This is a simple test case that just checks the hashes of files on your
34*760c253cSXin Lifile system. This means you won't have to find a specific compiler error for
35*760c253cSXin Lithe bisector to triage in order to test each bisector.
36*760c253cSXin Li
37*760c253cSXin LiTODO:
38*760c253cSXin LiThe bisection tool (I believe) is in a fairly good state. So these are mostly
39*760c253cSXin Liwishlist items and things that could use some improvement.
40*760c253cSXin Li
41*760c253cSXin Li  1. Get rid of binary_search_perforce.py. This file is mostly legacy code and
42*760c253cSXin Li     the majority of it isn't even used to bisect object files. The file was
43*760c253cSXin Li     originally intended to bisect CLs, and binary_search_state.py just reused
44*760c253cSXin Li     the binary searching logic from it. Maybe just extract the binary searching
45*760c253cSXin Li     logic from binary_search_perforce.py and put it in its own module in
46*760c253cSXin Li     cros_utils?
47*760c253cSXin Li
48*760c253cSXin Li  2. Cleanup unit tests in ./test. These tests are a little hacked together,
49*760c253cSXin Li     and are all under one test suite. Maybe consider organizing them across
50*760c253cSXin Li     multiple directories.
51*760c253cSXin Li
52*760c253cSXin Li  3. Create a "checkout setup" system for bisection. Currently if you want to
53*760c253cSXin Li     bisect, you have to run scripts/edit sources in this repo. Ideally these
54*760c253cSXin Li     scripts would be static, and if you wanted to bisect/make changes you would
55*760c253cSXin Li     "checkout" or copy all the scripts to a working directory and have a unique
56*760c253cSXin Li     working directory for each bisection. Credits to Luis for this idea =)
57*760c253cSXin Li
58*760c253cSXin Li  4. Make all scripts relative to each other. Currently all scripts enforce the
59*760c253cSXin Li     idea that their cwd will be ./binary_search_tool/. But it would be less
60*760c253cSXin Li     confusing to have each script relative to each other. There's quite a few
61*760c253cSXin Li     stackoverflow topics on how to do this best, but each one has some sort of
62*760c253cSXin Li     downside or flaw.
63*760c253cSXin Li
64*760c253cSXin Li  5. Overall modularize code more, especially in binary_search_state.py
65*760c253cSXin Li
66*760c253cSXin LiDESIGN EXPLANATIONS:
67*760c253cSXin LiSome of the design decisions are a bit difficult to understand from just reading
68*760c253cSXin Lithe code unfortunately. I will attempt to clear up the major offenders of this:
69*760c253cSXin Li
70*760c253cSXin Li  1. common.py's argument dictionary:
71*760c253cSXin Li     binary_search_state.py and run_bisect.py both have to have near identical
72*760c253cSXin Li     arguments in order to support argument overriding in run_bisect.py. However
73*760c253cSXin Li     they do have to be slightly different. Mainly, run_bisect.py needs to have
74*760c253cSXin Li     no default values for arguments (so it can determine what's being
75*760c253cSXin Li     overriden).
76*760c253cSXin Li
77*760c253cSXin Li     In order to reduce huge amounts of code duplication for the argument
78*760c253cSXin Li     building, we put argument building in common.py. That way both modules
79*760c253cSXin Li     can reference the arguments, and they can have different configurations
80*760c253cSXin Li     across both.
81*760c253cSXin Li
82*760c253cSXin Li  2. Compiler wrapper:
83*760c253cSXin Li     The compiler wrapper is called before all compiler calls. It exists to
84*760c253cSXin Li     trick whatever build system (make, emerge, etc.) into thinking our
85*760c253cSXin Li     bisection is just a normal build, when really we're doing some tricks.
86*760c253cSXin Li
87*760c253cSXin Li     The biggest benefit the compiler wrapper gives is: knowing for sure which
88*760c253cSXin Li     files are actually generated by the compiler during bisection setup, and
89*760c253cSXin Li     potentially being able to skip compilations while triaging (speeding up the
90*760c253cSXin Li     triaging process significantly).
91*760c253cSXin Li
92*760c253cSXin Li  3. The weird options for the --verify, --verbose, --file_args, etc. arguments:
93*760c253cSXin Li     Some of the arguments for the bisection tool have a weird set of options
94*760c253cSXin Li     for the AddArgument method (nargs, const, default, StrToBool). This is so
95*760c253cSXin Li     we can make argument overriding workable. These options allow the following
96*760c253cSXin Li     functionality for a boolean argument (using --prune as an example):
97*760c253cSXin Li       * --prune (prune set to True)
98*760c253cSXin Li       * <not given> (prune set to False)
99*760c253cSXin Li       * --prune=True (prune set to True)
100*760c253cSXin Li       * --prune=False (prune set to False)
101*760c253cSXin Li
102*760c253cSXin Li     The first two are easy to implement (action='store_true'), but the last two
103*760c253cSXin Li     are why the extra weird arguments are required. Now, why would we want the
104*760c253cSXin Li     last two? Imagine if the Android bisector set --prune=True as a default
105*760c253cSXin Li     argument. With just the first two options above it would be impossible for
106*760c253cSXin Li     the user to override prune and set it to False. So the user needs the
107*760c253cSXin Li     --prune=False option. See the argparse documentation for more details.
108*760c253cSXin Li
109*760c253cSXin Li  4. General binary searching logic/pruning logic:
110*760c253cSXin Li     binary_search_state.py will enumerate all items into a list. The binary
111*760c253cSXin Li     search will find the *first* bad item (starting with lowest index).
112*760c253cSXin Li     Everything to the left of the "current" index is switched to good,
113*760c253cSXin Li     everything to right of the "current" index is switched to bad. Once a bad
114*760c253cSXin Li     item is found, it's put at the very end of the list.
115*760c253cSXin Li
116*760c253cSXin Li     If prune is set, the tool will continuing searching until all bad items are
117*760c253cSXin Li     found (instead of stopping after the first one). If the tool finds the same
118*760c253cSXin Li     item twice, that means no more bad items exist. This is because the item
119*760c253cSXin Li     was found, said item was put at the end of the list, and it was found
120*760c253cSXin Li     again. Because the binary search logic finds the bad item with the lowest
121*760c253cSXin Li     index, this means nothing in between the start of the list and the end of
122*760c253cSXin Li     the list is bad (thus no more bad items remain).
123