1
0
mirror of https://github.com/golang/go synced 2024-09-29 12:24:31 -06:00

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 <gobot@golang.org>
Reviewed-by: Bryan Mills <bcmills@google.com>
Run-TryBot: Bryan Mills <bcmills@google.com>
This commit is contained in:
Cherry Mui 2022-10-03 19:07:39 -04:00
parent 17de9e2d18
commit 32851587d1
5 changed files with 127 additions and 21 deletions

View File

@ -202,6 +202,8 @@
// run through go run and go test respectively.
// -pgo file
// specify the file path of a profile for profile-guided optimization (PGO).
// Special name "auto" lets the go command select a file named
// "default.pgo" in the main package's directory if that file exists.
// Special name "off" turns off PGO.
// -pkgdir dir
// install and load all packages from dir instead of the usual locations.

View File

@ -2807,7 +2807,9 @@ func PackagesAndErrors(ctx context.Context, opts PackageOpts, patterns []string)
// We need to test whether the path is an actual Go file and not a
// package path or pattern ending in '.go' (see golang.org/issue/34653).
if fi, err := fsys.Stat(p); err == nil && !fi.IsDir() {
return []*Package{GoFilesPackage(ctx, opts, patterns)}
pkgs := []*Package{GoFilesPackage(ctx, opts, patterns)}
setPGOProfilePath(pkgs)
return pkgs
}
}
}
@ -2886,9 +2888,60 @@ func PackagesAndErrors(ctx context.Context, opts PackageOpts, patterns []string)
// their dependencies).
setToolFlags(pkgs...)
setPGOProfilePath(pkgs)
return pkgs
}
// setPGOProfilePath sets cfg.BuildPGOFile to the PGO profile path.
// In -pgo=auto mode, it finds the default PGO profile.
func setPGOProfilePath(pkgs []*Package) {
switch cfg.BuildPGO {
case "":
fallthrough // default to "off"
case "off":
return
case "auto":
// Locate PGO profile from the main package.
setError := func(p *Package) {
if p.Error == nil {
p.Error = &PackageError{Err: errors.New("-pgo=auto requires exactly one main package")}
}
}
var mainpkg *Package
for _, p := range pkgs {
if p.Name == "main" {
if mainpkg != nil {
setError(p)
setError(mainpkg)
continue
}
mainpkg = p
}
}
if mainpkg == nil {
// No main package, no default.pgo to look for.
return
}
file := filepath.Join(mainpkg.Dir, "default.pgo")
if fi, err := os.Stat(file); err == nil && !fi.IsDir() {
cfg.BuildPGOFile = file
}
default:
// Profile specified from the command line.
// Make it absolute path, as the compiler runs on various directories.
if p, err := filepath.Abs(cfg.BuildPGO); err != nil {
base.Fatalf("fail to get absolute path of PGO file %s: %v", cfg.BuildPGO, err)
} else {
cfg.BuildPGOFile = p
}
}
}
// CheckPackageErrors prints errors encountered loading pkgs and their
// dependencies, then exits with a non-zero status if any errors were found.
func CheckPackageErrors(pkgs []*Package) {

View File

@ -159,6 +159,8 @@ and test commands:
run through go run and go test respectively.
-pgo file
specify the file path of a profile for profile-guided optimization (PGO).
Special name "auto" lets the go command select a file named
"default.pgo" in the main package's directory if that file exists.
Special name "off" turns off PGO.
-pkgdir dir
install and load all packages from dir instead of the usual locations.

View File

@ -84,8 +84,6 @@ func BuildInit() {
if cfg.BuildRace && cfg.BuildCoverMode != "atomic" {
base.Fatalf(`-covermode must be "atomic", not %q, when -race is enabled`, cfg.BuildCoverMode)
}
setPGOProfilePath()
}
// fuzzInstrumentFlags returns compiler flags that enable fuzzing instrumation
@ -442,21 +440,3 @@ func compilerRequiredAsanVersion() error {
}
return nil
}
func setPGOProfilePath() {
switch cfg.BuildPGO {
case "":
fallthrough // default to "auto"
case "off":
// Nothing to do.
case "auto":
base.Fatalf("-pgo=auto is not implemented")
default:
// make it absolute path, as the compiler runs on various directories.
if p, err := filepath.Abs(cfg.BuildPGO); err != nil {
base.Fatalf("fail to get absolute path of PGO file %s: %v", cfg.BuildPGO, err)
} else {
cfg.BuildPGOFile = p
}
}
}

View File

@ -0,0 +1,69 @@
# Test go build -pgo=auto flag.
# use default.pgo for a single main package
go build -n -pgo=auto ./a/a1
stderr 'compile.*-pgoprofile=.*default\.pgo.*a1.go'
# check that pgo applied to dependencies
stderr 'compile.*-p test/dep.*-pgoprofile=.*default\.pgo'
# use default.pgo for ... with a single main package
go build -n -pgo=auto ./a/...
stderr 'compile.*-pgoprofile=.*default\.pgo.*a1.go'
# error with multiple packages
! go build -n -pgo=auto ./b/...
stderr '-pgo=auto requires exactly one main package'
# build succeeds without PGO when default.pgo file is absent
go build -n -pgo=auto -o nopgo.exe ./nopgo
stderr 'compile.*nopgo.go'
! stderr '-pgoprofile'
# other build-related commands
go install -n -pgo=auto ./a/a1
stderr 'compile.*-pgoprofile=.*default\.pgo.*a1.go'
go run -n -pgo=auto ./a/a1
stderr 'compile.*-pgoprofile=.*default\.pgo.*a1.go'
go test -n -pgo=auto ./a/a1
stderr 'compile.*-pgoprofile=.*default\.pgo.*a1.go.*a1_test.go'
stderr 'compile.*-pgoprofile=.*default\.pgo.*external_test.go'
# go list commands should succeed as usual
go list -pgo=auto ./a/a1
go list -test -pgo=auto ./a/a1
go list -deps -pgo=auto ./a/a1
-- go.mod --
module test
go 1.20
-- a/a1/a1.go --
package main
import _ "test/dep"
func main() {}
-- a/a1/a1_test.go --
package main
import "testing"
func TestA(*testing.T) {}
-- a/a1/external_test.go --
package main_test
import "testing"
func TestExternal(*testing.T) {}
-- a/a1/default.pgo --
-- b/b1/b1.go --
package main
func main() {}
-- b/b1/default.pgo --
-- b/b2/b2.go --
package main
func main() {}
-- b/b2/default.pgo --
-- nopgo/nopgo.go --
package main
func main() {}
-- dep/dep.go --
package dep