diff --git a/dashboard/app/graphs.go b/dashboard/app/graphs.go
index 54520820f942..9918f9200dac 100644
--- a/dashboard/app/graphs.go
+++ b/dashboard/app/graphs.go
@@ -10,6 +10,7 @@ import (
"net/http"
"net/url"
"regexp"
+ "slices"
"sort"
"strconv"
"time"
@@ -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)
@@ -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 {
diff --git a/dashboard/app/static/coverage.js b/dashboard/app/static/coverage.js
index 16eb4fcd7e1f..5a17ad0a9e5b 100644
--- a/dashboard/app/static/coverage.js
+++ b/dashboard/app/static/coverage.js
@@ -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(){
@@ -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
s.
diff --git a/pkg/cover/heatmap.go b/pkg/cover/heatmap.go
index 903294095568..b8e3bbfa6690 100644
--- a/pkg/cover/heatmap.go
+++ b/pkg/cover/heatmap.go
@@ -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,
@@ -188,8 +190,8 @@ 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())
@@ -197,8 +199,8 @@ func filesCoverageWithDetails(ctx context.Context, projectID, ns, subsystem, man
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 {
@@ -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)
}
@@ -274,6 +285,7 @@ func DoSubsystemsHeatMapStyleBodyJS(ctx context.Context, projectID, ns, subsyste
}
}
templData := filesCoverageToTemplateData(ssCovAndDates)
+ templData.Managers = managers
return stylesBodyJSTemplate(templData)
}
diff --git a/pkg/cover/templates/heatmap.html b/pkg/cover/templates/heatmap.html
index fc1b457c9998..5dd951afe7b0 100644
--- a/pkg/cover/templates/heatmap.html
+++ b/pkg/cover/templates/heatmap.html
@@ -104,6 +104,44 @@
{{ end }}
{{ define "body" }}
+
+