Merge "Create a highmem pool and put metalava into it"

This commit is contained in:
Treehugger Robot 2020-01-25 01:09:43 +00:00 committed by Gerrit Code Review
commit 6cc0515e82
13 changed files with 95 additions and 13 deletions

View File

@ -827,6 +827,10 @@ func (c *config) UseRBE() bool {
return Bool(c.productVariables.UseRBE) return Bool(c.productVariables.UseRBE)
} }
func (c *config) UseRemoteBuild() bool {
return c.UseGoma() || c.UseRBE()
}
func (c *config) RunErrorProne() bool { func (c *config) RunErrorProne() bool {
return c.IsEnvTrue("RUN_ERROR_PRONE") return c.IsEnvTrue("RUN_ERROR_PRONE")
} }

View File

@ -99,6 +99,9 @@ var (
// Used only when USE_GOMA=true is set, to restrict non-goma jobs to the local parallelism value // Used only when USE_GOMA=true is set, to restrict non-goma jobs to the local parallelism value
localPool = blueprint.NewBuiltinPool("local_pool") localPool = blueprint.NewBuiltinPool("local_pool")
// Used for processes that need significant RAM to ensure there are not too many running in parallel.
highmemPool = blueprint.NewBuiltinPool("highmem_pool")
) )
func init() { func init() {

View File

@ -1351,7 +1351,7 @@ func (m *moduleContext) Variable(pctx PackageContext, name, value string) {
func (m *moduleContext) Rule(pctx PackageContext, name string, params blueprint.RuleParams, func (m *moduleContext) Rule(pctx PackageContext, name string, params blueprint.RuleParams,
argNames ...string) blueprint.Rule { argNames ...string) blueprint.Rule {
if (m.config.UseGoma() || m.config.UseRBE()) && params.Pool == nil { if m.config.UseRemoteBuild() && params.Pool == nil {
// When USE_GOMA=true or USE_RBE=true are set and the rule is not supported by goma/RBE, restrict // When USE_GOMA=true or USE_RBE=true are set and the rule is not supported by goma/RBE, restrict
// jobs to the local parallelism value // jobs to the local parallelism value
params.Pool = localPool params.Pool = localPool

View File

@ -109,7 +109,7 @@ func (p PackageContext) RuleFunc(name string,
if len(ctx.errors) > 0 { if len(ctx.errors) > 0 {
return params, ctx.errors[0] return params, ctx.errors[0]
} }
if (ctx.Config().UseGoma() || ctx.Config().UseRBE()) && params.Pool == nil { if ctx.Config().UseRemoteBuild() && params.Pool == nil {
// When USE_GOMA=true or USE_RBE=true are set and the rule is not supported by // When USE_GOMA=true or USE_RBE=true are set and the rule is not supported by
// goma/RBE, restrict jobs to the local parallelism value // goma/RBE, restrict jobs to the local parallelism value
params.Pool = localPool params.Pool = localPool

View File

@ -33,6 +33,8 @@ type RuleBuilder struct {
temporariesSet map[WritablePath]bool temporariesSet map[WritablePath]bool
restat bool restat bool
sbox bool sbox bool
highmem bool
remoteable RemoteRuleSupports
sboxOutDir WritablePath sboxOutDir WritablePath
missingDeps []string missingDeps []string
} }
@ -87,6 +89,19 @@ func (r *RuleBuilder) Restat() *RuleBuilder {
return r return r
} }
// HighMem marks the rule as a high memory rule, which will limit how many run in parallel with other high memory
// rules.
func (r *RuleBuilder) HighMem() *RuleBuilder {
r.highmem = true
return r
}
// Remoteable marks the rule as supporting remote execution.
func (r *RuleBuilder) Remoteable(supports RemoteRuleSupports) *RuleBuilder {
r.remoteable = supports
return r
}
// Sbox marks the rule as needing to be wrapped by sbox. The WritablePath should point to the output // Sbox marks the rule as needing to be wrapped by sbox. The WritablePath should point to the output
// directory that sbox will wipe. It should not be written to by any other rule. sbox will ensure // directory that sbox will wipe. It should not be written to by any other rule. sbox will ensure
// that all outputs have been written, and will discard any output files that were not specified. // that all outputs have been written, and will discard any output files that were not specified.
@ -401,6 +416,17 @@ func (r *RuleBuilder) Build(pctx PackageContext, ctx BuilderContext, name string
rspFileContent = "$in" rspFileContent = "$in"
} }
var pool blueprint.Pool
if ctx.Config().UseGoma() && r.remoteable&SUPPORTS_GOMA != 0 {
// When USE_GOMA=true is set and the rule is supported by goma, allow jobs to run outside the local pool.
} else if ctx.Config().UseRBE() && r.remoteable&SUPPORTS_RBE != 0 {
// When USE_GOMA=true is set and the rule is supported by RBE, allow jobs to run outside the local pool.
} else if r.highmem {
pool = highmemPool
} else if ctx.Config().UseRemoteBuild() {
pool = localPool
}
ctx.Build(pctx, BuildParams{ ctx.Build(pctx, BuildParams{
Rule: ctx.Rule(pctx, name, blueprint.RuleParams{ Rule: ctx.Rule(pctx, name, blueprint.RuleParams{
Command: commandString, Command: commandString,
@ -408,6 +434,7 @@ func (r *RuleBuilder) Build(pctx PackageContext, ctx BuilderContext, name string
Restat: r.restat, Restat: r.restat,
Rspfile: rspFile, Rspfile: rspFile,
RspfileContent: rspFileContent, RspfileContent: rspFileContent,
Pool: pool,
}), }),
Inputs: rspFileInputs, Inputs: rspFileInputs,
Implicits: r.Inputs(), Implicits: r.Inputs(),

View File

@ -128,7 +128,7 @@ func (s *singletonContextAdaptor) Variable(pctx PackageContext, name, value stri
} }
func (s *singletonContextAdaptor) Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule { func (s *singletonContextAdaptor) Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule {
if (s.Config().UseGoma() || s.Config().UseRBE()) && params.Pool == nil { if s.Config().UseRemoteBuild() && params.Pool == nil {
// When USE_GOMA=true or USE_RBE=true are set and the rule is not supported by goma/RBE, restrict // When USE_GOMA=true or USE_RBE=true are set and the rule is not supported by goma/RBE, restrict
// jobs to the local parallelism value // jobs to the local parallelism value
params.Pool = localPool params.Pool = localPool

View File

@ -174,6 +174,10 @@ func main() {
stat.AddOutput(status.NewProtoErrorLog(log, filepath.Join(logsDir, c.logsPrefix+"build_error"))) stat.AddOutput(status.NewProtoErrorLog(log, filepath.Join(logsDir, c.logsPrefix+"build_error")))
stat.AddOutput(status.NewCriticalPath(log)) stat.AddOutput(status.NewCriticalPath(log))
buildCtx.Verbosef("Detected %.3v GB total RAM", float32(config.TotalRAM())/(1024*1024*1024))
buildCtx.Verbosef("Parallelism (local/remote/highmem): %v/%v/%v",
config.Parallel(), config.RemoteParallel(), config.HighmemParallel())
defer met.Dump(filepath.Join(logsDir, c.logsPrefix+"soong_metrics")) defer met.Dump(filepath.Join(logsDir, c.logsPrefix+"soong_metrics"))
if start, ok := os.LookupEnv("TRACE_BEGIN_SOONG"); ok { if start, ok := os.LookupEnv("TRACE_BEGIN_SOONG"); ok {

View File

@ -1456,6 +1456,8 @@ func (d *Droidstubs) apiToXmlFlags(ctx android.ModuleContext, cmd *android.RuleB
func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersion javaVersion, srcs android.Paths, func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersion javaVersion, srcs android.Paths,
srcJarList android.Path, bootclasspath, classpath classpath, sourcepaths android.Paths) *android.RuleBuilderCommand { srcJarList android.Path, bootclasspath, classpath classpath, sourcepaths android.Paths) *android.RuleBuilderCommand {
// Metalava uses lots of memory, restrict the number of metalava jobs that can run in parallel.
rule.HighMem()
cmd := rule.Command().BuiltTool(ctx, "metalava"). cmd := rule.Command().BuiltTool(ctx, "metalava").
Flag(config.JavacVmFlags). Flag(config.JavacVmFlags).
FlagWithArg("-encoding ", "UTF-8"). FlagWithArg("-encoding ", "UTF-8").

View File

@ -48,8 +48,11 @@ func SetupOutDir(ctx Context, config Config) {
var combinedBuildNinjaTemplate = template.Must(template.New("combined").Parse(` var combinedBuildNinjaTemplate = template.Must(template.New("combined").Parse(`
builddir = {{.OutDir}} builddir = {{.OutDir}}
pool local_pool {{if .UseRemoteBuild }}pool local_pool
depth = {{.Parallel}} depth = {{.Parallel}}
{{end -}}
pool highmem_pool
depth = {{.HighmemParallel}}
build _kati_always_build_: phony build _kati_always_build_: phony
{{if .HasKatiSuffix}}subninja {{.KatiBuildNinjaFile}} {{if .HasKatiSuffix}}subninja {{.KatiBuildNinjaFile}}
subninja {{.KatiPackageNinjaFile}} subninja {{.KatiPackageNinjaFile}}

View File

@ -722,6 +722,33 @@ func (c *configImpl) Parallel() int {
return c.parallel return c.parallel
} }
func (c *configImpl) HighmemParallel() int {
if i, ok := c.environ.GetInt("NINJA_HIGHMEM_NUM_JOBS"); ok {
return i
}
const minMemPerHighmemProcess = 8 * 1024 * 1024 * 1024
parallel := c.Parallel()
if c.UseRemoteBuild() {
// Ninja doesn't support nested pools, and when remote builds are enabled the total ninja parallelism
// is set very high (i.e. 500). Using a large value here would cause the total number of running jobs
// to be the sum of the sizes of the local and highmem pools, which will cause extra CPU contention.
// Return 1/16th of the size of the local pool, rounding up.
return (parallel + 15) / 16
} else if c.totalRAM == 0 {
// Couldn't detect the total RAM, don't restrict highmem processes.
return parallel
} else if c.totalRAM <= 32*1024*1024*1024 {
// Less than 32GB of ram, restrict to 2 highmem processes
return 2
} else if p := int(c.totalRAM / minMemPerHighmemProcess); p < parallel {
// If less than 8GB total RAM per process, reduce the number of highmem processes
return p
}
// No restriction on highmem processes
return parallel
}
func (c *configImpl) TotalRAM() uint64 { func (c *configImpl) TotalRAM() uint64 {
return c.totalRAM return c.totalRAM
} }
@ -782,10 +809,11 @@ func (c *configImpl) UseRemoteBuild() bool {
// gomacc) are run in parallel. Note the parallelism of all other jobs is // gomacc) are run in parallel. Note the parallelism of all other jobs is
// still limited by Parallel() // still limited by Parallel()
func (c *configImpl) RemoteParallel() int { func (c *configImpl) RemoteParallel() int {
if v, ok := c.environ.Get("NINJA_REMOTE_NUM_JOBS"); ok { if !c.UseRemoteBuild() {
if i, err := strconv.Atoi(v); err == nil { return 0
return i }
} if i, ok := c.environ.GetInt("NINJA_REMOTE_NUM_JOBS"); ok {
return i
} }
return 500 return 500
} }

View File

@ -22,7 +22,7 @@ import (
func detectTotalRAM(ctx Context) uint64 { func detectTotalRAM(ctx Context) uint64 {
s, err := syscall.Sysctl("hw.memsize") s, err := syscall.Sysctl("hw.memsize")
if err != nil { if err != nil {
ctx.Printf("Failed to get system memory size: %s") ctx.Printf("Failed to get system memory size: %v", err)
return 0 return 0
} }
@ -32,7 +32,7 @@ func detectTotalRAM(ctx Context) uint64 {
} }
if len(s) != 8 { if len(s) != 8 {
ctx.Printf("Failed to get system memory size, returned %d bytes, 8", len(s)) ctx.Printf("Failed to get system memory size, returned %d bytes, expecting 8 bytes", len(s))
return 0 return 0
} }

View File

@ -20,9 +20,8 @@ func detectTotalRAM(ctx Context) uint64 {
var info syscall.Sysinfo_t var info syscall.Sysinfo_t
err := syscall.Sysinfo(&info) err := syscall.Sysinfo(&info)
if err != nil { if err != nil {
ctx.Printf("Failed to get system memory size: %s") ctx.Printf("Failed to get system memory size: %v", err)
return 0 return 0
} }
memBytes := uint64(info.Totalram) * uint64(info.Unit) return uint64(info.Totalram) * uint64(info.Unit)
return memBytes
} }

View File

@ -19,6 +19,7 @@ import (
"fmt" "fmt"
"io" "io"
"os" "os"
"strconv"
"strings" "strings"
) )
@ -44,6 +45,17 @@ func (e *Environment) Get(key string) (string, bool) {
return "", false return "", false
} }
// Get returns the int value associated with the key, and whether it exists
// and is a valid int.
func (e *Environment) GetInt(key string) (int, bool) {
if v, ok := e.Get(key); ok {
if i, err := strconv.Atoi(v); err == nil {
return i, true
}
}
return 0, false
}
// Set sets the value associated with the key, overwriting the current value // Set sets the value associated with the key, overwriting the current value
// if it exists. // if it exists.
func (e *Environment) Set(key, value string) { func (e *Environment) Set(key, value string) {