From bb5e6c0f355e952e91e8aef0ffb51b7b153b2e25 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Wed, 10 Apr 2024 09:55:53 +0200 Subject: 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. --- syz-ci/manager.go | 5 ++++- syz-manager/cover.go | 35 +++++++++++++++++++++++------------ syz-manager/http.go | 10 ++++++++-- 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) { -- cgit mrf-deployment