Create a highmem pool and put metalava into it
Create a highmem pool based on the total RAM and the number of CPUs,
with an override via the NINJA_HIGHMEM_NUM_JOBS variable. Put
metalava into the highmem pool.
Ninja does not support nested pools, and when goma or RBE is enabled
the maximum ninja parallelism is set very high with local jobs in a
local pool. When both the local pool and highmem pool are enabled,
the total number of local jobs will be as high as the sum of the sizes
of the two pools. Keep the highmem pool limited to 1/16th of the
local pool when remote builds are enabled to try to minimize the
effect while still limiting highmem jobs.
Fixes: 142644983
Test: m nothing, examine pools
Test: m USE_GOMA=true nothing, examine pools
Change-Id: Id79f11f44948992960ac34ecf831dacbe21bd332
diff --git a/ui/build/build.go b/ui/build/build.go
index 1c2d864..de36dce 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -46,8 +46,11 @@
var combinedBuildNinjaTemplate = template.Must(template.New("combined").Parse(`
builddir = {{.OutDir}}
-pool local_pool
+{{if .UseRemoteBuild }}pool local_pool
depth = {{.Parallel}}
+{{end -}}
+pool highmem_pool
+ depth = {{.HighmemParallel}}
build _kati_always_build_: phony
{{if .HasKatiSuffix}}subninja {{.KatiBuildNinjaFile}}
subninja {{.KatiPackageNinjaFile}}
diff --git a/ui/build/config.go b/ui/build/config.go
index c084171..9b19ede 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -722,6 +722,33 @@
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 {
return c.totalRAM
}
@@ -782,10 +809,11 @@
// gomacc) are run in parallel. Note the parallelism of all other jobs is
// still limited by Parallel()
func (c *configImpl) RemoteParallel() int {
- if v, ok := c.environ.Get("NINJA_REMOTE_NUM_JOBS"); ok {
- if i, err := strconv.Atoi(v); err == nil {
- return i
- }
+ if !c.UseRemoteBuild() {
+ return 0
+ }
+ if i, ok := c.environ.GetInt("NINJA_REMOTE_NUM_JOBS"); ok {
+ return i
}
return 500
}
diff --git a/ui/build/config_darwin.go b/ui/build/config_darwin.go
index 480d8d1..fe74e31 100644
--- a/ui/build/config_darwin.go
+++ b/ui/build/config_darwin.go
@@ -22,7 +22,7 @@
func detectTotalRAM(ctx Context) uint64 {
s, err := syscall.Sysctl("hw.memsize")
if err != nil {
- ctx.Printf("Failed to get system memory size: %s")
+ ctx.Printf("Failed to get system memory size: %v", err)
return 0
}
@@ -32,7 +32,7 @@
}
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
}
diff --git a/ui/build/config_linux.go b/ui/build/config_linux.go
index 9e1bdc7..162d372 100644
--- a/ui/build/config_linux.go
+++ b/ui/build/config_linux.go
@@ -20,9 +20,8 @@
var info syscall.Sysinfo_t
err := syscall.Sysinfo(&info)
if err != nil {
- ctx.Printf("Failed to get system memory size: %s")
+ ctx.Printf("Failed to get system memory size: %v", err)
return 0
}
- memBytes := uint64(info.Totalram) * uint64(info.Unit)
- return memBytes
+ return uint64(info.Totalram) * uint64(info.Unit)
}
diff --git a/ui/build/environment.go b/ui/build/environment.go
index d8ff7f2..9bca7c0 100644
--- a/ui/build/environment.go
+++ b/ui/build/environment.go
@@ -19,6 +19,7 @@
"fmt"
"io"
"os"
+ "strconv"
"strings"
)
@@ -44,6 +45,17 @@
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
// if it exists.
func (e *Environment) Set(key, value string) {