1 // Copyright 2023 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
17 // testPGODevirtualize tests that specific PGO devirtualize rewrites are performed.
18 func testPGODevirtualize(t *testing.T, dir string) {
19 testenv.MustHaveGoRun(t)
22 const pkg = "example.com/pgo/devirtualize"
24 // Add a go.mod so we have a consistent symbol names in this temp dir.
25 goMod := fmt.Sprintf(`module %s
28 if err := os.WriteFile(filepath.Join(dir, "go.mod"), []byte(goMod), 0644); err != nil {
29 t.Fatalf("error writing go.mod: %v", err)
32 // Build the test with the profile.
33 pprof := filepath.Join(dir, "devirt.pprof")
34 gcflag := fmt.Sprintf("-gcflags=-m=2 -pgoprofile=%s -d=pgodebug=2", pprof)
35 out := filepath.Join(dir, "test.exe")
36 cmd := testenv.CleanCmdEnv(testenv.Command(t, testenv.GoToolPath(t), "build", "-o", out, gcflag, "."))
39 pr, pw, err := os.Pipe()
41 t.Fatalf("error creating pipe: %v", err)
50 t.Fatalf("error starting go test: %v", err)
53 type devirtualization struct {
58 want := []devirtualization{
60 pos: "./devirt.go:61:21",
61 callee: "mult.Mult.Multiply",
64 pos: "./devirt.go:61:31",
69 got := make(map[devirtualization]struct{})
71 devirtualizedLine := regexp.MustCompile(`(.*): PGO devirtualizing .* to (.*)`)
73 scanner := bufio.NewScanner(pr)
75 line := scanner.Text()
76 t.Logf("child: %s", line)
78 m := devirtualizedLine.FindStringSubmatch(line)
83 d := devirtualization{
89 if err := cmd.Wait(); err != nil {
90 t.Fatalf("error running go test: %v", err)
92 if err := scanner.Err(); err != nil {
93 t.Fatalf("error reading go test output: %v", err)
96 if len(got) != len(want) {
97 t.Errorf("mismatched devirtualization count; got %v want %v", got, want)
99 for _, w := range want {
100 if _, ok := got[w]; ok {
103 t.Errorf("devirtualization %v missing; got %v", w, got)
107 // TestPGODevirtualize tests that specific functions are devirtualized when PGO
108 // is applied to the exact source that was profiled.
109 func TestPGODevirtualize(t *testing.T) {
110 wd, err := os.Getwd()
112 t.Fatalf("error getting wd: %v", err)
114 srcDir := filepath.Join(wd, "testdata", "pgo", "devirtualize")
116 // Copy the module to a scratch location so we can add a go.mod.
118 if err := os.Mkdir(filepath.Join(dir, "mult"), 0755); err != nil {
119 t.Fatalf("error creating dir: %v", err)
121 for _, file := range []string{"devirt.go", "devirt_test.go", "devirt.pprof", filepath.Join("mult", "mult.go")} {
122 if err := copyFile(filepath.Join(dir, file), filepath.Join(srcDir, file)); err != nil {
123 t.Fatalf("error copying %s: %v", file, err)
127 testPGODevirtualize(t, dir)