diff options
Diffstat (limited to 'pkg')
| -rw-r--r-- | pkg/bisect/bisect.go | 58 | ||||
| -rw-r--r-- | pkg/bisect/bisect_test.go | 62 | ||||
| -rw-r--r-- | pkg/vcs/linux.go | 32 | ||||
| -rw-r--r-- | pkg/vcs/vcs.go | 26 |
4 files changed, 150 insertions, 28 deletions
diff --git a/pkg/bisect/bisect.go b/pkg/bisect/bisect.go index 9ea5a6c04..8d83b0737 100644 --- a/pkg/bisect/bisect.go +++ b/pkg/bisect/bisect.go @@ -518,9 +518,12 @@ func (env *env) commitRangeForCause() (*vcs.Commit, *vcs.Commit, []*testResult, if len(tags) == 0 { return nil, nil, nil, fmt.Errorf("no release tags before this commit") } + pickedTags := pickReleaseTags(tags) + env.log("picked %d out of %d release tags", pickedTags) + lastBad := env.commit var results []*testResult - for _, tag := range tags { + for _, tag := range pickedTags { env.log("testing release %v", tag) com, err := env.repo.SwitchCommit(tag) if err != nil { @@ -1034,3 +1037,56 @@ func checkConfig(cfg *Config) error { func (env *env) log(msg string, args ...interface{}) { env.cfg.Trace.Log(msg, args...) } + +// pickReleaseTags() picks a subset of revisions to test. +// `all` is an ordered list of tags (from newer to older). +func pickReleaseTags(all []string) []string { + if len(all) == 0 { + return nil + } + // First split into x.y.z, x.y.z-1, ... and x.y, x.y-1, ... + var subReleases, releases []string + releaseBegin := false + for _, tag := range all { + v1, _, rc, v3 := vcs.ParseReleaseTag(tag) + if v1 < 0 || rc < 0 && v3 < 0 { + releaseBegin = true + releases = append(releases, tag) + } + if !releaseBegin { + subReleases = append(subReleases, tag) + } + } + var ret []string + // Take 2 latest sub releases. + takeSubReleases := minInts(2, len(subReleases)) + ret = append(ret, subReleases[:takeSubReleases]...) + // If there are a lot of sub releases, also take the middle one. + if len(subReleases) > 5 { + ret = append(ret, subReleases[len(subReleases)/2]) + } + for i := 0; i < len(releases); i++ { + // Gradually increase step. + step := 1 + if i >= 3 { + step = 2 + } + if i >= 11 { + step = 3 + } + if i%step == 0 || i == len(releases)-1 { + ret = append(ret, releases[i]) + } + } + return ret +} + +func minInts(vals ...int) int { + ret := vals[0] + for i := 1; i < len(vals); i++ { + if vals[i] < ret { + ret = vals[i] + } + } + return ret +} diff --git a/pkg/bisect/bisect_test.go b/pkg/bisect/bisect_test.go index 600a68b60..d44532fe0 100644 --- a/pkg/bisect/bisect_test.go +++ b/pkg/bisect/bisect_test.go @@ -353,9 +353,9 @@ var bisectionTests = []BisectionTest{ introduced: "605", extraTest: func(t *testing.T, res *Result) { // False negative probability of each run is ~35%. - // We get two "good" results, so our accumulated confidence is ~42%. - assert.Less(t, res.Confidence, 0.5) - assert.Greater(t, res.Confidence, 0.4) + // We get three "good" results, so our accumulated confidence is ~27%. + assert.Less(t, res.Confidence, 0.3) + assert.Greater(t, res.Confidence, 0.2) }, }, // Test bisection returns correct cause with different baseline/config combinations. @@ -955,3 +955,59 @@ func TestMostFrequentReport(t *testing.T) { }) } } + +func TestPickReleaseTags(t *testing.T) { + tests := []struct { + name string + tags []string + ret []string + }{ + { + name: "upstream-clang", + tags: []string{ + "v6.5", "v6.4", "v6.3", "v6.2", "v6.1", "v6.0", "v5.19", + "v5.18", "v5.17", "v5.16", "v5.15", "v5.14", "v5.13", + "v5.12", "v5.11", "v5.10", "v5.9", "v5.8", "v5.7", "v5.6", + "v5.5", "v5.4", + }, + ret: []string{ + "v6.5", "v6.4", "v6.3", "v6.1", "v5.19", "v5.17", "v5.15", + "v5.13", "v5.10", "v5.7", "v5.4", + }, + }, + { + name: "upstream-gcc", + tags: []string{ + "v6.5", "v6.4", "v6.3", "v6.2", "v6.1", "v6.0", "v5.19", + "v5.18", "v5.17", "v5.16", "v5.15", "v5.14", "v5.13", + "v5.12", "v5.11", "v5.10", "v5.9", "v5.8", "v5.7", "v5.6", + "v5.5", "v5.4", "v5.3", "v5.2", "v5.1", "v5.0", "v4.20", "v4.19", + "v4.18", + }, + ret: []string{ + "v6.5", "v6.4", "v6.3", "v6.1", "v5.19", "v5.17", "v5.15", + "v5.13", "v5.10", "v5.7", "v5.4", "v5.1", "v4.19", "v4.18", + }, + }, + { + name: "lts", + tags: []string{ + "v5.15.10", "v5.15.9", "v5.15.8", "v5.15.7", "v5.15.6", + "v5.15.5", "v5.15.4", "v5.15.3", "v5.15.2", "v5.15.1", + "v5.15", "v5.14", "v5.13", "v5.12", "v5.11", "v5.10", + "v5.9", "v5.8", "v5.7", "v5.6", "v5.5", "v5.4", + }, + ret: []string{ + "v5.15.10", "v5.15.9", "v5.15.5", "v5.15", "v5.14", "v5.13", + "v5.11", "v5.9", "v5.7", "v5.5", "v5.4", + }, + }, + } + for _, test := range tests { + test := test + t.Run(test.name, func(t *testing.T) { + ret := pickReleaseTags(append([]string{}, test.tags...)) + assert.Equal(t, test.ret, ret) + }) + } +} diff --git a/pkg/vcs/linux.go b/pkg/vcs/linux.go index 270240da7..62319096d 100644 --- a/pkg/vcs/linux.go +++ b/pkg/vcs/linux.go @@ -10,7 +10,6 @@ import ( "path/filepath" "regexp" "sort" - "strconv" "strings" "time" @@ -105,36 +104,21 @@ func gitParseReleaseTags(output []byte, includeRC bool) []string { } func gitReleaseTagToInt(tag string, includeRC bool) uint64 { - matches := releaseTagRe.FindStringSubmatchIndex(tag) - if matches == nil { + v1, v2, rc, v3 := ParseReleaseTag(tag) + if v1 < 0 { return 0 } - v1, err := strconv.ParseUint(tag[matches[2]:matches[3]], 10, 64) - if err != nil { - return 0 + if v3 < 0 { + v3 = 0 } - v2, err := strconv.ParseUint(tag[matches[4]:matches[5]], 10, 64) - if err != nil { - return 0 - } - rc := uint64(999) - if matches[6] != -1 { + if rc >= 0 { if !includeRC { return 0 } - rc, err = strconv.ParseUint(tag[matches[6]:matches[7]], 10, 64) - if err != nil { - return 0 - } - } - var v3 uint64 - if matches[8] != -1 { - v3, err = strconv.ParseUint(tag[matches[8]:matches[9]], 10, 64) - if err != nil { - return 0 - } + } else { + rc = 999 } - return v1*1e9 + v2*1e6 + rc*1e3 + v3 + return uint64(v1)*1e9 + uint64(v2)*1e6 + uint64(rc)*1e3 + uint64(v3) } func (ctx *linux) EnvForCommit( diff --git a/pkg/vcs/vcs.go b/pkg/vcs/vcs.go index ae2b34174..26665bda3 100644 --- a/pkg/vcs/vcs.go +++ b/pkg/vcs/vcs.go @@ -10,6 +10,7 @@ import ( "net/mail" "regexp" "sort" + "strconv" "strings" "time" @@ -268,6 +269,31 @@ func CheckCommitHash(hash string) bool { return gitHashRe.MatchString(hash) } +func ParseReleaseTag(tag string) (v1, v2, rc, v3 int) { + invalid := func() { + v1, v2, rc, v3 = -1, -1, -1, -1 + } + invalid() + matches := releaseTagRe.FindStringSubmatch(tag) + if matches == nil { + return + } + for ptr, idx := range map[*int]int{ + &v1: 1, &v2: 2, &rc: 3, &v3: 4, + } { + if matches[idx] == "" { + continue + } + var err error + *ptr, err = strconv.Atoi(matches[idx]) + if err != nil { + invalid() + return + } + } + return +} + func runSandboxed(dir, command string, args ...string) ([]byte, error) { cmd := osutil.Command(command, args...) cmd.Dir = dir |
