]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/go: add undocumented -debug-actiongraph flag to dump action graph
authorRuss Cox <rsc@golang.org>
Mon, 9 Oct 2017 18:37:11 +0000 (14:37 -0400)
committerRuss Cox <rsc@golang.org>
Tue, 10 Oct 2017 00:19:37 +0000 (00:19 +0000)
This will be useful for debugging but is intentionally
undocumented and not guaranteed to persist in any
particular form.

Change-Id: I60710a1e94cfc2ce31fe91fc268c51985060f8df
Reviewed-on: https://go-review.googlesource.com/69330
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: David Crawshaw <crawshaw@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/cmd/go/internal/cfg/cfg.go
src/cmd/go/internal/run/run.go
src/cmd/go/internal/test/test.go
src/cmd/go/internal/work/build.go

index d45043e6dc77e0270988c811411ae7be577b44ef..290757fdb476d2744d48370d100477556fe5f343 100644 (file)
@@ -37,6 +37,8 @@ var (
        BuildV                 bool // -v flag
        BuildWork              bool // -work flag
        BuildX                 bool // -x flag
+
+       DebugActiongraph string // -debug-actiongraph flag (undocumented, unstable)
 )
 
 func init() {
index 6e276c28ec19f96f59caed7531c4c2dc3e281348..72af80fac2097a8944276acda10a3e3cf1eec81f 100644 (file)
@@ -111,7 +111,7 @@ func runRun(cmd *base.Command, args []string) {
        }
        p.Internal.ExeName = src[:len(src)-len(".go")] // name temporary executable for first go file
        a1 := b.Action(work.ModeBuild, work.ModeBuild, p)
-       a := &work.Action{Func: buildRunProgram, Args: cmdArgs, Deps: []*work.Action{a1}}
+       a := &work.Action{Mode: "go run", Func: buildRunProgram, Args: cmdArgs, Deps: []*work.Action{a1}}
        b.Do(a)
 }
 
index 90fa1b1ce1078e2cb983b046aa7f791f158c6bf3..0d21194287dbeccc5b48bf518d69e10d22c273f2 100644 (file)
@@ -522,7 +522,7 @@ func runTest(cmd *base.Command, args []string) {
                }
                sort.Strings(all)
 
-               a := &work.Action{}
+               a := &work.Action{Mode: "go test -i"}
                for _, p := range load.PackagesForBuild(all) {
                        a.Deps = append(a.Deps, b.Action(work.ModeInstall, work.ModeInstall, p))
                }
@@ -599,7 +599,7 @@ func runTest(cmd *base.Command, args []string) {
        }
 
        // Ultimately the goal is to print the output.
-       root := &work.Action{Deps: prints}
+       root := &work.Action{Mode: "go test", Deps: prints}
 
        // Force the printing of results to happen in order,
        // one at a time.
