1// Copyright 2019 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/rand" 20 "os" 21 "path/filepath" 22 "time" 23 24 "android/soong/ui/metrics" 25) 26 27const ( 28 rbeLeastNProcs = 2500 29 rbeLeastNFiles = 16000 30 31 // prebuilt RBE binaries 32 bootstrapCmd = "bootstrap" 33 34 // RBE metrics proto buffer file 35 rbeMetricsPBFilename = "rbe_metrics.pb" 36) 37 38func rbeCommand(ctx Context, config Config, rbeCmd string) string { 39 var cmdPath string 40 if rbeDir, ok := config.Environment().Get("RBE_DIR"); ok { 41 cmdPath = filepath.Join(rbeDir, rbeCmd) 42 } else if home, ok := config.Environment().Get("HOME"); ok { 43 cmdPath = filepath.Join(home, "rbe", rbeCmd) 44 } else { 45 ctx.Fatalf("rbe command path not found") 46 } 47 48 if _, err := os.Stat(cmdPath); err != nil && os.IsNotExist(err) { 49 ctx.Fatalf("rbe command %q not found", rbeCmd) 50 } 51 52 return cmdPath 53} 54 55func getRBEVars(ctx Context, tmpDir string) map[string]string { 56 rand.Seed(time.Now().UnixNano()) 57 return map[string]string{"RBE_server_address": fmt.Sprintf("unix://%v/reproxy_%v.sock", tmpDir, rand.Intn(1000))} 58} 59 60func startRBE(ctx Context, config Config) { 61 ctx.BeginTrace(metrics.RunSetupTool, "rbe_bootstrap") 62 defer ctx.EndTrace() 63 64 if u := ulimitOrFatal(ctx, config, "-u"); u < rbeLeastNProcs { 65 ctx.Fatalf("max user processes is insufficient: %d; want >= %d.\n", u, rbeLeastNProcs) 66 } 67 if n := ulimitOrFatal(ctx, config, "-n"); n < rbeLeastNFiles { 68 ctx.Fatalf("max open files is insufficient: %d; want >= %d.\n", n, rbeLeastNFiles) 69 } 70 71 cmd := Command(ctx, config, "startRBE bootstrap", rbeCommand(ctx, config, bootstrapCmd)) 72 73 if output, err := cmd.CombinedOutput(); err != nil { 74 ctx.Fatalf("rbe bootstrap failed with: %v\n%s\n", err, output) 75 } 76} 77 78func stopRBE(ctx Context, config Config) { 79 cmd := Command(ctx, config, "stopRBE bootstrap", rbeCommand(ctx, config, bootstrapCmd), "-shutdown") 80 if output, err := cmd.CombinedOutput(); err != nil { 81 ctx.Fatalf("rbe bootstrap with shutdown failed with: %v\n%s\n", err, output) 82 } 83} 84 85// DumpRBEMetrics creates a metrics protobuf file containing RBE related metrics. 86// The protobuf file is created if RBE is enabled and the proxy service has 87// started. The proxy service is shutdown in order to dump the RBE metrics to the 88// protobuf file. 89func DumpRBEMetrics(ctx Context, config Config, filename string) { 90 ctx.BeginTrace(metrics.RunShutdownTool, "dump_rbe_metrics") 91 defer ctx.EndTrace() 92 93 // Remove the previous metrics file in case there is a failure or RBE has been 94 // disable for this run. 95 os.Remove(filename) 96 97 // If RBE is not enabled then there are no metrics to generate. 98 // If RBE does not require to start, the RBE proxy maybe started 99 // manually for debugging purpose and can generate the metrics 100 // afterwards. 101 if !config.StartRBE() { 102 return 103 } 104 105 outputDir := config.RBEStatsOutputDir() 106 if outputDir == "" { 107 ctx.Fatal("RBE output dir variable not defined. Aborting metrics dumping.") 108 } 109 metricsFile := filepath.Join(outputDir, rbeMetricsPBFilename) 110 111 // Stop the proxy first in order to generate the RBE metrics protobuf file. 112 stopRBE(ctx, config) 113 114 if _, err := copyFile(metricsFile, filename); err != nil { 115 ctx.Fatalf("failed to copy %q to %q: %v\n", metricsFile, filename, err) 116 } 117} 118