From 8a9bfbcda821c7c38dba195d7ba4a5f34463b49b Mon Sep 17 00:00:00 2001 From: Aleksandr Nogikh Date: Thu, 25 Nov 2021 18:41:52 +0000 Subject: tools/syz-testbed: show one stat view at a time In the HTML form, show only one stat view at a time. Let user switch between the views. --- tools/syz-testbed/html.go | 134 ++++++++++++++++++++++++++++++------------- tools/syz-testbed/stats.go | 9 +++ tools/syz-testbed/testbed.go | 13 ++--- 3 files changed, 109 insertions(+), 47 deletions(-) (limited to 'tools') diff --git a/tools/syz-testbed/html.go b/tools/syz-testbed/html.go index 196c12a3c..39d39bcb3 100644 --- a/tools/syz-testbed/html.go +++ b/tools/syz-testbed/html.go @@ -39,8 +39,39 @@ func (ctx *TestbedContext) setupHTTPServer() { }() } -func (ctx *TestbedContext) httpGraph(w http.ResponseWriter, r *http.Request) { +func (ctx *TestbedContext) getCurrentStatView(r *http.Request) (*StatView, error) { + views, err := ctx.GetStatViews() + if err != nil { + return nil, err + } + if len(views) == 0 { + return nil, fmt.Errorf("no stat views available") + } viewName := r.FormValue("view") + if viewName != "" { + var targetView *StatView + for _, view := range views { + if view.Name == viewName { + targetView = &view + break + } + } + if targetView == nil { + return nil, fmt.Errorf("the requested view is not found") + } + return targetView, nil + } + // No specific view is requested. + // First try to find the first non-empty one. + for _, view := range views { + if !view.IsEmpty() { + return &view, nil + } + } + return &views[0], nil +} + +func (ctx *TestbedContext) httpGraph(w http.ResponseWriter, r *http.Request) { over := r.FormValue("over") if ctx.Config.BenchCmp == "" { @@ -48,20 +79,9 @@ func (ctx *TestbedContext) httpGraph(w http.ResponseWriter, r *http.Request) { return } - views, err := ctx.GetStatViews() + targetView, err := ctx.getCurrentStatView(r) if err != nil { - http.Error(w, "failed to retrieve stat views", http.StatusInternalServerError) - return - } - var targetView *StatView - for _, view := range views { - if view.Name == viewName { - targetView = &view - break - } - } - if targetView == nil { - http.Error(w, "the requested view was not found", http.StatusInternalServerError) + http.Error(w, fmt.Sprintf("%s", err), http.StatusInternalServerError) return } @@ -106,33 +126,38 @@ type uiStatView struct { } type uiMainPage struct { - Name string - Summary *Table - Views []uiStatView + Name string + Summary *Table + Views []StatView + ActiveView uiStatView } func (ctx *TestbedContext) httpMain(w http.ResponseWriter, r *http.Request) { - uiViews := []uiStatView{} + activeView, err := ctx.getCurrentStatView(r) + if err != nil { + http.Error(w, fmt.Sprintf("%s", err), http.StatusInternalServerError) + return + } + views, err := ctx.GetStatViews() if err != nil { - log.Printf("%s", err) - views = nil + http.Error(w, fmt.Sprintf("%s", err), http.StatusInternalServerError) + return } - for _, view := range views { - table, err := view.StatsTable() - if err != nil { - log.Printf("stat table generation failed: %s", err) - continue - } - uiViews = append(uiViews, uiStatView{ - Name: view.Name, - Table: table, - }) + + uiView := uiStatView{Name: activeView.Name} + table, err := activeView.StatsTable() + if err != nil { + log.Printf("stat table generation failed: %s", err) + } else { + uiView.Table = table } + data := &uiMainPage{ - Name: ctx.Config.Name, - Summary: ctx.TestbedStatsTable(), - Views: uiViews, + Name: ctx.Config.Name, + Summary: ctx.TestbedStatsTable(), + Views: views, + ActiveView: uiView, } executeTemplate(w, mainTemplate, data) @@ -154,9 +179,41 @@ var mainTemplate = html.CreatePage(` {{.Name }} syzkaller {{HEAD}} + +
+ + + + +
+

syz-testbed "{{.Name }}"

+
+ + + + +
+
+ {{define "Table"}} {{if .}} @@ -178,15 +235,12 @@ var mainTemplate = html.CreatePage(` {{end}} {{end}} -{{.Name }} syz-testbed {{template "Table" .Summary}} -{{range $view := .Views}} -Stat view "{{$view.Name}}"
-Graph over time / -Graph over executions
-{{template "Table" .Table}} -{{end}} +Stat view "{{$.ActiveView.Name}}"
+Graph over time / +Graph over executions
+{{template "Table" .ActiveView.Table}} diff --git a/tools/syz-testbed/stats.go b/tools/syz-testbed/stats.go index 3086e6741..42ce9537b 100644 --- a/tools/syz-testbed/stats.go +++ b/tools/syz-testbed/stats.go @@ -256,3 +256,12 @@ func (view *StatView) SaveAvgBenches(benchDir string) ([]string, error) { } return files, nil } + +func (view *StatView) IsEmpty() bool { + for _, group := range view.Groups { + if group.minResultLength() > 0 { + return false + } + } + return true +} diff --git a/tools/syz-testbed/testbed.go b/tools/syz-testbed/testbed.go index 192784763..12884d0a4 100644 --- a/tools/syz-testbed/testbed.go +++ b/tools/syz-testbed/testbed.go @@ -130,10 +130,9 @@ func (ctx *TestbedContext) GetStatViews() ([]StatView, error) { running := []*RunResult{} for _, instance := range checkout.Running { result, err := instance.FetchResult() - if err != nil { - return nil, err + if err == nil { + running = append(running, result) } - running = append(running, result) } groupsCompleted = append(groupsCompleted, RunResultGroup{ Name: checkout.Name, @@ -145,14 +144,14 @@ func (ctx *TestbedContext) GetStatViews() ([]StatView, error) { }) } return []StatView{ - { - Name: "all", - Groups: groupsAll, - }, { Name: "completed", Groups: groupsCompleted, }, + { + Name: "all", + Groups: groupsAll, + }, }, nil } -- cgit mrf-deployment