aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTaras Madan <tarasmadan@google.com>2024-09-09 11:58:14 +0200
committerTaras Madan <tarasmadan@google.com>2024-09-09 13:32:24 +0000
commitdf6d5ba592799e2e819c8b3447b9a08e7e8d1986 (patch)
tree47eab9f8491b01fad881baa0afad6651f093c07e
parentee18ec07f58b8b246c76570bce69251e735906fe (diff)
dashboard/app: use day long aggregations not week long
Current coverage is a week long data merge for every day. The goal is to show a monthly data by default and make daily data available for &period=day requests. This commit makes the first two steps: 1. Make the day a day long, not a week long aggregation. 2. Enable the month long merges available for &period=month.
-rw-r--r--dashboard/app/graphs.go22
-rw-r--r--pkg/cover/heatmap.go60
-rw-r--r--pkg/coveragedb/time_period.go11
-rw-r--r--pkg/coveragedb/time_period_test.go18
-rw-r--r--tools/syz-cover/syz-cover.go18
5 files changed, 82 insertions, 47 deletions
diff --git a/dashboard/app/graphs.go b/dashboard/app/graphs.go
index f3f62577e..87c7e1403 100644
--- a/dashboard/app/graphs.go
+++ b/dashboard/app/graphs.go
@@ -192,7 +192,7 @@ 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 string, dateFrom, dateTo civil.Date,
+type funcStyleBodyJS func(ctx context.Context, projectID, ns, subsystem string, periods []coveragedb.TimePeriod,
) (template.CSS, template.HTML, template.HTML, error)
func handleCoverageHeatmap(c context.Context, w http.ResponseWriter, r *http.Request) error {
@@ -209,11 +209,21 @@ func handleHeatmap(c context.Context, w http.ResponseWriter, r *http.Request, f
return err
}
ss := r.FormValue("subsystem")
- dateFrom := civil.DateOf(time.Now().Add(-14 * 24 * time.Hour))
- dateTo := civil.DateOf(time.Now())
+ periodType := r.FormValue("period")
+ if periodType == "" {
+ periodType = coveragedb.DayPeriod
+ }
+ if periodType != coveragedb.DayPeriod && periodType != coveragedb.MonthPeriod {
+ return fmt.Errorf("only day and month are allowed, but received %s instead", periodType)
+ }
+ pOps, err := coveragedb.PeriodOps(periodType)
+ if err != nil {
+ return err
+ }
+ periods := coveragedb.GenNPeriodsTill(12, civil.DateOf(time.Now()), pOps)
var style template.CSS
var body, js template.HTML
- if style, body, js, err = f(c, "syzkaller", hdr.Namespace, ss, dateFrom, dateTo); err != nil {
+ if style, body, js, err = f(c, "syzkaller", hdr.Namespace, ss, periods); err != nil {
return fmt.Errorf("failed to generate heatmap: %w", err)
}
return serveTemplate(w, "custom_content.html", struct {
@@ -249,11 +259,11 @@ func handleCoverageGraph(c context.Context, w http.ResponseWriter, r *http.Reque
if err != nil {
return err
}
- periodEndDates := coveragedb.GenNPeriodEndDatesTill(12, civil.DateOf(time.Now()), pOps)
+ periodEndDates := coveragedb.GenNPeriodsTill(12, civil.DateOf(time.Now()), pOps)
cols := []uiGraphColumn{}
for _, periodEndDate := range periodEndDates {
- date := periodEndDate.String()
+ date := periodEndDate.DateTo.String()
if _, ok := hist.covered[date]; !ok || hist.instrumented[date] == 0 {
cols = append(cols, uiGraphColumn{Hint: date, Vals: []uiGraphValue{{IsNull: true}}})
} else {
diff --git a/pkg/cover/heatmap.go b/pkg/cover/heatmap.go
index 63ea96515..7faea553a 100644
--- a/pkg/cover/heatmap.go
+++ b/pkg/cover/heatmap.go
@@ -125,7 +125,7 @@ func filesCoverageToTemplateData(fCov []*fileCoverageWithDetails) *templateHeatm
return &res
}
-func filesCoverageWithDetailsStmt(ns, subsystem string, fromDate, toDate civil.Date) spanner.Statement {
+func filesCoverageWithDetailsStmt(ns, subsystem string, timePeriod coveragedb.TimePeriod) spanner.Statement {
stmt := spanner.Statement{
SQL: `
select
@@ -140,11 +140,11 @@ from merge_history
join file_subsystems
on merge_history.namespace = file_subsystems.namespace and files.filepath = file_subsystems.filepath
where
- merge_history.namespace=$1 and dateto>=$2 and dateto<=$3`,
+ merge_history.namespace=$1 and dateto=$2 and duration=$3`,
Params: map[string]interface{}{
"p1": ns,
- "p2": fromDate,
- "p3": toDate,
+ "p2": timePeriod.DateTo,
+ "p3": timePeriod.Days,
},
}
if subsystem != "" {
@@ -154,7 +154,7 @@ where
return stmt
}
-func filesCoverageWithDetails(ctx context.Context, projectID, ns, subsystem string, fromDate, toDate civil.Date,
+func filesCoverageWithDetails(ctx context.Context, projectID, ns, subsystem string, timePeriods []coveragedb.TimePeriod,
) ([]*fileCoverageWithDetails, error) {
client, err := coveragedb.NewClient(ctx, projectID)
if err != nil {
@@ -162,23 +162,25 @@ func filesCoverageWithDetails(ctx context.Context, projectID, ns, subsystem stri
}
defer client.Close()
- stmt := filesCoverageWithDetailsStmt(ns, subsystem, fromDate, toDate)
- iter := client.Single().Query(ctx, stmt)
- defer iter.Stop()
res := []*fileCoverageWithDetails{}
- for {
- row, err := iter.Next()
- if err == iterator.Done {
- break
- }
- if err != nil {
- return nil, fmt.Errorf("failed to iter.Next() spanner DB: %w", err)
- }
- var r fileCoverageWithDetails
- if err = row.ToStruct(&r); err != nil {
- return nil, fmt.Errorf("failed to row.ToStruct() spanner DB: %w", err)
+ for _, timePeriod := range timePeriods {
+ stmt := filesCoverageWithDetailsStmt(ns, subsystem, timePeriod)
+ iter := client.Single().Query(ctx, stmt)
+ defer iter.Stop()
+ for {
+ row, err := iter.Next()
+ if err == iterator.Done {
+ break
+ }
+ if err != nil {
+ return nil, fmt.Errorf("failed to iter.Next() spanner DB: %w", err)
+ }
+ var r fileCoverageWithDetails
+ if err = row.ToStruct(&r); err != nil {
+ return nil, fmt.Errorf("failed to row.ToStruct() spanner DB: %w", err)
+ }
+ res = append(res, &r)
}
- res = append(res, &r)
}
return res, nil
}
@@ -190,8 +192,8 @@ type StyleBodyJS struct {
}
// nolint: dupl
-func DoDirHeatMap(w io.Writer, projectID, ns string, dateFrom, dateTo civil.Date) error {
- style, body, js, err := DoHeatMapStyleBodyJS(context.Background(), projectID, ns, "", dateFrom, dateTo)
+func DoDirHeatMap(w io.Writer, projectID, ns string, periods []coveragedb.TimePeriod) error {
+ style, body, js, err := DoHeatMapStyleBodyJS(context.Background(), projectID, ns, "", periods)
if err != nil {
return fmt.Errorf("failed to DoHeatMapStyleBodyJS() %w", err)
}
@@ -203,8 +205,8 @@ func DoDirHeatMap(w io.Writer, projectID, ns string, dateFrom, dateTo civil.Date
}
// nolint: dupl
-func DoSubsystemsHeatMap(w io.Writer, projectID, ns string, dateFrom, dateTo civil.Date) error {
- style, body, js, err := DoSubsystemsHeatMapStyleBodyJS(context.Background(), projectID, ns, "", dateFrom, dateTo)
+func DoSubsystemsHeatMap(w io.Writer, projectID, ns string, periods []coveragedb.TimePeriod) error {
+ style, body, js, err := DoSubsystemsHeatMapStyleBodyJS(context.Background(), projectID, ns, "", periods)
if err != nil {
return fmt.Errorf("failed to DoSubsystemsHeatMapStyleBodyJS() %w", err)
}
@@ -232,9 +234,9 @@ func stylesBodyJSTemplate(templData *templateHeatmap,
template.HTML(js.Bytes()), nil
}
-func DoHeatMapStyleBodyJS(ctx context.Context, projectID, ns, subsystem string, dateFrom, dateTo civil.Date,
+func DoHeatMapStyleBodyJS(ctx context.Context, projectID, ns, subsystem string, periods []coveragedb.TimePeriod,
) (template.CSS, template.HTML, template.HTML, error) {
- covAndDates, err := filesCoverageWithDetails(ctx, projectID, ns, subsystem, dateFrom, dateTo)
+ covAndDates, err := filesCoverageWithDetails(ctx, projectID, ns, subsystem, periods)
if err != nil {
return "", "", "", fmt.Errorf("failed to filesCoverageWithDetails: %w", err)
}
@@ -242,9 +244,9 @@ func DoHeatMapStyleBodyJS(ctx context.Context, projectID, ns, subsystem string,
return stylesBodyJSTemplate(templData)
}
-func DoSubsystemsHeatMapStyleBodyJS(ctx context.Context, projectID, ns, subsystem string, dateFrom, dateTo civil.Date,
-) (template.CSS, template.HTML, template.HTML, error) {
- covWithDetails, err := filesCoverageWithDetails(ctx, projectID, ns, subsystem, dateFrom, dateTo)
+func DoSubsystemsHeatMapStyleBodyJS(ctx context.Context, projectID, ns, subsystem string,
+ periods []coveragedb.TimePeriod) (template.CSS, template.HTML, template.HTML, error) {
+ covWithDetails, err := filesCoverageWithDetails(ctx, projectID, ns, subsystem, periods)
if err != nil {
panic(err)
}
diff --git a/pkg/coveragedb/time_period.go b/pkg/coveragedb/time_period.go
index b3a2aad73..bfa1b2789 100644
--- a/pkg/coveragedb/time_period.go
+++ b/pkg/coveragedb/time_period.go
@@ -17,6 +17,7 @@ type TimePeriod struct {
}
const (
+ DayPeriod = "day"
MonthPeriod = "month"
QuarterPeriod = "quarter"
)
@@ -25,6 +26,8 @@ var errUnknownTimePeriodType = errors.New("unknown time period type")
func MinMaxDays(periodType string) (int, int, error) {
switch periodType {
+ case DayPeriod:
+ return 1, 1, nil
case MonthPeriod:
return 28, 31, nil
case QuarterPeriod:
@@ -36,6 +39,8 @@ func MinMaxDays(periodType string) (int, int, error) {
func PeriodOps(periodType string) (periodOps, error) {
switch periodType {
+ case DayPeriod:
+ return &DayPeriodOps{}, nil
case MonthPeriod:
return &MonthPeriodOps{}, nil
case QuarterPeriod:
@@ -51,11 +56,11 @@ type periodOps interface {
pointedPeriodDays(d civil.Date) int
}
-func GenNPeriodEndDatesTill(n int, d civil.Date, po periodOps) []civil.Date {
- var res []civil.Date
+func GenNPeriodsTill(n int, d civil.Date, po periodOps) []TimePeriod {
+ var res []TimePeriod
for i := 0; i < n; i++ {
d = po.lastPeriodDate(d)
- res = append(res, d)
+ res = append(res, TimePeriod{DateTo: d, Days: po.pointedPeriodDays(d)})
d = d.AddDays(-po.pointedPeriodDays(d))
}
slices.Reverse(res)
diff --git a/pkg/coveragedb/time_period_test.go b/pkg/coveragedb/time_period_test.go
index 86201e4db..4ccd18f12 100644
--- a/pkg/coveragedb/time_period_test.go
+++ b/pkg/coveragedb/time_period_test.go
@@ -25,8 +25,10 @@ func TestDayPeriodOps(t *testing.T) {
assert.Equal(t, 1, ops.pointedPeriodDays(d))
assert.Equal(t,
- []civil.Date{{Year: 2024, Month: time.February, Day: 19}, {Year: 2024, Month: time.February, Day: 20}},
- GenNPeriodEndDatesTill(2, d, ops))
+ []TimePeriod{
+ {DateTo: civil.Date{Year: 2024, Month: time.February, Day: 19}, Days: 1},
+ {DateTo: civil.Date{Year: 2024, Month: time.February, Day: 20}, Days: 1}},
+ GenNPeriodsTill(2, d, ops))
}
func TestMonthPeriodOps(t *testing.T) {
@@ -48,8 +50,10 @@ func TestMonthPeriodOps(t *testing.T) {
assert.Equal(t, 29, ops.pointedPeriodDays(midMonthDate))
assert.Equal(t,
- []civil.Date{{Year: 2024, Month: time.January, Day: 31}, {Year: 2024, Month: time.February, Day: 29}},
- GenNPeriodEndDatesTill(2, goodPeriod.DateTo, ops))
+ []TimePeriod{
+ {DateTo: civil.Date{Year: 2024, Month: time.January, Day: 31}, Days: 31},
+ {DateTo: civil.Date{Year: 2024, Month: time.February, Day: 29}, Days: 29}},
+ GenNPeriodsTill(2, goodPeriod.DateTo, ops))
}
func TestQuarterPeriodOps(t *testing.T) {
@@ -72,8 +76,10 @@ func TestQuarterPeriodOps(t *testing.T) {
assert.Equal(t, 31+29+31, ops.pointedPeriodDays(midQuarterDate))
assert.Equal(t,
- []civil.Date{{Year: 2023, Month: time.December, Day: 31}, {Year: 2024, Month: time.March, Day: 31}},
- GenNPeriodEndDatesTill(2, goodPeriod.DateTo, ops))
+ []TimePeriod{
+ {DateTo: civil.Date{Year: 2023, Month: time.December, Day: 31}, Days: 31 + 30 + 31},
+ {DateTo: civil.Date{Year: 2024, Month: time.March, Day: 31}, Days: 31 + 29 + 31}},
+ GenNPeriodsTill(2, goodPeriod.DateTo, ops))
}
func TestPeriodsToMerge(t *testing.T) {
diff --git a/tools/syz-cover/syz-cover.go b/tools/syz-cover/syz-cover.go
index dc10a14a9..bfab129da 100644
--- a/tools/syz-cover/syz-cover.go
+++ b/tools/syz-cover/syz-cover.go
@@ -37,6 +37,7 @@ import (
"cloud.google.com/go/civil"
"github.com/google/syzkaller/pkg/cover"
"github.com/google/syzkaller/pkg/cover/backend"
+ "github.com/google/syzkaller/pkg/coveragedb"
"github.com/google/syzkaller/pkg/log"
"github.com/google/syzkaller/pkg/mgrconfig"
"github.com/google/syzkaller/pkg/osutil"
@@ -81,17 +82,28 @@ func parseDates() (civil.Date, civil.Date) {
return dateFrom, dateTo
}
+func periodsFromDays(from, to civil.Date) []coveragedb.TimePeriod {
+ if to.Before(from) {
+ panic("toDay can't be less than fromDay")
+ }
+ res := []coveragedb.TimePeriod{{DateTo: from, Days: 1}}
+ for ; from.Before(to); from = from.AddDays(1) {
+ res = append(res, coveragedb.TimePeriod{DateTo: from, Days: 1})
+ }
+ return res
+}
+
func toolBuildNsHeatmap() {
buf := new(bytes.Buffer)
- dateFrom, dateTo := parseDates()
+ periods := periodsFromDays(parseDates())
var err error
switch *flagNsHeatmapGroupBy {
case "dir":
- if err = cover.DoDirHeatMap(buf, *flagProjectID, *flagNsHeatmap, dateFrom, dateTo); err != nil {
+ if err = cover.DoDirHeatMap(buf, *flagProjectID, *flagNsHeatmap, periods); err != nil {
tool.Fail(err)
}
case "subsystem":
- if err = cover.DoSubsystemsHeatMap(buf, *flagProjectID, *flagNsHeatmap, dateFrom, dateTo); err != nil {
+ if err = cover.DoSubsystemsHeatMap(buf, *flagProjectID, *flagNsHeatmap, periods); err != nil {
tool.Fail(err)
}
default: