Fatal error on insufficient resource to use Goma in Soong UI.
As suggested in
https://android-review.googlesource.com/c/platform/build/soong/+/839293
I am moving some features in goma.mk to goma.go in Soong UI.
With this CL, let me implement ulimit check to Soong UI.
Test: export USE_GOMA=true
Test: launch aosp_arm-eng
Test: make
Test: the command succeeds if "ulimit -n" and "ulimit -u" are large enough.
Test: Otherwise, it shows error. I confirmed both cases.
Change-Id: I5d7d5ed71f620302a0d635770d1a51a2baab51fd
Signed-off-by: Yoshisato Yanagisawa <yyanagisawa@google.com>
diff --git a/ui/build/goma.go b/ui/build/goma.go
index d0dc9cf..015a7c7 100644
--- a/ui/build/goma.go
+++ b/ui/build/goma.go
@@ -15,34 +15,65 @@
package build
import (
- "errors"
+ "fmt"
+ "math"
"path/filepath"
+ "strconv"
+ "strings"
"android/soong/ui/metrics"
)
const gomaCtlScript = "goma_ctl.py"
+const gomaLeastNProcs = 2500
+const gomaLeastNFiles = 16000
-var gomaCtlNotFound = errors.New("goma_ctl.py not found")
+// ulimit returns ulimit result for |opt|.
+// if the resource is unlimited, it returns math.MaxInt32 so that a caller do
+// not need special handling of the returned value.
+//
+// Note that since go syscall package do not have RLIMIT_NPROC constant,
+// we use bash ulimit instead.
+func ulimitOrFatal(ctx Context, config Config, opt string) int {
+ commandText := fmt.Sprintf("ulimit %s", opt)
+ cmd := Command(ctx, config, commandText, "bash", "-c", commandText)
+ output := strings.TrimRight(string(cmd.CombinedOutputOrFatal()), "\n")
+ ctx.Verbose(output + "\n")
+ ctx.Verbose("done\n")
-func startGoma(ctx Context, config Config) error {
+ if output == "unlimited" {
+ return math.MaxInt32
+ }
+ num, err := strconv.Atoi(output)
+ if err != nil {
+ ctx.Fatalf("ulimit returned unexpected value: %s: %v\n", opt, err)
+ }
+ return num
+}
+
+func startGoma(ctx Context, config Config) {
ctx.BeginTrace(metrics.RunSetupTool, "goma_ctl")
defer ctx.EndTrace()
+ if u := ulimitOrFatal(ctx, config, "-u"); u < gomaLeastNProcs {
+ ctx.Fatalf("max user processes is insufficient: %d; want >= %d.\n", u, gomaLeastNProcs)
+ }
+ if n := ulimitOrFatal(ctx, config, "-n"); n < gomaLeastNFiles {
+ ctx.Fatalf("max open files is insufficient: %d; want >= %d.\n", n, gomaLeastNFiles)
+ }
+
var gomaCtl string
if gomaDir, ok := config.Environment().Get("GOMA_DIR"); ok {
gomaCtl = filepath.Join(gomaDir, gomaCtlScript)
} else if home, ok := config.Environment().Get("HOME"); ok {
gomaCtl = filepath.Join(home, "goma", gomaCtlScript)
} else {
- return gomaCtlNotFound
+ ctx.Fatalln("goma_ctl.py not found")
}
cmd := Command(ctx, config, "goma_ctl.py ensure_start", gomaCtl, "ensure_start")
if err := cmd.Run(); err != nil {
- ctx.Fatalf("goma_ctl.py ensure_start failed with: %v", err)
+ ctx.Fatalf("goma_ctl.py ensure_start failed with: %v\n", err)
}
-
- return nil
}