Skip to content

Commit 3285158

Browse files
committed
cmd/go: add PGO auto mode
Add "auto" mode for the -pgo build flag. When -pgo=auto is specified, if there is a default.pgo file in the directory of the main package, it will be selected and used for the build. Currently it requires exactly one main package when -pgo=auto is specified. (We'll support multiple main packages in the future.) Also apply to other build-related subcommands, "go install", "go run", "go test", and "go list". For #55022. Change-Id: Iab7974ab8932daf0e83506de505e044a8e412466 Reviewed-on: https://go-review.googlesource.com/c/go/+/438737 TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Bryan Mills <[email protected]> Run-TryBot: Bryan Mills <[email protected]>
1 parent 17de9e2 commit 3285158

File tree

5 files changed

+127
-21
lines changed

5 files changed

+127
-21
lines changed

src/cmd/go/alldocs.go

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/cmd/go/internal/load/pkg.go

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2807,7 +2807,9 @@ func PackagesAndErrors(ctx context.Context, opts PackageOpts, patterns []string)
28072807
// We need to test whether the path is an actual Go file and not a
28082808
// package path or pattern ending in '.go' (see golang.org/issue/34653).
28092809
if fi, err := fsys.Stat(p); err == nil && !fi.IsDir() {
2810-
return []*Package{GoFilesPackage(ctx, opts, patterns)}
2810+
pkgs := []*Package{GoFilesPackage(ctx, opts, patterns)}
2811+
setPGOProfilePath(pkgs)
2812+
return pkgs
28112813
}
28122814
}
28132815
}
@@ -2886,9 +2888,60 @@ func PackagesAndErrors(ctx context.Context, opts PackageOpts, patterns []string)
28862888
// their dependencies).
28872889
setToolFlags(pkgs...)
28882890

2891+
setPGOProfilePath(pkgs)
2892+
28892893
return pkgs
28902894
}
28912895

2896+
// setPGOProfilePath sets cfg.BuildPGOFile to the PGO profile path.
2897+
// In -pgo=auto mode, it finds the default PGO profile.
2898+
func setPGOProfilePath(pkgs []*Package) {
2899+
switch cfg.BuildPGO {
2900+
case "":
2901+
fallthrough // default to "off"
2902+
case "off":
2903+
return
2904+
2905+
case "auto":
2906+
// Locate PGO profile from the main package.
2907+
2908+
setError := func(p *Package) {
2909+
if p.Error == nil {
2910+
p.Error = &PackageError{Err: errors.New("-pgo=auto requires exactly one main package")}
2911+
}
2912+
}
2913+
2914+
var mainpkg *Package
2915+
for _, p := range pkgs {
2916+
if p.Name == "main" {
2917+
if mainpkg != nil {
2918+
setError(p)
2919+
setError(mainpkg)
2920+
continue
2921+
}
2922+
mainpkg = p
2923+
}
2924+
}
2925+
if mainpkg == nil {
2926+
// No main package, no default.pgo to look for.
2927+
return
2928+
}
2929+
file := filepath.Join(mainpkg.Dir, "default.pgo")
2930+
if fi, err := os.Stat(file); err == nil && !fi.IsDir() {
2931+
cfg.BuildPGOFile = file
2932+
}
2933+
2934+
default:
2935+
// Profile specified from the command line.
2936+
// Make it absolute path, as the compiler runs on various directories.
2937+
if p, err := filepath.Abs(cfg.BuildPGO); err != nil {
2938+
base.Fatalf("fail to get absolute path of PGO file %s: %v", cfg.BuildPGO, err)
2939+
} else {
2940+
cfg.BuildPGOFile = p
2941+
}
2942+
}
2943+
}
2944+
28922945
// CheckPackageErrors prints errors encountered loading pkgs and their
28932946
// dependencies, then exits with a non-zero status if any errors were found.
28942947
func CheckPackageErrors(pkgs []*Package) {

src/cmd/go/internal/work/build.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,8 @@ and test commands:
159159
run through go run and go test respectively.
160160
-pgo file
161161
specify the file path of a profile for profile-guided optimization (PGO).
162+
Special name "auto" lets the go command select a file named
163+
"default.pgo" in the main package's directory if that file exists.
162164
Special name "off" turns off PGO.
163165
-pkgdir dir
164166
install and load all packages from dir instead of the usual locations.

src/cmd/go/internal/work/init.go

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,6 @@ 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()
8987
}
9088

