Add build tracing
This creates a rotating build.trace.gz in the out directory that can be
loaded with chrome://tracing. It'll include start and end timings for
make/soong/kati/ninja, and it will import and time-correct the ninja log
files.
Test: m -j; load out/build.trace.gz in chrome://tracing
Test: multiproduct_kati -keep; load out/multiproduct*/build.trace.gz
Change-Id: Ic060fa9515eb88d95dbe16712479dae9dffcf626
diff --git a/ui/build/Android.bp b/ui/build/Android.bp
index d6da950..e4044e1 100644
--- a/ui/build/Android.bp
+++ b/ui/build/Android.bp
@@ -17,6 +17,7 @@
pkgPath: "android/soong/ui/build",
deps: [
"soong-ui-logger",
+ "soong-ui-tracer",
],
srcs: [
"build.go",
diff --git a/ui/build/context.go b/ui/build/context.go
index 59474f5..8144e58 100644
--- a/ui/build/context.go
+++ b/ui/build/context.go
@@ -18,8 +18,10 @@
"context"
"io"
"os"
+ "time"
"android/soong/ui/logger"
+ "android/soong/ui/tracer"
)
type StdioInterface interface {
@@ -55,10 +57,41 @@
// Context combines a context.Context, logger.Logger, and StdIO redirection.
// These all are agnostic of the current build, and may be used for multiple
// builds, while the Config objects contain per-build information.
-type Context *ContextImpl
+type Context struct{ *ContextImpl }
type ContextImpl struct {
context.Context
logger.Logger
StdioInterface
+
+ Thread tracer.Thread
+ Tracer tracer.Tracer
+}
+
+// BeginTrace starts a new Duration Event.
+func (c ContextImpl) BeginTrace(name string) {
+ if c.Tracer != nil {
+ c.Tracer.Begin(name, c.Thread)
+ }
+}
+
+// EndTrace finishes the last Duration Event.
+func (c ContextImpl) EndTrace() {
+ if c.Tracer != nil {
+ c.Tracer.End(c.Thread)
+ }
+}
+
+// CompleteTrace writes a trace with a beginning and end times.
+func (c ContextImpl) CompleteTrace(name string, begin, end uint64) {
+ if c.Tracer != nil {
+ c.Tracer.Complete(name, c.Thread, begin, end)
+ }
+}
+
+// ImportNinjaLog imports a .ninja_log file into the tracer.
+func (c ContextImpl) ImportNinjaLog(filename string, startOffset time.Time) {
+ if c.Tracer != nil {
+ c.Tracer.ImportNinjaLog(c.Thread, filename, startOffset)
+ }
}
diff --git a/ui/build/kati.go b/ui/build/kati.go
index 6997fbe..423bcbc 100644
--- a/ui/build/kati.go
+++ b/ui/build/kati.go
@@ -57,6 +57,9 @@
}
func runKati(ctx Context, config Config) {
+ ctx.BeginTrace("kati")
+ defer ctx.EndTrace()
+
genKatiSuffix(ctx, config)
executable := "prebuilts/build-tools/" + config.HostPrebuiltTag() + "/bin/ckati"
diff --git a/ui/build/make.go b/ui/build/make.go
index 5880509..89e03f7 100644
--- a/ui/build/make.go
+++ b/ui/build/make.go
@@ -35,6 +35,9 @@
// vars is the list of variables to read. The values will be put in the
// returned map.
func DumpMakeVars(ctx Context, config Config, goals, extra_targets, vars []string) (map[string]string, error) {
+ ctx.BeginTrace("dumpvars")
+ defer ctx.EndTrace()
+
cmd := exec.CommandContext(ctx.Context,
"make",
"--no-print-directory",
diff --git a/ui/build/ninja.go b/ui/build/ninja.go
index 13e1834..33f9a07 100644
--- a/ui/build/ninja.go
+++ b/ui/build/ninja.go
@@ -16,11 +16,16 @@
import (
"os/exec"
+ "path/filepath"
"strconv"
"strings"
+ "time"
)
func runNinja(ctx Context, config Config) {
+ ctx.BeginTrace("ninja")
+ defer ctx.EndTrace()
+
executable := "prebuilts/build-tools/" + config.HostPrebuiltTag() + "/bin/ninja"
args := []string{
"-d", "keepdepfile",
@@ -68,6 +73,8 @@
cmd.Stdout = ctx.Stdout()
cmd.Stderr = ctx.Stderr()
ctx.Verboseln(cmd.Path, cmd.Args)
+ startTime := time.Now()
+ defer ctx.ImportNinjaLog(filepath.Join(config.OutDir(), ".ninja_log"), startTime)
if err := cmd.Run(); err != nil {
if e, ok := err.(*exec.ExitError); ok {
ctx.Fatalln("ninja failed with:", e.ProcessState.String())
diff --git a/ui/build/soong.go b/ui/build/soong.go
index 88e4161..d017e70 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -20,6 +20,9 @@
)
func runSoongBootstrap(ctx Context, config Config) {
+ ctx.BeginTrace("bootstrap soong")
+ defer ctx.EndTrace()
+
cmd := exec.CommandContext(ctx.Context, "./bootstrap.bash")
env := config.Environment().Copy()
env.Set("BUILDDIR", config.SoongOutDir())
@@ -37,6 +40,9 @@
}
func runSoong(ctx Context, config Config) {
+ ctx.BeginTrace("soong")
+ defer ctx.EndTrace()
+
cmd := exec.CommandContext(ctx.Context, filepath.Join(config.SoongOutDir(), "soong"), "-w", "dupbuild=err")
if config.IsVerbose() {
cmd.Args = append(cmd.Args, "-v")