diff options
| -rw-r--r-- | dashboard/app/admin.go | 8 | ||||
| -rw-r--r-- | dashboard/app/bisect_test.go | 4 | ||||
| -rw-r--r-- | dashboard/app/entities.go | 43 | ||||
| -rw-r--r-- | dashboard/app/jobs.go | 6 | ||||
| -rw-r--r-- | dashboard/app/main.go | 88 | ||||
| -rw-r--r-- | dashboard/app/reporting.go | 9 | ||||
| -rw-r--r-- | dashboard/app/static/common.js | 2 | ||||
| -rw-r--r-- | dashboard/app/static/style.css | 7 | ||||
| -rw-r--r-- | dashboard/app/templates.html | 20 | ||||
| -rw-r--r-- | pkg/html/generated.go | 9 |
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}} {{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; } |
