aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2024-04-10 09:55:53 +0200
committerDmitry Vyukov <dvyukov@google.com>2024-04-10 08:48:25 +0000
commitbb5e6c0f355e952e91e8aef0ffb51b7b153b2e25 (patch)
tree6f55f9d917850bdb81c53466bc4c5ba136292b92
parent171ec3714ee4886a3f5ecbfe71f63c8f81c7fd7c (diff)
syz-ci: flush coverage report generator
Flush manager coverage report generator after requesting JSONL report. We won't use coverage reports after this point, but it consumes gigs of RAM.
-rw-r--r--syz-ci/manager.go5
-rw-r--r--syz-manager/cover.go35
-rw-r--r--syz-manager/http.go10
3 files changed, 35 insertions, 15 deletions
diff --git a/syz-ci/manager.go b/syz-ci/manager.go
index 542d3950e..38fcc4a77 100644
--- a/syz-ci/manager.go
+++ b/syz-ci/manager.go
@@ -877,7 +877,10 @@ func (mgr *Manager) uploadCoverStat(fuzzingMinutes int) error {
}
defer buildSem.Signal()
- resp, err := mgr.httpGET("/cover?jsonl=1")
+ // Coverage report generation consumes and caches lots of memory.
+ // In the syz-ci context report generation won't be used after this point,
+ // so tell manager to flush report generator.
+ resp, err := mgr.httpGET("/cover?jsonl=1&flush=1")
if err != nil {
return fmt.Errorf("failed to httpGet /cover?jsonl=1 report: %w", err)
}
diff --git a/syz-manager/cover.go b/syz-manager/cover.go
index 9591562b0..31fabeca9 100644
--- a/syz-manager/cover.go
+++ b/syz-manager/cover.go
@@ -12,19 +12,30 @@ import (
"github.com/google/syzkaller/pkg/mgrconfig"
)
-var getReportGenerator = func() func(cfg *mgrconfig.Config,
- modules []host.KernelModule) (*cover.ReportGenerator, error) {
- var once sync.Once
- var rg *cover.ReportGenerator
- var err error
- return func(cfg *mgrconfig.Config, modules []host.KernelModule) (*cover.ReportGenerator, error) {
- once.Do(func() {
- log.Logf(0, "initializing coverage information...")
- rg, err = cover.MakeReportGenerator(cfg, cfg.KernelSubsystem, modules, cfg.RawCover)
- })
- return rg, err
+var (
+ cachedRepGenMu sync.Mutex
+ cachedRepGen *cover.ReportGenerator
+)
+
+func getReportGenerator(cfg *mgrconfig.Config, modules []host.KernelModule) (*cover.ReportGenerator, error) {
+ cachedRepGenMu.Lock()
+ defer cachedRepGenMu.Unlock()
+ if cachedRepGen == nil {
+ log.Logf(0, "initializing coverage information...")
+ rg, err := cover.MakeReportGenerator(cfg, cfg.KernelSubsystem, modules, cfg.RawCover)
+ if err != nil {
+ return nil, err
+ }
+ cachedRepGen = rg
}
-}()
+ return cachedRepGen, nil
+}
+
+func resetReportGenerator() {
+ cachedRepGenMu.Lock()
+ defer cachedRepGenMu.Unlock()
+ cachedRepGen = nil
+}
func coverToPCs(rg *cover.ReportGenerator, cov []uint32) []uint64 {
pcs := make([]uint64, 0, len(cov))
diff --git a/syz-manager/http.go b/syz-manager/http.go
index ddb0707f1..a8c9a8ccd 100644
--- a/syz-manager/http.go
+++ b/syz-manager/http.go
@@ -14,7 +14,7 @@ import (
"os"
"path/filepath"
"regexp"
- "runtime"
+ "runtime/debug"
"sort"
"strconv"
"strings"
@@ -267,6 +267,13 @@ func (mgr *Manager) httpCoverCover(w http.ResponseWriter, r *http.Request, funcF
return
}
+ if r.FormValue("flush") != "" {
+ defer func() {
+ resetReportGenerator()
+ debug.FreeOSMemory()
+ }()
+ }
+
mgr.mu.Lock()
var progs []cover.Prog
if sig := r.FormValue("input"); sig != "" {
@@ -343,7 +350,6 @@ func (mgr *Manager) httpCoverCover(w http.ResponseWriter, r *http.Request, funcF
http.Error(w, fmt.Sprintf("failed to generate coverage profile: %v", err), http.StatusInternalServerError)
return
}
- runtime.GC()
}
func (mgr *Manager) httpCoverFallback(w http.ResponseWriter, r *http.Request) {