@@ -652,8 +652,8 @@ var windowsBadWords = []string{
 func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, printAction *work.Action, err error) {
        if len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 {
                build := b.Action(work.ModeBuild, work.ModeBuild, p)
-               run := &work.Action{Package: p, Deps: []*work.Action{build}}
-               print := &work.Action{Func: builderNoTest, Package: p, Deps: []*work.Action{run}}
+               run := &work.Action{Mode: "test run", Package: p, Deps: []*work.Action{build}}
+               print := &work.Action{Mode: "test print", Func: builderNoTest, Package: p, Deps: []*work.Action{run}}
                return build, run, print, nil
        }
 
@@ -945,6 +945,7 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin
                        }
                }
                buildAction = &work.Action{
+                       Mode:    "test build",
                        Func:    work.BuildInstallFunc,
                        Deps:    []*work.Action{buildAction},
                        Package: pmain,
@@ -953,22 +954,25 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin
                runAction = buildAction // make sure runAction != nil even if not running test
        }
        if testC {
-               printAction = &work.Action{Package: p, Deps: []*work.Action{runAction}} // nop
+               printAction = &work.Action{Mode: "test print (nop)", Package: p, Deps: []*work.Action{runAction}} // nop
        } else {
                // run test
                runAction = &work.Action{
+                       Mode:       "test run",
                        Func:       builderRunTest,
                        Deps:       []*work.Action{buildAction},
                        Package:    p,
                        IgnoreFail: true,
                }
                cleanAction := &work.Action{
+                       Mode:    "test clean",
                        Func:    builderCleanTest,
                        Deps:    []*work.Action{runAction},
                        Package: p,
                        Objdir:  testDir,
                }
                printAction = &work.Action{
+                       Mode:    "test print",
                        Func:    builderPrintTest,
                        Deps:    []*work.Action{cleanAction},
                        Package: p,
index 21d3f8f6801c325a4cd7bdc382ef57734a699612..92e2a3750dad1a9bdda57a280f65a125f3036a02 100644 (file)
@@ -9,6 +9,7 @@ import (
        "bytes"
        "container/heap"
        "debug/elf"
+       "encoding/json"
        "errors"
        "flag"
        "fmt"
@@ -223,6 +224,9 @@ func AddBuildFlags(cmd *base.Command) {
        cmd.Flag.Var((*base.StringsFlag)(&cfg.BuildContext.BuildTags), "tags", "")
        cmd.Flag.Var((*base.StringsFlag)(&cfg.BuildToolexec), "toolexec", "")
        cmd.Flag.BoolVar(&cfg.BuildWork, "work", false, "")
+
+       // Undocumented, unstable debugging flags.
+       cmd.Flag.StringVar(&cfg.DebugActiongraph, "debug-actiongraph", "", "")
 }
 
 // fileExtSplit expects a filename and returns the name
@@ -471,7 +475,7 @@ func runBuild(cmd *base.Command, args []string) {
                        a = b.libaction(libName, pkgs, ModeBuild, depMode)
                }
        } else {
-               a = &Action{}
+               a = &Action{Mode: "go build"}
                for _, p := range pkgs {
                        a.Deps = append(a.Deps, b.Action(ModeBuild, depMode, p))
                }
@@ -589,7 +593,7 @@ func InstallPackages(args []string, forGet bool) {
                        a = b.libaction(libName, pkgs, ModeInstall, ModeInstall)
                }
        } else {
-               a = &Action{}
+               a = &Action{Mode: "go install"}
                var tools []*Action
                for _, p := range pkgs {
                        // During 'go get', don't attempt (and fail) to install packages with only tests.
@@ -611,6 +615,7 @@ func InstallPackages(args []string, forGet bool) {
                }
                if len(tools) > 0 {
                        a = &Action{
+                               Mode: "go install (tools)",
                                Deps: tools,
                        }
                }
@@ -672,6 +677,7 @@ type Builder struct {
 
 // An Action represents a single action in the action graph.
 type Action struct {
+       Mode       string                        // description of action operation
        Package    *load.Package                 // the package this action works on
        Deps       []*Action                     // actions that must happen before this one
        Func       func(*Builder, *Action) error // the action itself (nil = no-op)
@@ -692,6 +698,21 @@ type Action struct {
        Failed   bool // whether the action failed
 }
 
+type actionJSON struct {
+       ID         int
+       Mode       string
+       Package    string
+       Deps       []int    `json:",omitempty"`
+       IgnoreFail bool     `json:",omitempty"`
+       Args       []string `json:",omitempty"`
+       Link       bool     `json:",omitempty"`
+       Objdir     string   `json:",omitempty"`
+       Target     string   `json:",omitempty"`
+       Priority   int      `json:",omitempty"`
+       Failed     bool     `json:",omitempty"`
+       Pkgfile    string   `json:",omitempty"`
+}
+
 // cacheKey is the key for the action cache.
 type cacheKey struct {
        mode  BuildMode
@@ -699,6 +720,57 @@ type cacheKey struct {
        shlib string
 }
 
+func actionGraphJSON(a *Action) string {
+       var workq []*Action
+       var inWorkq = make(map[*Action]int)
+
+       add := func(a *Action) {
+               if _, ok := inWorkq[a]; ok {
+                       return
+               }
+               inWorkq[a] = len(workq)
+               workq = append(workq, a)
+       }
+       add(a)
+
+       for i := 0; i < len(workq); i++ {
+               for _, dep := range workq[i].Deps {
+                       add(dep)
+               }
+       }
+
+       var list []*actionJSON
+       for id, a := range workq {
+               aj := &actionJSON{
+                       Mode:       a.Mode,
+                       ID:         id,
+                       IgnoreFail: a.IgnoreFail,
+                       Args:       a.Args,
+                       Link:       a.Link,
+                       Objdir:     a.Objdir,
+                       Target:     a.Target,
+                       Failed:     a.Failed,
+                       Priority:   a.priority,
+               }
+               if a.Package != nil {
+                       // TODO(rsc): Make this a unique key for a.Package somehow.
+                       aj.Package = a.Package.ImportPath
+                       aj.Pkgfile = a.Package.Internal.Pkgfile
+               }
+               for _, a1 := range a.Deps {
+                       aj.Deps = append(aj.Deps, inWorkq[a1])
+               }
+               list = append(list, aj)
+       }
+
+       js, err := json.MarshalIndent(list, "", "\t")
+       if err != nil {
+               fmt.Fprintf(os.Stderr, "go: writing debug action graph: %v\n", err)
+               return ""
+       }
+       return string(js)
+}
+
 // BuildMode specifies the build mode:
 // are we just building things or also installing the results?
 type BuildMode int
@@ -827,7 +899,7 @@ func (b *Builder) action1(mode BuildMode, depMode BuildMode, p *load.Package, lo
                return a
        }
 
-       a = &Action{Package: p}
+       a = &Action{Mode: "???", Package: p}
        b.actionCache[key] = a
 
        for _, p1 := range p.Internal.Imports {
@@ -854,11 +926,13 @@ func (b *Builder) action1(mode BuildMode, depMode BuildMode, p *load.Package, lo
                switch p.ImportPath {
                case "builtin", "unsafe":
                        // Fake packages - nothing to build.
+                       a.Mode = "built-in package"
                        return a
                }
                // gccgo standard library is "fake" too.
                if cfg.BuildToolchainName == "gccgo" {
                        // the target name is needed for cgo.
+                       a.Mode = "gccgo stdlib"
                        a.Target = p.Internal.Target
                        return a
                }
@@ -867,6 +941,7 @@ func (b *Builder) action1(mode BuildMode, depMode BuildMode, p *load.Package, lo
        if !p.Stale && p.Internal.Target != "" {
                // p.Stale==false implies that p.Internal.Target is up-to-date.
                // Record target name for use by actions depending on this one.
+               a.Mode = "use installed"
                a.Target = p.Internal.Target
                p.Internal.Pkgfile = a.Target
                return a
@@ -938,7 +1013,7 @@ func (b *Builder) action1(mode BuildMode, depMode BuildMode, p *load.Package, lo
 }
 
 func (b *Builder) libaction(libname string, pkgs []*load.Package, mode, depMode BuildMode) *Action {
-       a := &Action{}
+       a := &Action{Mode: "libaction???"}
        switch mode {
        default:
                base.Fatalf("unrecognized mode %v", mode)
@@ -1046,7 +1121,7 @@ func (b *Builder) libaction(libname string, pkgs []*load.Package, mode, depMode
                                if p.Internal.Target == "" {
                                        continue
                                }
-                               shlibnameaction := &Action{}
+                               shlibnameaction := &Action{Mode: "shlibname"}
                                shlibnameaction.Func = (*Builder).installShlibname
                                shlibnameaction.Target = p.Internal.Target[:len(p.Internal.Target)-2] + ".shlibname"
                                a.Deps = append(a.Deps, shlibnameaction)
@@ -1095,6 +1170,14 @@ func (b *Builder) Do(root *Action) {
                a.priority = i
        }
 
+       if cfg.DebugActiongraph != "" {
+               js := actionGraphJSON(root)
+               if err := ioutil.WriteFile(cfg.DebugActiongraph, []byte(js), 0666); err != nil {
+                       fmt.Fprintf(os.Stderr, "go: writing action graph: %v\n", err)
+                       base.SetExitStatus(1)
+               }
+       }
+
        b.readySema = make(chan bool, len(all))
 
        // Initialize per-action execution state.
@@ -3040,7 +3123,7 @@ func (tools gccgoToolchain) ld(b *Builder, root *Action, out, importcfg string,
 }
 
 func (tools gccgoToolchain) ldShared(b *Builder, toplevelactions []*Action, out, importcfg string, allactions []*Action) error {
-       fakeRoot := &Action{}
+       fakeRoot := &Action{Mode: "gccgo ldshared"}
        fakeRoot.Deps = toplevelactions
        return tools.link(b, fakeRoot, out, importcfg, allactions, "", nil, "shared", out)
 }
@@ -3673,7 +3756,7 @@ func (b *Builder) swigDoIntSize(objdir string) (intsize string, err error) {
 
        p := load.GoFilesPackage(srcs)
 
-       if _, _, e := BuildToolchain.gc(b, &Action{Package: p, Objdir: objdir}, "", nil, false, srcs); e != nil {
+       if _, _, e := BuildToolchain.gc(b, &Action{Mode: "swigDoIntSize", Package: p, Objdir: objdir}, "", nil, false, srcs); e != nil {
                return "32", nil
        }
        return "64", nil