aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/syz-testbed/stats.go97
1 files changed, 61 insertions, 36 deletions
diff --git a/tools/syz-testbed/stats.go b/tools/syz-testbed/stats.go
index a25b312f1..bd3c821c9 100644
--- a/tools/syz-testbed/stats.go
+++ b/tools/syz-testbed/stats.go
@@ -13,6 +13,7 @@ import (
"strings"
"github.com/google/syzkaller/pkg/osutil"
+ "github.com/google/syzkaller/pkg/stats"
)
type BugInfo struct {
@@ -23,9 +24,12 @@ type BugInfo struct {
type RunResult struct {
Workdir string
Bugs []BugInfo
- StatRecords []map[string]uint64
+ StatRecords []StatRecord
}
+// A snapshot of syzkaller statistics at a particular time.
+type StatRecord map[string]uint64
+
// The grouping of single instance results. Taken by all stat generating routines.
type RunResultGroup struct {
Name string
@@ -59,16 +63,16 @@ func collectBugs(workdir string) ([]BugInfo, error) {
return bugs, nil
}
-func readBenches(benchFile string) ([]map[string]uint64, error) {
+func readBenches(benchFile string) ([]StatRecord, error) {
f, err := os.Open(benchFile)
if err != nil {
return nil, err
}
defer f.Close()
dec := json.NewDecoder(f)
- ret := []map[string]uint64{}
+ ret := []StatRecord{}
for dec.More() {
- curr := make(map[string]uint64)
+ curr := make(StatRecord)
if err := dec.Decode(&curr); err == nil {
ret = append(ret, curr)
}
@@ -76,19 +80,18 @@ func readBenches(benchFile string) ([]map[string]uint64, error) {
return ret, nil
}
-func avgBenches(infos []map[string]uint64) map[string]uint64 {
- ret := make(map[string]uint64)
- if len(infos) == 0 {
- return ret
- }
- for _, stat := range infos {
- for key, value := range stat {
- ret[key] += value
+// The input are stat snapshots of different instances taken at the same time.
+// This function groups those data points per stat types (e.g. exec total, crashes, etc.).
+func groupSamples(records []StatRecord) map[string]*stats.Sample {
+ ret := make(map[string]*stats.Sample)
+ for _, record := range records {
+ for key, value := range record {
+ if ret[key] == nil {
+ ret[key] = &stats.Sample{}
+ }
+ ret[key].Xs = append(ret[key].Xs, float64(value))
}
}
- for key, value := range ret {
- ret[key] = value / uint64(len(infos))
- }
return ret
}
@@ -153,44 +156,66 @@ func (view StatView) GenerateBugTable() ([][]string, error) {
func (group RunResultGroup) AvgStatRecords() []map[string]uint64 {
ret := []map[string]uint64{}
- for i := 0; ; i++ {
- toAvg := []map[string]uint64{}
- for _, result := range group.Results {
- if i < len(result.StatRecords) {
- toAvg = append(toAvg, result.StatRecords[i])
- }
+ commonLen := group.minResultLength()
+ for i := 0; i < commonLen; i++ {
+ record := make(map[string]uint64)
+ for key, value := range group.groupNthRecord(i) {
+ record[key] = uint64(value.Median())
}
- if len(toAvg) != len(group.Results) || len(toAvg) == 0 {
- break
+ ret = append(ret, record)
+ }
+ return ret
+}
+
+func (group RunResultGroup) minResultLength() int {
+ if len(group.Results) == 0 {
+ return 0
+ }
+ ret := len(group.Results[0].StatRecords)
+ for _, result := range group.Results {
+ currLen := len(result.StatRecords)
+ if currLen < ret {
+ ret = currLen
}
- ret = append(ret, avgBenches(toAvg))
}
return ret
}
+func (group RunResultGroup) groupNthRecord(i int) map[string]*stats.Sample {
+ records := []StatRecord{}
+ for _, result := range group.Results {
+ records = append(records, result.StatRecords[i])
+ }
+ return groupSamples(records)
+}
+
func (view StatView) StatsTable() ([][]string, error) {
- // Ensure that everything is at the same point in time.
- avgs := make(map[string][]map[string]uint64)
- commonLength := 0
+ commonLen := 0
for _, group := range view.Groups {
- records := group.AvgStatRecords()
- if len(records) == 0 {
+ minLen := group.minResultLength()
+ if minLen == 0 {
continue
}
- if commonLength > len(records) || commonLength == 0 {
- commonLength = len(records)
+ if minLen < commonLen || commonLen == 0 {
+ commonLen = minLen
}
- avgs[group.Name] = records
}
-
+ if commonLen == 0 {
+ return nil, fmt.Errorf("not enough stat records")
+ }
// Map: stats key x group name -> value.
cells := make(map[string]map[string]string)
- for name, avg := range avgs {
- for key, value := range avg[commonLength-1] {
+ for _, group := range view.Groups {
+ if group.minResultLength() == 0 {
+ // Skip empty groups.
+ continue
+ }
+ samples := group.groupNthRecord(commonLen - 1)
+ for key, sample := range samples {
if _, ok := cells[key]; !ok {
cells[key] = make(map[string]string)
}
- cells[key][name] = fmt.Sprintf("%d", value)
+ cells[key][group.Name] = fmt.Sprintf("%d", int64(sample.Median()))
}
}
title := []string{""}