diff options
| author | Aleksandr Nogikh <nogikh@google.com> | 2021-11-30 14:30:41 +0000 |
|---|---|---|
| committer | Aleksandr Nogikh <wp32pw@gmail.com> | 2021-12-06 14:29:36 +0100 |
| commit | 45bf1e232e9518f6666c051c242a4ef656a97228 (patch) | |
| tree | ef77af18a08a6d4e8eade22466ebdcaad813814e | |
| parent | 9bc82119f890ecaa556935301dc721f90100d2dd (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.
| -rw-r--r-- | tools/syz-testbed/html.go | 37 | ||||
| -rw-r--r-- | tools/syz-testbed/stats.go | 33 |
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) |
