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 /tools | |
| 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.
Diffstat (limited to 'tools')
| -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) |
