Skip to content

Commit

Permalink
dashboard/app: add targeting controls to the coverage page
Browse files Browse the repository at this point in the history
It allows to control known parameters:
1. Period (months or days).
2. Target subsystem.
3. Target manager.

And adds the disabled "Only unique" checkbox.
  • Loading branch information
tarasmadan committed Jan 9, 2025
1 parent 9220929 commit 7cc1700
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 16 deletions.
26 changes: 23 additions & 3 deletions dashboard/app/graphs.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"net/http"
"net/url"
"regexp"
"slices"
"sort"
"strconv"
"time"
Expand Down Expand Up @@ -194,8 +195,8 @@ func handleFoundBugsGraph(c context.Context, w http.ResponseWriter, r *http.Requ
return serveTemplate(w, "graph_histogram.html", data)
}

type funcStyleBodyJS func(ctx context.Context, projectID, ns, subsystem, manager string,
periods []coveragedb.TimePeriod) (template.CSS, template.HTML, template.HTML, error)
type funcStyleBodyJS func(ctx context.Context, projectID string, scope *cover.SelectScope, sss, managers []string,
) (template.CSS, template.HTML, template.HTML, error)

func handleCoverageHeatmap(c context.Context, w http.ResponseWriter, r *http.Request) error {
return handleHeatmap(c, w, r, cover.DoHeatMapStyleBodyJS)
Expand Down Expand Up @@ -235,9 +236,28 @@ func handleHeatmap(c context.Context, w http.ResponseWriter, r *http.Request, f
if err != nil {
return fmt.Errorf("%s: %w", err.Error(), ErrClientBadRequest)
}
managers, err := CachedManagerList(c, hdr.Namespace)
if err != nil {
return err
}
ssService := getNsConfig(c, hdr.Namespace).Subsystems.Service
var subsystems []string
for _, ss := range ssService.List() {
subsystems = append(subsystems, ss.Name)
}
slices.Sort(managers)
slices.Sort(subsystems)

var style template.CSS
var body, js template.HTML
if style, body, js, err = f(c, "syzkaller", hdr.Namespace, ss, manager, periods); err != nil {
if style, body, js, err = f(c, "syzkaller",
&cover.SelectScope{
Ns: hdr.Namespace,
Subsystem: ss,
Manager: manager,
Periods: periods,
},
subsystems, managers); err != nil {
return fmt.Errorf("failed to generate heatmap: %w", err)
}
return serveTemplate(w, "custom_content.html", struct {
Expand Down
11 changes: 10 additions & 1 deletion dashboard/app/static/coverage.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
// Copyright 2024 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

initTogglers();
$(document).ready(initTogglers());
$(document).ready(initUpdateForm);

// Initializes the file tree onClick collapse logic.
function initTogglers(){
Expand All @@ -11,6 +12,14 @@ function initTogglers(){
});
}

function initUpdateForm(){
var curUrlParams = new URLSearchParams(window.location.search);
$('#target-period').val(curUrlParams.get('period'));
$('#target-subsystem').val(curUrlParams.get('subsystem'));
$('#target-manager').val(curUrlParams.get('manager'));
$("#only-unique").prop("checked", curUrlParams.get('subsystem') == "1");
}

// This handler is called when user clicks on the coverage percentage.
// It downloads the kernel file coverage html block and adjust page to show it.
// "#file-content-prev" and "#file-content-curr" are the file content <div>s.
Expand Down
36 changes: 24 additions & 12 deletions pkg/cover/heatmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,10 @@ type templateHeatmapRow struct {
}

type templateHeatmap struct {
Root *templateHeatmapRow
Periods []string
Root *templateHeatmapRow
Periods []string
Subsystems []string
Managers []string
}

func (thm *templateHeatmapRow) addParts(depth int, pathLeft []string, filePath string, instrumented, covered int64,
Expand Down Expand Up @@ -188,17 +190,17 @@ where
return stmt
}

func filesCoverageWithDetails(ctx context.Context, projectID, ns, subsystem, manager string,
timePeriods []coveragedb.TimePeriod) ([]*fileCoverageWithDetails, error) {
func filesCoverageWithDetails(ctx context.Context, projectID string, scope *SelectScope,
) ([]*fileCoverageWithDetails, error) {
client, err := spannerclient.NewClient(ctx, projectID)
if err != nil {
return nil, fmt.Errorf("spanner.NewClient() failed: %s", err.Error())
}
defer client.Close()

res := []*fileCoverageWithDetails{}
for _, timePeriod := range timePeriods {
stmt := filesCoverageWithDetailsStmt(ns, subsystem, manager, timePeriod)
for _, timePeriod := range scope.Periods {
stmt := filesCoverageWithDetailsStmt(scope.Ns, scope.Subsystem, scope.Manager, timePeriod)
iter := client.Single().Query(ctx, stmt)
defer iter.Stop()
for {
Expand Down Expand Up @@ -243,19 +245,28 @@ func stylesBodyJSTemplate(templData *templateHeatmap,
template.HTML(js.Bytes()), nil
}

func DoHeatMapStyleBodyJS(ctx context.Context, projectID, ns, subsystem, manager string,
periods []coveragedb.TimePeriod) (template.CSS, template.HTML, template.HTML, error) {
covAndDates, err := filesCoverageWithDetails(ctx, projectID, ns, subsystem, manager, periods)
type SelectScope struct {
Ns string
Subsystem string
Manager string
Periods []coveragedb.TimePeriod
}

func DoHeatMapStyleBodyJS(ctx context.Context, projectID string, scope *SelectScope, sss, managers []string,
) (template.CSS, template.HTML, template.HTML, error) {
covAndDates, err := filesCoverageWithDetails(ctx, projectID, scope)
if err != nil {
return "", "", "", fmt.Errorf("failed to filesCoverageWithDetails: %w", err)
}
templData := filesCoverageToTemplateData(covAndDates)
templData.Subsystems = sss
templData.Managers = managers
return stylesBodyJSTemplate(templData)
}

func DoSubsystemsHeatMapStyleBodyJS(ctx context.Context, projectID, ns, subsystem, manager string,
periods []coveragedb.TimePeriod) (template.CSS, template.HTML, template.HTML, error) {
covWithDetails, err := filesCoverageWithDetails(ctx, projectID, ns, subsystem, manager, periods)
func DoSubsystemsHeatMapStyleBodyJS(ctx context.Context, projectID string, scope *SelectScope, sss, managers []string,
) (template.CSS, template.HTML, template.HTML, error) {
covWithDetails, err := filesCoverageWithDetails(ctx, projectID, scope)
if err != nil {
panic(err)
}
Expand All @@ -274,6 +285,7 @@ func DoSubsystemsHeatMapStyleBodyJS(ctx context.Context, projectID, ns, subsyste
}
}
templData := filesCoverageToTemplateData(ssCovAndDates)
templData.Managers = managers
return stylesBodyJSTemplate(templData)
}

Expand Down
38 changes: 38 additions & 0 deletions pkg/cover/templates/heatmap.html
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,44 @@
{{ end }}

{{ define "body" }}
<div style="display:inline-block">
<form method="get">
<div style="display:inline-block; vertical-align: top">
<label for="target-period">Periods:</label>
<br>
<label for="target-subsystem">Subsystem:</label>
<br>
<label for="target-manager">Manager:</label>
<br>
<label for="only-unique">Only unique:</label>
</div>
<div style="display:inline-block; vertical-align: top">
<select id="target-period" name="period">
<option value="month">Month</option>
<option value="day">Day</option>
</select>
<br>
<select id="target-subsystem" name="subsystem">
<option value="">*</option>
{{ range $ss := .Subsystems }}
<option value="{{ $ss }}">{{ $ss }}</option>
{{ end }}
</select>
<br>
<select id="target-manager" name="manager">
<option value="">*</option>
{{ range $manager := .Managers }}
<option value="{{ $manager }}">{{ $manager }}</option>
{{ end }}
</select>
<br>
<input type="checkbox" id="only-unique" name="unique-only" disabled>
</div>
<br>
<button id="updateButton">Update</button>
</form>
</div>
<hr>
<div style="white-space: nowrap">
<div style="display:inline-block">
<ul id="collapsible-list">
Expand Down

0 comments on commit 7cc1700

Please sign in to comment.