mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile/internal/pgo: match on call line offsets
Rather than matching calls to edges in the profile based directly on line number in the source file, use the line offset from the start of the function. This makes matching robust to changes in the source file above the function containing the call. The start line in the profile comes from Function.start_line, which is included in Go pprof output since CL 438255. Currently it is an error if no samples set start_line to help users detect profiles missing this information. In the future, we should fallback to using absolute lines, which is better than nothing. For #55022. Change-Id: Ie621950cfee1fef8fb200907a2a3f1ded41d04fa Reviewed-on: https://go-review.googlesource.com/c/go/+/447315 Reviewed-by: Cherry Mui <cherryyz@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Run-TryBot: Michael Pratt <mpratt@google.com> Auto-Submit: Michael Pratt <mpratt@google.com>
This commit is contained in:
parent
f187c6b08e
commit
bdd1e283a9
6 changed files with 186 additions and 83 deletions
|
|
@ -8,6 +8,7 @@ import (
|
|||
"bufio"
|
||||
"fmt"
|
||||
"internal/testenv"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
|
|
@ -16,12 +17,20 @@ import (
|
|||
"testing"
|
||||
)
|
||||
|
||||
// TestPGOIntendedInlining tests that specific functions are inlined.
|
||||
func TestPGOIntendedInlining(t *testing.T) {
|
||||
// testPGOIntendedInlining tests that specific functions are inlined.
|
||||
func testPGOIntendedInlining(t *testing.T, dir string) {
|
||||
testenv.MustHaveGoRun(t)
|
||||
t.Parallel()
|
||||
|
||||
const pkg = "cmd/compile/internal/test/testdata/pgo/inline"
|
||||
const pkg = "example.com/pgo/inline"
|
||||
|
||||
// Add a go.mod so we have a consistent symbol names in this temp dir.
|
||||
goMod := fmt.Sprintf(`module %s
|
||||
go 1.19
|
||||
`, pkg)
|
||||
if err := os.WriteFile(filepath.Join(dir, "go.mod"), []byte(goMod), 0644); err != nil {
|
||||
t.Fatalf("error writing go.mod: %v", err)
|
||||
}
|
||||
|
||||
want := []string{
|
||||
"(*BS).NS",
|
||||
|
|
@ -58,14 +67,12 @@ func TestPGOIntendedInlining(t *testing.T) {
|
|||
expectedNotInlinedList[fullName] = struct{}{}
|
||||
}
|
||||
|
||||
// go test -c -o /tmp/test.exe -cpuprofile testdata/pgo/inline/inline_hot.pprof cmd/compile/internal/test/testdata/pgo/inline
|
||||
curdir, err := os.Getwd()
|
||||
if err != nil {
|
||||
t.Fatalf("error getting wd: %v", err)
|
||||
}
|
||||
gcflag := fmt.Sprintf("-gcflags=-m -m -pgoprofile %s/testdata/pgo/inline/inline_hot.pprof", curdir)
|
||||
out := filepath.Join(t.TempDir(), "test.exe")
|
||||
cmd := testenv.CleanCmdEnv(exec.Command(testenv.GoToolPath(t), "test", "-c", "-o", out, gcflag, pkg))
|
||||
// go test -c -o /tmp/test.exe -cpuprofile inline_hot.pprof
|
||||
pprof := filepath.Join(dir, "inline_hot.pprof")
|
||||
gcflag := fmt.Sprintf("-gcflags=-m -m -pgoprofile %s", pprof)
|
||||
out := filepath.Join(dir, "test.exe")
|
||||
cmd := testenv.CleanCmdEnv(exec.Command(testenv.GoToolPath(t), "test", "-c", "-o", out, gcflag, "."))
|
||||
cmd.Dir = dir
|
||||
|
||||
pr, pw, err := os.Pipe()
|
||||
if err != nil {
|
||||
|
|
@ -136,3 +143,89 @@ func TestPGOIntendedInlining(t *testing.T) {
|
|||
t.Errorf("%s was expected not inlined", fullName)
|
||||
}
|
||||
}
|
||||
|
||||
// TestPGOIntendedInlining tests that specific functions are inlined when PGO
|
||||
// is applied to the exact source that was profiled.
|
||||
func TestPGOIntendedInlining(t *testing.T) {
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
t.Fatalf("error getting wd: %v", err)
|
||||
}
|
||||
srcDir := filepath.Join(wd, "testdata/pgo/inline")
|
||||
|
||||
// Copy the module to a scratch location so we can add a go.mod.
|
||||
dir := t.TempDir()
|
||||
|
||||
for _, file := range []string{"inline_hot.go", "inline_hot_test.go", "inline_hot.pprof"} {
|
||||
if err := copyFile(filepath.Join(dir, file), filepath.Join(srcDir, file)); err != nil {
|
||||
t.Fatalf("error copying %s: %v", file, err)
|
||||
}
|
||||
}
|
||||
|
||||
testPGOIntendedInlining(t, dir)
|
||||
}
|
||||
|
||||
// TestPGOIntendedInlining tests that specific functions are inlined when PGO
|
||||
// is applied to the modified source.
|
||||
func TestPGOIntendedInliningShiftedLines(t *testing.T) {
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
t.Fatalf("error getting wd: %v", err)
|
||||
}
|
||||
srcDir := filepath.Join(wd, "testdata/pgo/inline")
|
||||
|
||||
// Copy the module to a scratch location so we can modify the source.
|
||||
dir := t.TempDir()
|
||||
|
||||
// Copy most of the files unmodified.
|
||||
for _, file := range []string{"inline_hot_test.go", "inline_hot.pprof"} {
|
||||
if err := copyFile(filepath.Join(dir, file), filepath.Join(srcDir, file)); err != nil {
|
||||
t.Fatalf("error copying %s : %v", file, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Add some comments to the top of inline_hot.go. This adjusts the line
|
||||
// numbers of all of the functions without changing the semantics.
|
||||
src, err := os.Open(filepath.Join(srcDir, "inline_hot.go"))
|
||||
if err != nil {
|
||||
t.Fatalf("error opening src inline_hot.go: %v", err)
|
||||
}
|
||||
defer src.Close()
|
||||
|
||||
dst, err := os.Create(filepath.Join(dir, "inline_hot.go"))
|
||||
if err != nil {
|
||||
t.Fatalf("error creating dst inline_hot.go: %v", err)
|
||||
}
|
||||
defer dst.Close()
|
||||
|
||||
if _, err := io.WriteString(dst, `// Autogenerated
|
||||
// Lines
|
||||
`); err != nil {
|
||||
t.Fatalf("error writing comments to dst: %v", err)
|
||||
}
|
||||
|
||||
if _, err := io.Copy(dst, src); err != nil {
|
||||
t.Fatalf("error copying inline_hot.go: %v", err)
|
||||
}
|
||||
|
||||
dst.Close()
|
||||
|
||||
testPGOIntendedInlining(t, dir)
|
||||
}
|
||||
|
||||
func copyFile(dst, src string) error {
|
||||
s, err := os.Open(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer s.Close()
|
||||
|
||||
d, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer d.Close()
|
||||
|
||||
_, err = io.Copy(d, s)
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue