aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorAleksandr Nogikh <nogikh@google.com>2021-11-30 14:30:41 +0000
committerAleksandr Nogikh <wp32pw@gmail.com>2021-12-06 14:29:36 +0100
commit45bf1e232e9518f6666c051c242a4ef656a97228 (patch)
treeef77af18a08a6d4e8eade22466ebdcaad813814e /tools
parent9bc82119f890ecaa556935301dc721f90100d2dd (diff)
tools/syz-testbed: align table per particular rows
It turns out that we often want to see the data aligned on some specific property - e.g. align all checkouts by "exec total" and see how other parameters differ. Add a preliminary support of such a feature. On a row title click, pick the minimal value in the row and wind the history of each column back until the target row value is closest to the minimal one.
Diffstat (limited to 'tools')
-rw-r--r--tools/syz-testbed/html.go37
-rw-r--r--tools/syz-testbed/stats.go33
2 files changed, 61 insertions, 9 deletions
diff --git a/tools/syz-testbed/html.go b/tools/syz-testbed/html.go
index 396265dc5..bae718fda 100644
--- a/tools/syz-testbed/html.go
+++ b/tools/syz-testbed/html.go
@@ -126,6 +126,7 @@ type uiTable struct {
ColumnURL func(string) string
RowURL func(string) string
Extra bool
+ AlignedBy string
}
type uiStatView struct {
@@ -153,7 +154,12 @@ func (ctx *TestbedContext) httpMain(w http.ResponseWriter, r *http.Request) {
return
}
uiView := uiStatView{Name: activeView.Name}
- table, err := activeView.StatsTable()
+
+ alignBy := r.FormValue("align")
+ if alignBy == "" {
+ alignBy = "fuzzing"
+ }
+ table, err := activeView.AlignedStatsTable(alignBy)
if err != nil {
log.Printf("stat table generation failed: %s", err)
} else {
@@ -172,8 +178,23 @@ func (ctx *TestbedContext) httpMain(w http.ResponseWriter, r *http.Request) {
if column == baseColumn {
return ""
}
- return "/?view=" + url.QueryEscape(activeView.Name) + "&base_column=" + url.QueryEscape(column)
+ v := url.Values{}
+ v.Set("view", activeView.Name)
+ v.Set("base_column", column)
+ v.Set("align", alignBy)
+ return "/?" + v.Encode()
+ },
+ RowURL: func(row string) string {
+ if row == alignBy {
+ return ""
+ }
+ v := url.Values{}
+ v.Set("view", activeView.Name)
+ v.Set("base_column", baseColumn)
+ v.Set("align", row)
+ return "/?" + v.Encode()
},
+ AlignedBy: alignBy,
}
}
@@ -270,6 +291,9 @@ href="?view={{$view.Name}}">█ {{$view.Name}}</a>
{{define "PrintTable"}}
{{$uiTable := .}}
{{if .Table}}
+{{if $uiTable.AlignedBy}}
+ The data are aligned by {{$uiTable.AlignedBy}} <br />
+{{end}}
<table class="list_table">
<tr>
<th>{{.Table.TopLeftHeader}}</th>
@@ -289,7 +313,14 @@ href="?view={{$view.Name}}">█ {{$view.Name}}</a>
</tr>
{{range $r := .Table.SortedRows}}
<tr>
- <td>{{$r}}</td>
+ <td>
+ {{$url := ""}}
+ {{if $uiTable.RowURL}}{{$url = (call $uiTable.RowURL $r)}}{{end}}
+ {{if $url}}<a href="{{$url}}">{{$r}}</a>
+ {{else}}
+ {{$r}}
+ {{end}}
+ </td>
{{range $c := $uiTable.Table.ColumnHeaders}}
{{$cell := ($uiTable.Table.Get $r $c)}}
{{if and $cell $uiTable.Extra}}
diff --git a/tools/syz-testbed/stats.go b/tools/syz-testbed/stats.go
index 42ce9537b..20ad9bb30 100644
--- a/tools/syz-testbed/stats.go
+++ b/tools/syz-testbed/stats.go
@@ -182,26 +182,47 @@ func (group RunResultGroup) groupNthRecord(i int) map[string]*stats.Sample {
}
func (view StatView) StatsTable() (*Table, error) {
- commonLen := 0
+ return view.AlignedStatsTable("uptime")
+}
+
+func (view StatView) AlignedStatsTable(field string) (*Table, error) {
+ // We assume that the stats values are nonnegative.
+ var commonValue float64
for _, group := range view.Groups {
minLen := group.minResultLength()
if minLen == 0 {
continue
}
- if minLen < commonLen || commonLen == 0 {
- commonLen = minLen
+ sampleGroup := group.groupNthRecord(minLen - 1)
+ sample, ok := sampleGroup[field]
+ if !ok {
+ return nil, fmt.Errorf("field %v is not found", field)
+ }
+ currValue := sample.Median()
+ if currValue < commonValue || commonValue == 0 {
+ commonValue = currValue
}
}
- // Map: stats key x group name -> value.
table := NewTable("Property")
cells := make(map[string]map[string]string)
for _, group := range view.Groups {
table.AddColumn(group.Name)
- if group.minResultLength() == 0 {
+ minLen := group.minResultLength()
+ if minLen == 0 {
// Skip empty groups.
continue
}
- samples := group.groupNthRecord(commonLen - 1)
+ // Unwind the samples so that they are aligned on the field value.
+ var samples map[string]*stats.Sample
+ for i := minLen - 1; i >= 0; i-- {
+ candidate := group.groupNthRecord(i)
+ // TODO: consider data interpolation.
+ if candidate[field].Median() >= commonValue {
+ samples = candidate
+ } else {
+ break
+ }
+ }
for key, sample := range samples {
if _, ok := cells[key]; !ok {
cells[key] = make(map[string]string)