aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2020-10-22 18:59:10 +0200
committerDmitry Vyukov <dvyukov@google.com>2020-10-22 22:02:56 +0200
commit4e740c00a474b578896830c7d27d90d9474364bb (patch)
treeff0f2787b64d3e339e2166325f236b2ec8227846
parent1616d34edcf609e9cff417106daa2152bbe754f8 (diff)
dashboard/app: show more detailed info about bisections
1. Split cause/fix bisections in the bug table. 2. Show if bisection is inconclusive/unreliable in the bug table. 3. Show if bisection is unreliable on the bug page. Update #2098
-rw-r--r--dashboard/app/admin.go8
-rw-r--r--dashboard/app/bisect_test.go4
-rw-r--r--dashboard/app/entities.go43
-rw-r--r--dashboard/app/jobs.go6
-rw-r--r--dashboard/app/main.go88
-rw-r--r--dashboard/app/reporting.go9
-rw-r--r--dashboard/app/static/common.js2
-rw-r--r--dashboard/app/static/style.css7
-rw-r--r--dashboard/app/templates.html20
-rw-r--r--pkg/html/generated.go9
10 files changed, 133 insertions, 63 deletions
diff --git a/dashboard/app/admin.go b/dashboard/app/admin.go
index 104807a56..8062d1881 100644
--- a/dashboard/app/admin.go
+++ b/dashboard/app/admin.go
@@ -142,7 +142,7 @@ func updateBugReporting(c context.Context, w http.ResponseWriter, r *http.Reques
}
log.Warningf(c, "fetched %v bugs for namespce %v", len(bugs), ns)
cfg := config.Namespaces[ns]
- transform := func(bug *Bug) {
+ transform := func(bug *Bug, index int) {
createBugReporting(bug, cfg)
}
var batchKeys []*db.Key
@@ -167,14 +167,14 @@ func updateBugReporting(c context.Context, w http.ResponseWriter, r *http.Reques
return nil
}
-func updateBugBatch(c context.Context, keys []*db.Key, transform func(bug *Bug)) error {
+func updateBugBatch(c context.Context, keys []*db.Key, transform func(bug *Bug, index int)) error {
tx := func(c context.Context) error {
bugs := make([]*Bug, len(keys))
if err := db.GetMulti(c, keys, bugs); err != nil {
return err
}
- for _, bug := range bugs {
- transform(bug)
+ for i, bug := range bugs {
+ transform(bug, i)
}
_, err := db.PutMulti(c, keys, bugs)
return err
diff --git a/dashboard/app/bisect_test.go b/dashboard/app/bisect_test.go
index 31edbadf0..8db11a0ba 100644
--- a/dashboard/app/bisect_test.go
+++ b/dashboard/app/bisect_test.go
@@ -1089,7 +1089,7 @@ func TestBugBisectionStatus(t *testing.T) {
url := fmt.Sprintf("/%v", bugs[0].Namespace)
content, err := c.httpRequest("GET", url, "", AccessAdmin)
c.expectEQ(err, nil)
- c.expectTrue(bytes.Contains(content, []byte("cause")))
+ c.expectTrue(bytes.Contains(content, []byte("done")))
// Advance time by 30 days and read out any notification emails.
{
@@ -1134,7 +1134,7 @@ func TestBugBisectionStatus(t *testing.T) {
c.expectOK(c.client2.JobDone(done))
content, err = c.httpRequest("GET", url, "", AccessAdmin)
c.expectEQ(err, nil)
- c.expectTrue(bytes.Contains(content, []byte("cause+fix")))
+ c.expectTrue(bytes.Contains(content, []byte("done")))
msg := c.client2.pollEmailBug()
c.expectTrue(strings.Contains(msg.Body, "syzbot suspects this issue was fixed by commit:"))
diff --git a/dashboard/app/entities.go b/dashboard/app/entities.go
index c0e756de5..d5558fde6 100644
--- a/dashboard/app/entities.go
+++ b/dashboard/app/entities.go
@@ -214,6 +214,26 @@ const (
BisectResultIgnore
)
+func (flags JobFlags) String() string {
+ res := ""
+ if flags&BisectResultMerge != 0 {
+ res += "merge "
+ }
+ if flags&BisectResultNoop != 0 {
+ res += "no-op "
+ }
+ if flags&BisectResultRelease != 0 {
+ res += "release "
+ }
+ if flags&BisectResultIgnore != 0 {
+ res += "ignored "
+ }
+ if res == "" {
+ return res
+ }
+ return "[" + res + "commit]"
+}
+
func (job *Job) isUnreliableBisect() bool {
if job.Type != JobBisectCause && job.Type != JobBisectFix {
panic(fmt.Sprintf("bad job type %v", job.Type))
@@ -274,9 +294,30 @@ const (
BisectNot BisectStatus = iota
BisectPending
BisectError
- BisectYes
+ BisectYes // have 1 commit
+ BisectUnreliable // have 1 commit, but suspect it's wrong
+ BisectInconclusive // multiple commits due to skips
+ BisectHorizont // happens on the oldest commit we can test (or HEAD for fix bisection)
+ bisectStatusLast // this value can be changed (not stored in datastore)
)
+func (status BisectStatus) String() string {
+ switch status {
+ case BisectError:
+ return "error"
+ case BisectYes:
+ return "done"
+ case BisectUnreliable:
+ return "unreliable"
+ case BisectInconclusive:
+ return "inconclusive"
+ case BisectHorizont:
+ return "inconclusive"
+ default:
+ return ""
+ }
+}
+
func mgrKey(c context.Context, ns, name string) *db.Key {
return db.NewKey(c, "Manager", fmt.Sprintf("%v-%v", ns, name), 0, nil)
}
diff --git a/dashboard/app/jobs.go b/dashboard/app/jobs.go
index ad6f2d734..af20f75e1 100644
--- a/dashboard/app/jobs.go
+++ b/dashboard/app/jobs.go
@@ -529,6 +529,12 @@ func updateBugBisection(c context.Context, job *Job, jobKey *db.Key, req *dashap
result := BisectYes
if len(req.Error) != 0 {
result = BisectError
+ } else if len(req.Commits) > 1 {
+ result = BisectInconclusive
+ } else if len(req.Commits) == 0 {
+ result = BisectHorizont
+ } else if job.isUnreliableBisect() {
+ result = BisectUnreliable
}
if job.Type == JobBisectCause {
bug.BisectCause = result
diff --git a/dashboard/app/main.go b/dashboard/app/main.go
index a5b39f023..8c3e27042 100644
--- a/dashboard/app/main.go
+++ b/dashboard/app/main.go
@@ -143,26 +143,26 @@ type uiJobList struct {
}
type uiBug struct {
- Namespace string
- Title string
- NumCrashes int64
- NumCrashesBad bool
- BisectCauseDone bool
- BisectFixDone bool
- FirstTime time.Time
- LastTime time.Time
- ReportedTime time.Time
- ClosedTime time.Time
- ReproLevel dashapi.ReproLevel
- ReportingIndex int
- Status string
- Link string
- ExternalLink string
- CreditEmail string
- Commits []*uiCommit
- PatchedOn []string
- MissingOn []string
- NumManagers int
+ Namespace string
+ Title string
+ NumCrashes int64
+ NumCrashesBad bool
+ BisectCause BisectStatus
+ BisectFix BisectStatus
+ FirstTime time.Time
+ LastTime time.Time
+ ReportedTime time.Time
+ ClosedTime time.Time
+ ReproLevel dashapi.ReproLevel
+ ReportingIndex int
+ Status string
+ Link string
+ ExternalLink string
+ CreditEmail string
+ Commits []*uiCommit
+ PatchedOn []string
+ MissingOn []string
+ NumManagers int
}
type uiCrash struct {
@@ -185,6 +185,7 @@ type uiCrashTable struct {
type uiJob struct {
Type JobType
+ Flags JobFlags
Created time.Time
BugLink string
ExternalLink string
@@ -803,22 +804,22 @@ func createUIBug(c context.Context, bug *Bug, state *ReportingState, managers []
}
id := bug.keyHash()
uiBug := &uiBug{
- Namespace: bug.Namespace,
- Title: bug.displayTitle(),
- BisectCauseDone: bug.BisectCause > BisectPending,
- BisectFixDone: bug.BisectFix > BisectPending,
- NumCrashes: bug.NumCrashes,
- FirstTime: bug.FirstTime,
- LastTime: bug.LastTime,
- ReportedTime: reported,
- ClosedTime: bug.Closed,
- ReproLevel: bug.ReproLevel,
- ReportingIndex: reportingIdx,
- Status: status,
- Link: bugLink(id),
- ExternalLink: link,
- CreditEmail: creditEmail,
- NumManagers: len(managers),
+ Namespace: bug.Namespace,
+ Title: bug.displayTitle(),
+ BisectCause: bug.BisectCause,
+ BisectFix: bug.BisectFix,
+ NumCrashes: bug.NumCrashes,
+ FirstTime: bug.FirstTime,
+ LastTime: bug.LastTime,
+ ReportedTime: reported,
+ ClosedTime: bug.Closed,
+ ReproLevel: bug.ReproLevel,
+ ReportingIndex: reportingIdx,
+ Status: status,
+ Link: bugLink(id),
+ ExternalLink: link,
+ CreditEmail: creditEmail,
+ NumManagers: len(managers),
}
updateBugBadness(c, uiBug)
if len(bug.Commits) != 0 {
@@ -853,8 +854,8 @@ func createUIBug(c context.Context, bug *Bug, state *ReportingState, managers []
func mergeUIBug(c context.Context, bug *uiBug, dup *Bug) {
bug.NumCrashes += dup.NumCrashes
- bug.BisectCauseDone = bug.BisectCauseDone || dup.BisectCause > BisectPending
- bug.BisectFixDone = bug.BisectFixDone || dup.BisectFix > BisectPending
+ bug.BisectCause = mergeBisectStatus(bug.BisectCause, dup.BisectCause)
+ bug.BisectFix = mergeBisectStatus(bug.BisectFix, dup.BisectFix)
if bug.LastTime.Before(dup.LastTime) {
bug.LastTime = dup.LastTime
}
@@ -864,6 +865,16 @@ func mergeUIBug(c context.Context, bug *uiBug, dup *Bug) {
updateBugBadness(c, bug)
}
+func mergeBisectStatus(a, b BisectStatus) BisectStatus {
+ // The statuses are stored in the datastore, so we can't reorder them.
+ // But if one of bisections is Yes, then we want to show Yes.
+ bisectPriority := [bisectStatusLast]int{0, 1, 2, 6, 5, 4, 3}
+ if bisectPriority[a] >= bisectPriority[b] {
+ return a
+ }
+ return b
+}
+
func updateBugBadness(c context.Context, bug *uiBug) {
bug.NumCrashesBad = bug.NumCrashes >= 10000 && timeNow(c).Sub(bug.LastTime) < 24*time.Hour
}
@@ -1095,6 +1106,7 @@ func loadTestPatchJobs(c context.Context, bug *Bug) ([]*uiJob, error) {
func makeUIJob(job *Job, jobKey *db.Key, bug *Bug, crash *Crash, build *Build) *uiJob {
ui := &uiJob{
Type: job.Type,
+ Flags: job.Flags,
Created: job.Created,
BugLink: bugLink(jobKey.Parent().StringID()),
ExternalLink: job.Link,
diff --git a/dashboard/app/reporting.go b/dashboard/app/reporting.go
index 775eaf759..54ad38cdd 100644
--- a/dashboard/app/reporting.go
+++ b/dashboard/app/reporting.go
@@ -356,14 +356,17 @@ func createBugReport(c context.Context, bug *Bug, crash *Crash, crashKey *db.Key
return nil, err
}
var job *Job
- if bug.BisectCause == BisectYes {
+ reportBisection := bug.BisectCause == BisectYes ||
+ bug.BisectCause == BisectInconclusive ||
+ bug.BisectCause == BisectHorizont
+ if reportBisection {
// If we have bisection results, report the crash/repro used for bisection.
job1, crash1, _, crashKey1, err := loadBisectJob(c, bug, JobBisectCause)
if err != nil {
return nil, err
}
job = job1
- if !job.isUnreliableBisect() && (crash1.ReproC != 0 || crash.ReproC == 0) {
+ if crash1.ReproC != 0 || crash.ReproC == 0 {
// Don't override the crash in this case,
// otherwise we will always think that we haven't reported the C repro.
crash, crashKey = crash1, crashKey1
@@ -444,7 +447,7 @@ func createBugReport(c context.Context, bug *Bug, crash *Crash, crashKey *db.Key
if build.Type == BuildFailed {
rep.Maintainers = append(rep.Maintainers, kernelRepo.BuildMaintainers...)
}
- if bug.BisectCause == BisectYes && !job.isUnreliableBisect() {
+ if reportBisection {
rep.BisectCause = bisectFromJob(c, rep, job)
}
if err := fillBugReport(c, rep, bug, bugReporting, build); err != nil {
diff --git a/dashboard/app/static/common.js b/dashboard/app/static/common.js
index 6d03cf78d..ec5a5c767 100644
--- a/dashboard/app/static/common.js
+++ b/dashboard/app/static/common.js
@@ -38,7 +38,7 @@ function isSorted(values) {
return true;
}
-function textSort(v) { return v.toLowerCase(); }
+function textSort(v) { return v == "" ? "zzz" : v.toLowerCase(); }
function numSort(v) { return -parseInt(v); }
function floatSort(v) { return -parseFloat(v); }
function reproSort(v) { return v == "C" ? 0 : v == "syz" ? 1 : 2; }
diff --git a/dashboard/app/static/style.css b/dashboard/app/static/style.css
index ae0a2ae6c..669e32dfe 100644
--- a/dashboard/app/static/style.css
+++ b/dashboard/app/static/style.css
@@ -157,6 +157,13 @@ table td, table th {
text-align: right;
}
+.list_table .bisect_status {
+ width: 75pt;
+ max-width: 75pt;
+ font-family: monospace;
+ text-align: right;
+}
+
.list_table .date {
width: 60pt;
max-width: 60pt;
diff --git a/dashboard/app/templates.html b/dashboard/app/templates.html
index f6839a594..0fc52bd66 100644
--- a/dashboard/app/templates.html
+++ b/dashboard/app/templates.html
@@ -93,7 +93,8 @@ Use of this source code is governed by Apache 2 LICENSE that can be found in the
{{end}}
<th><a onclick="return sortTable(this, 'Title', textSort)" href="#">Title</a></th>
<th><a onclick="return sortTable(this, 'Repro', reproSort)" href="#">Repro</a></th>
- <th><a onclick="return sortTable(this, 'Bisected', textSort)" href="#">Bisected</a></th>
+ <th><a onclick="return sortTable(this, 'Cause bisect', textSort)" href="#">Cause bisect</a></th>
+ <th><a onclick="return sortTable(this, 'Fix bisect', textSort)" href="#">Fix bisect</a></th>
<th><a onclick="return sortTable(this, 'Count', numSort)" href="#">Count</a></th>
<th><a onclick="return sortTable(this, 'Last', timeSort)" href="#">Last</a></th>
<th><a onclick="return sortTable(this, 'Reported', timeSort)" href="#">Reported</a></th>
@@ -115,15 +116,8 @@ Use of this source code is governed by Apache 2 LICENSE that can be found in the
{{if $.ShowNamespace}}<td>{{$b.Namespace}}</td>{{end}}
<td class="title"><a href="{{$b.Link}}">{{$b.Title}}</a></td>
<td class="stat">{{formatReproLevel $b.ReproLevel}}</td>
- <td class="stat">
- {{if and $b.BisectCauseDone $b.BisectFixDone}}
- cause+fix
- {{else if $b.BisectCauseDone}}
- cause
- {{else if $b.BisectFixDone}}
- fix
- {{end}}
- </td>
+ <td class="bisect_status">{{print $b.BisectCause}}</td>
+ <td class="bisect_status">{{print $b.BisectFix}}</td>
<td class="stat {{if $b.NumCrashesBad}}bad{{end}}">{{$b.NumCrashes}}</td>
<td class="stat">{{formatLateness $.Now $b.LastTime}}</td>
<td class="stat">
@@ -266,8 +260,8 @@ Use of this source code is governed by Apache 2 LICENSE that can be found in the
{{else if eq .Type $fixJob}}
<b>Fix bisection: fixed by</b>
{{end}}
- <b>({{link .LogLink "bisect log"}}):</b><br>
- <br><span class="mono">
+ <b>({{link .LogLink "bisect log"}})</b> <span class="bad">{{print .Flags}}</span>:<br>
+ <span class="mono">
commit {{.Commit.Hash}}<br>
Author: {{.Commit.Author}}<br>
Date: {{formatKernelTime .Commit.Date}}<br>
@@ -281,7 +275,7 @@ Use of this source code is governed by Apache 2 LICENSE that can be found in the
<b>Fix bisection: the fix commit could be any of</b>
{{end}}
<b>({{link .LogLink "bisect log"}}):</b><br>
- <br><span class="mono">
+ <span class="mono">
{{range $com := .Commits}}
&nbsp;&nbsp;{{formatTagHash $com.Hash}} {{$com.Title}}<br>
{{end}}
diff --git a/pkg/html/generated.go b/pkg/html/generated.go
index 9d85807dc..5db49d857 100644
--- a/pkg/html/generated.go
+++ b/pkg/html/generated.go
@@ -161,6 +161,13 @@ table td, table th {
text-align: right;
}
+.list_table .bisect_status {
+ width: 75pt;
+ max-width: 75pt;
+ font-family: monospace;
+ text-align: right;
+}
+
.list_table .date {
width: 60pt;
max-width: 60pt;
@@ -248,7 +255,7 @@ function isSorted(values) {
return true;
}
-function textSort(v) { return v.toLowerCase(); }
+function textSort(v) { return v == "" ? "zzz" : v.toLowerCase(); }
function numSort(v) { return -parseInt(v); }
function floatSort(v) { return -parseFloat(v); }
function reproSort(v) { return v == "C" ? 0 : v == "syz" ? 1 : 2; }