aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAleksandr Nogikh <nogikh@google.com>2024-01-22 14:29:41 +0100
committerAleksandr Nogikh <nogikh@google.com>2024-01-23 11:46:32 +0000
commit312699d7f4fcaf0e1a7a007f15195e770a99b3c2 (patch)
tree9040a57619174294e5bf5213d83c3d93627b529c
parent1c0ecc51adc9f44c7bd3f45c2aa1b62718d1236e (diff)
dashboard: capture cover and PCs after corpus triage
This statistics allows us to better estimate the amount of coverage that is lost after every syzbot instance is restarted.
-rw-r--r--dashboard/app/api.go6
-rw-r--r--dashboard/app/entities.go3
-rw-r--r--dashboard/app/graph_fuzzing.html2
-rw-r--r--dashboard/app/graphs.go46
-rw-r--r--dashboard/dashapi/dashapi.go4
-rw-r--r--syz-manager/manager.go14
6 files changed, 52 insertions, 23 deletions
diff --git a/dashboard/app/api.go b/dashboard/app/api.go
index 6a84c758b..381853716 100644
--- a/dashboard/app/api.go
+++ b/dashboard/app/api.go
@@ -1142,6 +1142,12 @@ func apiManagerStats(c context.Context, ns string, r *http.Request, payload []by
stats.TotalCrashes += int64(req.Crashes)
stats.SuppressedCrashes += int64(req.SuppressedCrashes)
stats.TotalExecs += int64(req.Execs)
+ if cur := int64(req.TriagedCoverage); cur > stats.TriagedCoverage {
+ stats.TriagedCoverage = cur
+ }
+ if cur := int64(req.TriagedPCs); cur > stats.TriagedPCs {
+ stats.TriagedPCs = cur
+ }
return nil
})
return nil, err
diff --git a/dashboard/app/entities.go b/dashboard/app/entities.go
index 71f4a92fc..74221af57 100644
--- a/dashboard/app/entities.go
+++ b/dashboard/app/entities.go
@@ -50,6 +50,9 @@ type ManagerStats struct {
CrashTypes int64 // unique crash types
SuppressedCrashes int64
TotalExecs int64
+ // These are only recorded once right after corpus is triaged.
+ TriagedCoverage int64
+ TriagedPCs int64
}
type Asset struct {
diff --git a/dashboard/app/graph_fuzzing.html b/dashboard/app/graph_fuzzing.html
index ab18a2742..5ed07ba63 100644
--- a/dashboard/app/graph_fuzzing.html
+++ b/dashboard/app/graph_fuzzing.html
@@ -24,7 +24,7 @@ Manager statistics graphs.
{{- end}}
data.addRows([ {{range $.Graph.Columns}}
[ "{{.Hint}}", {{range .Vals}}
- {{if .Val}}{{.Val}}{{end}}, '{{.Hint}}',
+ {{if .IsNull}}null{{else if .Val}}{{.Val}}{{end}}, '{{.Hint}}',
{{- end}}
],
{{- end}}
diff --git a/dashboard/app/graphs.go b/dashboard/app/graphs.go
index 125b909a6..7c023ca89 100644
--- a/dashboard/app/graphs.go
+++ b/dashboard/app/graphs.go
@@ -63,8 +63,9 @@ type uiGraphColumn struct {
}
type uiGraphValue struct {
- Val float32
- Hint string
+ Val float32
+ IsNull bool
+ Hint string
}
type uiCrashPageTable struct {
@@ -328,7 +329,7 @@ func handleGraphFuzzing(c context.Context, w http.ResponseWriter, r *http.Reques
metrics, err := createCheckBox(r, "Metrics", []string{
"MaxCorpus", "MaxCover", "MaxPCs", "TotalFuzzingTime",
"TotalCrashes", "CrashTypes", "SuppressedCrashes", "TotalExecs",
- "ExecsPerSec"})
+ "ExecsPerSec", "TriagedPCs", "TriagedCoverage"})
if err != nil {
return err
}
@@ -381,10 +382,11 @@ func createManagersGraph(c context.Context, ns string, selManagers, selMetrics [
continue
}
for metricIndex, metric := range selMetrics {
- val := extractMetric(stat, metric)
+ val, canBeZero := extractMetric(stat, metric)
graph.Columns[dayIndex].Vals[mgrIndex*len(selMetrics)+metricIndex] = uiGraphValue{
- Val: float32(val),
- Hint: fmt.Sprintf("%.2f", val),
+ Val: float32(val),
+ IsNull: !canBeZero && val == 0,
+ Hint: fmt.Sprintf("%.2f", val),
}
}
}
@@ -398,7 +400,11 @@ func createManagersGraph(c context.Context, ns string, selManagers, selMetrics [
max := float32(1)
for col := range graph.Columns {
for mgrIndex := range selManagers {
- val := graph.Columns[col].Vals[mgrIndex*len(selMetrics)+metricIndex].Val
+ item := graph.Columns[col].Vals[mgrIndex*len(selMetrics)+metricIndex]
+ if item.IsNull {
+ continue
+ }
+ val := item.Val
if max < val {
max = val
}
@@ -414,30 +420,34 @@ func createManagersGraph(c context.Context, ns string, selManagers, selMetrics [
return graph, nil
}
-func extractMetric(stat *ManagerStats, metric string) float64 {
+func extractMetric(stat *ManagerStats, metric string) (val float64, canBeZero bool) {
switch metric {
case "MaxCorpus":
- return float64(stat.MaxCorpus)
+ return float64(stat.MaxCorpus), false
case "MaxCover":
- return float64(stat.MaxCover)
+ return float64(stat.MaxCover), false
case "MaxPCs":
- return float64(stat.MaxPCs)
+ return float64(stat.MaxPCs), false
case "TotalFuzzingTime":
- return float64(stat.TotalFuzzingTime)
+ return float64(stat.TotalFuzzingTime), true
case "TotalCrashes":
- return float64(stat.TotalCrashes)
+ return float64(stat.TotalCrashes), true
case "CrashTypes":
- return float64(stat.CrashTypes)
+ return float64(stat.CrashTypes), true
case "SuppressedCrashes":
- return float64(stat.SuppressedCrashes)
+ return float64(stat.SuppressedCrashes), true
case "TotalExecs":
- return float64(stat.TotalExecs)
+ return float64(stat.TotalExecs), true
case "ExecsPerSec":
timeSec := float64(stat.TotalFuzzingTime) / 1e9
if timeSec == 0 {
- return 0
+ return 0, true
}
- return float64(stat.TotalExecs) / timeSec
+ return float64(stat.TotalExecs) / timeSec, true
+ case "TriagedCoverage":
+ return float64(stat.TriagedCoverage), false
+ case "TriagedPCs":
+ return float64(stat.TriagedPCs), false
default:
panic(fmt.Sprintf("unknown metric %q", metric))
}
diff --git a/dashboard/dashapi/dashapi.go b/dashboard/dashapi/dashapi.go
index aaaf3edfa..520a991fc 100644
--- a/dashboard/dashapi/dashapi.go
+++ b/dashboard/dashapi/dashapi.go
@@ -725,6 +725,10 @@ type ManagerStatsReq struct {
Crashes uint64
SuppressedCrashes uint64
Execs uint64
+
+ // Non-zero only when set.
+ TriagedCoverage uint64
+ TriagedPCs uint64
}
func (dash *Dashboard) UploadManagerStats(req *ManagerStatsReq) error {
diff --git a/syz-manager/manager.go b/syz-manager/manager.go
index 3efee4f0e..0670a6bb3 100644
--- a/syz-manager/manager.go
+++ b/syz-manager/manager.go
@@ -90,10 +90,11 @@ type Manager struct {
// Maps file name to modification time.
usedFiles map[string]time.Time
- modules []host.KernelModule
- coverFilter map[uint32]uint32
- execCoverFilter map[uint32]uint32
- modulesInitialized bool
+ modules []host.KernelModule
+ coverFilter map[uint32]uint32
+ execCoverFilter map[uint32]uint32
+ modulesInitialized bool
+ afterTriageStatSent bool
assetStorage *asset.Storage
}
@@ -1521,6 +1522,11 @@ func (mgr *Manager) dashboardReporter() {
SuppressedCrashes: suppressedCrashes - lastSuppressedCrashes,
Execs: execs - lastExecs,
}
+ if mgr.phase >= phaseTriagedCorpus && !mgr.afterTriageStatSent {
+ mgr.afterTriageStatSent = true
+ req.TriagedCoverage = mgr.stats.corpusSignal.get()
+ req.TriagedPCs = mgr.stats.corpusCover.get()
+ }
mgr.mu.Unlock()
if err := mgr.dash.UploadManagerStats(req); err != nil {