9189
// fuzzInstrumentFlags returns compiler flags that enable fuzzing instrumation
@@ -442,21 +440,3 @@ func compilerRequiredAsanVersion() error {
442440
}
443441
return nil
444442
}
445-
446-
func setPGOProfilePath() {
447-
switch cfg.BuildPGO {
448-
case "":
449-
fallthrough // default to "auto"
450-
case "off":
451-
// Nothing to do.
452-
case "auto":
453-
base.Fatalf("-pgo=auto is not implemented")
454-
default:
455-
// make it absolute path, as the compiler runs on various directories.
456-
if p, err := filepath.Abs(cfg.BuildPGO); err != nil {
457-
base.Fatalf("fail to get absolute path of PGO file %s: %v", cfg.BuildPGO, err)
458-
} else {
459-
cfg.BuildPGOFile = p
460-
}
461-
}
462-
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# Test go build -pgo=auto flag.
2+
3+
# use default.pgo for a single main package
4+
go build -n -pgo=auto ./a/a1
5+
stderr 'compile.*-pgoprofile=.*default\.pgo.*a1.go'
6+
7+
# check that pgo applied to dependencies
8+
stderr 'compile.*-p test/dep.*-pgoprofile=.*default\.pgo'
9+
10+
# use default.pgo for ... with a single main package
11+
go build -n -pgo=auto ./a/...
12+
stderr 'compile.*-pgoprofile=.*default\.pgo.*a1.go'
13+
14+
# error with multiple packages
15+
! go build -n -pgo=auto ./b/...
16+
stderr '-pgo=auto requires exactly one main package'
17+
18+
# build succeeds without PGO when default.pgo file is absent
19+
go build -n -pgo=auto -o nopgo.exe ./nopgo
20+
stderr 'compile.*nopgo.go'
21+
! stderr '-pgoprofile'
22+
23+
# other build-related commands
24+
go install -n -pgo=auto ./a/a1
25+
stderr 'compile.*-pgoprofile=.*default\.pgo.*a1.go'
26+
27+
go run -n -pgo=auto ./a/a1
28+
stderr 'compile.*-pgoprofile=.*default\.pgo.*a1.go'
29+
30+
go test -n -pgo=auto ./a/a1
31+
stderr 'compile.*-pgoprofile=.*default\.pgo.*a1.go.*a1_test.go'
32+
stderr 'compile.*-pgoprofile=.*default\.pgo.*external_test.go'
33+
34+
# go list commands should succeed as usual
35+
go list -pgo=auto ./a/a1
36+
37+
go list -test -pgo=auto ./a/a1
38+
39+
go list -deps -pgo=auto ./a/a1
40+
41+
-- go.mod --
42+
module test
43+
go 1.20
44+
-- a/a1/a1.go --
45+
package main
46+
import _ "test/dep"
47+
func main() {}
48+
-- a/a1/a1_test.go --
49+
package main
50+
import "testing"
51+
func TestA(*testing.T) {}
52+
-- a/a1/external_test.go --
53+
package main_test
54+
import "testing"
55+
func TestExternal(*testing.T) {}
56+
-- a/a1/default.pgo --
57+
-- b/b1/b1.go --
58+
package main
59+
func main() {}
60+
-- b/b1/default.pgo --
61+
-- b/b2/b2.go --
62+
package main
63+
func main() {}
64+
-- b/b2/default.pgo --
65+
-- nopgo/nopgo.go --
66+
package main
67+
func main() {}
68+
-- dep/dep.go --
69+
package dep

0 commit comments

Comments
 (0)