Skip to content

Commit 4b43b74

Browse files
committed
cmd/go: add -pgo build flag
Add a -pgo flag for "go build" (and other build actions), to specify the file path of a profile used for PGO. Special name "off" turns off PGO. The given profile path is passed to the compiler. The build cache is sensitive to the content of the given PGO profile. TODO: auto mode. For #55022. Change-Id: Ieee1b131b4c041f9502fd0a1acf112f3e44246be Reviewed-on: https://go-review.googlesource.com/c/go/+/438736 TryBot-Result: Gopher Robot <[email protected]> Run-TryBot: Cherry Mui <[email protected]> Reviewed-by: Michael Pratt <[email protected]> Reviewed-by: Bryan Mills <[email protected]>
1 parent 4179552 commit 4b43b74

File tree

8 files changed

+104
-0
lines changed

8 files changed

+104
-0
lines changed

Diff for: src/cmd/go/alldocs.go

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: src/cmd/go/internal/cfg/cfg.go

+2
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ var (
7979
BuildN bool // -n flag
8080
BuildO string // -o flag
8181
BuildP = runtime.GOMAXPROCS(0) // -p flag
82+
BuildPGO string // -pgo flag
83+
BuildPGOFile string // profile selected by -pgo flag, an absolute path (if not empty)
8284
BuildPkgdir string // -pkgdir flag
8385
BuildRace bool // -race flag
8486
BuildToolexec []string // -toolexec flag

Diff for: src/cmd/go/internal/load/pkg.go

+7
Original file line numberDiff line numberDiff line change
@@ -2387,6 +2387,13 @@ func (p *Package) setBuildInfo(autoVCS bool) {
23872387
appendSetting("-ldflags", ldflags)
23882388
}
23892389
}
2390+
if cfg.BuildPGOFile != "" {
2391+
if cfg.BuildTrimpath {
2392+
appendSetting("-pgo", filepath.Base(cfg.BuildPGOFile))
2393+
} else {
2394+
appendSetting("-pgo", cfg.BuildPGOFile)
2395+
}
2396+
}
23902397
if cfg.BuildMSan {
23912398
appendSetting("-msan", "true")
23922399
}

Diff for: src/cmd/go/internal/work/build.go

