1// Copyright 2018 Google Inc. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package build 16 17import ( 18 "fmt" 19 "math" 20 "path/filepath" 21 "strconv" 22 "strings" 23 24 "android/soong/ui/metrics" 25) 26 27const gomaCtlScript = "goma_ctl.py" 28const gomaLeastNProcs = 2500 29const gomaLeastNFiles = 16000 30 31// ulimit returns ulimit result for |opt|. 32// if the resource is unlimited, it returns math.MaxInt32 so that a caller do 33// not need special handling of the returned value. 34// 35// Note that since go syscall package do not have RLIMIT_NPROC constant, 36// we use bash ulimit instead. 37func ulimitOrFatal(ctx Context, config Config, opt string) int { 38 commandText := fmt.Sprintf("ulimit %s", opt) 39 cmd := Command(ctx, config, commandText, "bash", "-c", commandText) 40 output := strings.TrimRight(string(cmd.CombinedOutputOrFatal()), "\n") 41 ctx.Verbose(output + "\n") 42 ctx.Verbose("done\n") 43 44 if output == "unlimited" { 45 return math.MaxInt32 46 } 47 num, err := strconv.Atoi(output) 48 if err != nil { 49 ctx.Fatalf("ulimit returned unexpected value: %s: %v\n", opt, err) 50 } 51 return num 52} 53 54func startGoma(ctx Context, config Config) { 55 ctx.BeginTrace(metrics.RunSetupTool, "goma_ctl") 56 defer ctx.EndTrace() 57 58 if u := ulimitOrFatal(ctx, config, "-u"); u < gomaLeastNProcs { 59 ctx.Fatalf("max user processes is insufficient: %d; want >= %d.\n", u, gomaLeastNProcs) 60 } 61 if n := ulimitOrFatal(ctx, config, "-n"); n < gomaLeastNFiles { 62 ctx.Fatalf("max open files is insufficient: %d; want >= %d.\n", n, gomaLeastNFiles) 63 } 64 65 var gomaCtl string 66 if gomaDir, ok := config.Environment().Get("GOMA_DIR"); ok { 67 gomaCtl = filepath.Join(gomaDir, gomaCtlScript) 68 } else if home, ok := config.Environment().Get("HOME"); ok { 69 gomaCtl = filepath.Join(home, "goma", gomaCtlScript) 70 } else { 71 ctx.Fatalln("goma_ctl.py not found") 72 } 73 74 cmd := Command(ctx, config, "goma_ctl.py ensure_start", gomaCtl, "ensure_start") 75 cmd.Environment.Set("DIST_DIR", config.DistDir()) 76 77 if output, err := cmd.CombinedOutput(); err != nil { 78 ctx.Fatalf("goma_ctl.py ensure_start failed with: %v\n%s\n", err, output) 79 } 80} 81