+4
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,9 @@ and test commands:
158158
include path must be in the same directory as the Go package they are
159159
included from, and overlays will not appear when binaries and tests are
160160
run through go run and go test respectively.
161+
-pgo file
162+
specify the file path of a profile for profile-guided optimization (PGO).
163+
Special name "off" turns off PGO.
161164
-pkgdir dir
162165
install and load all packages from dir instead of the usual locations.
163166
For example, when building with a non-standard configuration,
@@ -312,6 +315,7 @@ func AddBuildFlags(cmd *base.Command, mask BuildFlagMask) {
312315
cmd.Flag.StringVar(&cfg.BuildContext.InstallSuffix, "installsuffix", "", "")
313316
cmd.Flag.Var(&load.BuildLdflags, "ldflags", "")
314317
cmd.Flag.BoolVar(&cfg.BuildLinkshared, "linkshared", false, "")
318+
cmd.Flag.StringVar(&cfg.BuildPGO, "pgo", "", "")
315319
cmd.Flag.StringVar(&cfg.BuildPkgdir, "pkgdir", "", "")
316320
cmd.Flag.BoolVar(&cfg.BuildRace, "race", false, "")
317321
cmd.Flag.BoolVar(&cfg.BuildMSan, "msan", false, "")

Diff for: src/cmd/go/internal/work/exec.go

+3
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,9 @@ func (b *Builder) buildActionID(a *Action) cache.ActionID {
383383
for _, file := range inputFiles {
384384
fmt.Fprintf(h, "file %s %s\n", file, b.fileHash(filepath.Join(p.Dir, file)))
385385
}
386+
if cfg.BuildPGOFile != "" {
387+
fmt.Fprintf(h, "pgofile %s\n", b.fileHash(cfg.BuildPGOFile))
388+
}
386389
for _, a1 := range a.Deps {
387390
p1 := a1.Package
388391
if p1 != nil {

Diff for: src/cmd/go/internal/work/gc.go

+3
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,9 @@ func (gcToolchain) gc(b *Builder, a *Action, archive string, importcfg, embedcfg
145145
if p.Internal.CoverageCfg != "" {
146146
defaultGcFlags = append(defaultGcFlags, "-coveragecfg="+p.Internal.CoverageCfg)
147147
}
148+
if cfg.BuildPGOFile != "" {
149+
defaultGcFlags = append(defaultGcFlags, "-pgoprofile="+cfg.BuildPGOFile)
150+
}
148151
if symabis != "" {
149152
defaultGcFlags = append(defaultGcFlags, "-symabis", symabis)
150153
}

Diff for: src/cmd/go/internal/work/init.go

+20
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ func BuildInit() {
8484
if cfg.BuildRace && cfg.BuildCoverMode != "atomic" {
8585
base.Fatalf(`-covermode must be "atomic", not %q, when -race is enabled`, cfg.BuildCoverMode)
8686
}
87+
88+
setPGOProfilePath()
8789
}
8890

8991
// fuzzInstrumentFlags returns compiler flags that enable fuzzing instrumation
@@ -438,3 +440,21 @@ func compilerRequiredAsanVersion() error {
438440
}
439441
return nil
440442
}
443+
444+
func setPGOProfilePath() {
445+
switch cfg.BuildPGO {
446+
case "":
447+
fallthrough // default to "auto"
448+
case "off":
449+
// Nothing to do.
450+
case "auto":
451+
base.Fatalf("-pgo=auto is not implemented")
452+
default:
453+
// make it absolute path, as the compiler runs on various directories.
454+
if p, err := filepath.Abs(cfg.BuildPGO); err != nil {
455+
base.Fatalf("fail to get absolute path of PGO file %s: %v", cfg.BuildPGO, err)
456+
} else {
457+
cfg.BuildPGOFile = p
458+
}
459+
}
460+
}

Diff for: src/cmd/go/testdata/script/build_pgo.txt

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Test go build -pgo flag.
2+
# Specifically, the build cache handles profile content correctly.
3+
4+
# this test rebuild runtime with different flags, skip in short mode
5+
[short] skip
6+
7+
# build without PGO
8+
go build triv.go
9+
10+
# build with PGO, should trigger rebuild
11+
# starting with an empty profile (the compiler accepts it)
12+
go build -x -pgo=prof triv.go
13+
stderr 'compile.*-pgoprofile=.*prof.*triv.go'
14+
15+
# store the build ID
16+
go list -export -json=BuildID -pgo=prof triv.go
17+
stdout '"BuildID":' # check that output actually contains a build ID
18+
cp stdout list.out
19+
20+
# build again with the same profile, should be cached
21+
go build -x -pgo=prof triv.go
22+
! stderr 'compile.*triv.go'
23+
24+
# check that the build ID is the same
25+
go list -export -json=BuildID -pgo=prof triv.go
26+
cmp stdout list.out
27+
28+
# overwrite the prof
29+
go run overwrite.go
30+
31+
# build again, profile content changed, should trigger rebuild
32+
go build -n -pgo=prof triv.go
33+
stderr 'compile.*-pgoprofile=.*prof.*p.go'
34+
35+
# check that the build ID is different
36+
go list -export -json=BuildID -pgo=prof triv.go
37+
! cmp stdout list.out
38+
39+
-- prof --
40+
-- triv.go --
41+
package main
42+
func main() {}
43+
-- overwrite.go --
44+
package main
45+
46+
import (
47+
"os"
48+
"runtime/pprof"
49+
)
50+
51+
func main() {
52+
f, err := os.Create("prof")
53+
if err != nil {
54+
panic(err)
55+
}
56+
err = pprof.StartCPUProfile(f)
57+
if err != nil {
58+
panic(err)
59+
}
60+
pprof.StopCPUProfile()
61+
f.Close()
62+
}

0 commit comments

Comments
 (0)