Skip to content

Commit 185f31b

Browse files
jinlin-bayareacherrymui
authored andcommitted
cmd/compile: update the incorrect assignment of call site offset.
The call site calculation in the previous version is incorrect. For the PGO preprocess file, the compiler should directly use the call site offset value. Additionly, this change refactors the preprocess tool to clean up unused fields including startline, the flat and the cum. Change-Id: I7bffed3215d4c016d9a9e4034bfd373bf50ab43f Reviewed-on: https://go-review.googlesource.com/c/go/+/562795 Reviewed-by: Cherry Mui <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Michael Pratt <[email protected]>
1 parent b6ca586 commit 185f31b

File tree

6 files changed

+162
-91
lines changed

6 files changed

+162
-91
lines changed

src/cmd/compile/internal/pgo/irgraph.go

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,6 @@ type NamedCallEdge struct {
108108
CallerName string
109109
CalleeName string
110110
CallSiteOffset int // Line offset from function start line.
111-
CallStartLine int // Start line of the function. Can be 0 which means missing.
112111
}
113112

114113
// NamedEdgeMap contains all unique call edges in the profile and their
@@ -336,20 +335,19 @@ func createNamedEdgeMapFromPreprocess(r io.Reader) (edgeMap NamedEdgeMap, totalW
336335

337336
split := strings.Split(readStr, " ")
338337

339-
if len(split) != 5 {
340-
return NamedEdgeMap{}, 0, fmt.Errorf("preprocessed profile entry got %v want 5 fields", split)
338+
if len(split) != 2 {
339+
return NamedEdgeMap{}, 0, fmt.Errorf("preprocessed profile entry got %v want 2 fields", split)
341340
}
342341

343342
co, _ := strconv.Atoi(split[0])
344-
cs, _ := strconv.Atoi(split[1])
345343

346344
namedEdge := NamedCallEdge{
347345
CallerName: callerName,
348-
CallSiteOffset: co - cs,
346+
CalleeName: calleeName,
347+
CallSiteOffset: co,
349348
}
350349

351-
namedEdge.CalleeName = calleeName
352-
EWeight, _ := strconv.ParseInt(split[4], 10, 64)
350+
EWeight, _ := strconv.ParseInt(split[1], 10, 64)
353351

354352
weight[namedEdge] += EWeight
355353
totalWeight += EWeight

src/cmd/compile/internal/test/pgo_devirtualize_test.go

Lines changed: 72 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,11 @@ type devirtualization struct {
1919
callee string
2020
}
2121

22+
const profFileName = "devirt.pprof"
23+
const preProfFileName = "devirt.pprof.node_map"
24+
2225
// testPGODevirtualize tests that specific PGO devirtualize rewrites are performed.
23-
func testPGODevirtualize(t *testing.T, dir string, want []devirtualization) {
26+
func testPGODevirtualize(t *testing.T, dir string, want []devirtualization, pgoProfileName string) {
2427
testenv.MustHaveGoRun(t)
2528
t.Parallel()
2629

@@ -45,7 +48,7 @@ go 1.21
4548
}
4649

4750
// Build the test with the profile.
48-
pprof := filepath.Join(dir, "devirt.pprof")
51+
pprof := filepath.Join(dir, pgoProfileName)
4952
gcflag := fmt.Sprintf("-gcflags=-m=2 -pgoprofile=%s -d=pgodebug=3", pprof)
5053
out := filepath.Join(dir, "test.exe")
5154
cmd = testenv.CleanCmdEnv(testenv.Command(t, testenv.GoToolPath(t), "test", "-o", out, gcflag, "."))
@@ -126,7 +129,70 @@ func TestPGODevirtualize(t *testing.T) {
126129
if err := os.Mkdir(filepath.Join(dir, "mult.pkg"), 0755); err != nil {
127130
t.Fatalf("error creating dir: %v", err)
128131
}
129-
for _, file := range []string{"devirt.go", "devirt_test.go", "devirt.pprof", filepath.Join("mult.pkg", "mult.go")} {
132+
for _, file := range []string{"devirt.go", "devirt_test.go", profFileName, filepath.Join("mult.pkg", "mult.go")} {
133+
if err := copyFile(filepath.Join(dir, file), filepath.Join(srcDir, file)); err != nil {
134+
t.Fatalf("error copying %s: %v", file, err)
135+
}
136+
}
137+
138+
want := []devirtualization{
139+
// ExerciseIface
140+
{
141+
pos: "./devirt.go:101:20",
142+
callee: "mult.Mult.Multiply",
143+
},
144+
{
145+
pos: "./devirt.go:101:39",
146+
callee: "Add.Add",
147+
},
148+
// ExerciseFuncConcrete
149+
{
150+
pos: "./devirt.go:173:36",
151+
callee: "AddFn",
152+
},
153+
{
154+
pos: "./devirt.go:173:15",
155+
callee: "mult.MultFn",
156+
},
157+
// ExerciseFuncField
158+
{
159+
pos: "./devirt.go:207:35",
160+
callee: "AddFn",
161+
},
162+
{
163+
pos: "./devirt.go:207:19",
164+
callee: "mult.MultFn",
165+
},
166+
// ExerciseFuncClosure
167+
// TODO(prattmic): Closure callees not implemented.
168+
//{
169+
// pos: "./devirt.go:249:27",
170+
// callee: "AddClosure.func1",
171+
//},
172+
//{
173+
// pos: "./devirt.go:249:15",
174+
// callee: "mult.MultClosure.func1",
175+
//},
176+
}
177+
178+
testPGODevirtualize(t, dir, want, profFileName)
179+
}
180+
181+
// TestPGOPreprocessDevirtualize tests that specific functions are devirtualized when PGO
182+
// is applied to the exact source that was profiled. The input profile is PGO preprocessed file.
183+
func TestPGOPreprocessDevirtualize(t *testing.T) {
184+
wd, err := os.Getwd()
185+
if err != nil {
186+
t.Fatalf("error getting wd: %v", err)
187+
}
188+
srcDir := filepath.Join(wd, "testdata", "pgo", "devirtualize")
189+
190+
// Copy the module to a scratch location so we can add a go.mod.
191+
dir := t.TempDir()
192+
if err := os.Mkdir(filepath.Join(dir, "mult.pkg"), 0755); err != nil {
193+
t.Fatalf("error creating dir: %v", err)
194+
}
195+
for _, file := range []string{"devirt.go", "devirt_test.go", preProfFileName, filepath.Join("mult.pkg", "mult.go")} {
130196
if err := copyFile(filepath.Join(dir, file), filepath.Join(srcDir, file)); err != nil {
131197
t.Fatalf("error copying %s: %v", file, err)
132198
}
@@ -172,7 +238,7 @@ func TestPGODevirtualize(t *testing.T) {
172238
//},
173239
}
174240

175-
testPGODevirtualize(t, dir, want)
241+
testPGODevirtualize(t, dir, want, preProfFileName)
176242
}
177243

178244
// Regression test for https://go.dev/issue/65615. If a target function changes
@@ -190,7 +256,7 @@ func TestLookupFuncGeneric(t *testing.T) {
190256
if err := os.Mkdir(filepath.Join(dir, "mult.pkg"), 0755); err != nil {
191257
t.Fatalf("error creating dir: %v", err)
192258
}
193-
for _, file := range []string{"devirt.go", "devirt_test.go", "devirt.pprof", filepath.Join("mult.pkg", "mult.go")} {
259+
for _, file := range []string{"devirt.go", "devirt_test.go", profFileName, filepath.Join("mult.pkg", "mult.go")} {
194260
if err := copyFile(filepath.Join(dir, file), filepath.Join(srcDir, file)); err != nil {
195261
t.Fatalf("error copying %s: %v", file, err)
196262
}
@@ -238,7 +304,7 @@ func TestLookupFuncGeneric(t *testing.T) {
238304
//},
239305
}
240306

241-
testPGODevirtualize(t, dir, want)
307+
testPGODevirtualize(t, dir, want, profFileName)
242308
}
243309

244310
var multFnRe = regexp.MustCompile(`func MultFn\(a, b int64\) int64`)

src/cmd/compile/internal/test/pgo_inl_test.go

Lines changed: 20 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ import (
1818
"testing"
1919
)
2020

21+
const profFile = "inline_hot.pprof"
22+
const preProfFile = "inline_hot.pprof.node_map"
23+
2124
func buildPGOInliningTest(t *testing.T, dir string, gcflag string) []byte {
2225
const pkg = "example.com/pgo/inline"
2326

@@ -43,12 +46,7 @@ go 1.19
4346
}
4447

4548
// testPGOIntendedInlining tests that specific functions are inlined.
46-
func testPGOIntendedInlining(t *testing.T, dir string, preprocessed ...bool) {
47-
defaultPGOPackValue := false
48-
if len(preprocessed) > 0 {
49-
defaultPGOPackValue = preprocessed[0]
50-
}
51-
49+
func testPGOIntendedInlining(t *testing.T, dir string, profFile string) {
5250
testenv.MustHaveGoRun(t)
5351
t.Parallel()
5452

@@ -91,13 +89,7 @@ func testPGOIntendedInlining(t *testing.T, dir string, preprocessed ...bool) {
9189

9290
// Build the test with the profile. Use a smaller threshold to test.
9391
// TODO: maybe adjust the test to work with default threshold.
94-
var pprof string
95-
if defaultPGOPackValue == false {
96-
pprof = filepath.Join(dir, "inline_hot.pprof")
97-
} else {
98-
pprof = filepath.Join(dir, "inline_hot.pprof.node_map")
99-
}
100-
gcflag := fmt.Sprintf("-m -m -pgoprofile=%s -d=pgoinlinebudget=160,pgoinlinecdfthreshold=90", pprof)
92+
gcflag := fmt.Sprintf("-m -m -pgoprofile=%s -d=pgoinlinebudget=160,pgoinlinecdfthreshold=90", profFile)
10193
out := buildPGOInliningTest(t, dir, gcflag)
10294

10395
scanner := bufio.NewScanner(bytes.NewReader(out))
@@ -165,13 +157,13 @@ func TestPGOIntendedInlining(t *testing.T) {
165157
// Copy the module to a scratch location so we can add a go.mod.
166158
dir := t.TempDir()
167159

168-
for _, file := range []string{"inline_hot.go", "inline_hot_test.go", "inline_hot.pprof"} {
160+
for _, file := range []string{"inline_hot.go", "inline_hot_test.go", profFile} {
169161
if err := copyFile(filepath.Join(dir, file), filepath.Join(srcDir, file)); err != nil {
170162
t.Fatalf("error copying %s: %v", file, err)
171163
}
172164
}
173165

174-
testPGOIntendedInlining(t, dir)
166+
testPGOIntendedInlining(t, dir, profFile)
175167
}
176168

177169
// TestPGOIntendedInlining tests that specific functions are inlined when PGO
@@ -186,13 +178,13 @@ func TestPGOPreprocessInlining(t *testing.T) {
186178
// Copy the module to a scratch location so we can add a go.mod.
187179
dir := t.TempDir()
188180

189-
for _, file := range []string{"inline_hot.go", "inline_hot_test.go", "inline_hot.pprof.node_map"} {
181+
for _, file := range []string{"inline_hot.go", "inline_hot_test.go", preProfFile} {
190182
if err := copyFile(filepath.Join(dir, file), filepath.Join(srcDir, file)); err != nil {
191183
t.Fatalf("error copying %s: %v", file, err)
192184
}
193185
}
194186

195-
testPGOIntendedInlining(t, dir, true)
187+
testPGOIntendedInlining(t, dir, preProfFile)
196188
}
197189

198190
// TestPGOIntendedInlining tests that specific functions are inlined when PGO
@@ -208,7 +200,7 @@ func TestPGOIntendedInliningShiftedLines(t *testing.T) {
208200
dir := t.TempDir()
209201

210202
// Copy most of the files unmodified.
211-
for _, file := range []string{"inline_hot_test.go", "inline_hot.pprof"} {
203+
for _, file := range []string{"inline_hot_test.go", profFile} {
212204
if err := copyFile(filepath.Join(dir, file), filepath.Join(srcDir, file)); err != nil {
213205
t.Fatalf("error copying %s : %v", file, err)
214206
}
@@ -240,7 +232,7 @@ func TestPGOIntendedInliningShiftedLines(t *testing.T) {
240232

241233
dst.Close()
242234

243-
testPGOIntendedInlining(t, dir)
235+
testPGOIntendedInlining(t, dir, profFile)
244236
}
245237

246238
// TestPGOSingleIndex tests that the sample index can not be 1 and compilation
@@ -270,15 +262,15 @@ func TestPGOSingleIndex(t *testing.T) {
270262
// Copy the module to a scratch location so we can add a go.mod.
271263
dir := t.TempDir()
272264

273-
originalPprofFile, err := os.Open(filepath.Join(srcDir, "inline_hot.pprof"))
265+
originalPprofFile, err := os.Open(filepath.Join(srcDir, profFile))
274266
if err != nil {
275-
t.Fatalf("error opening inline_hot.pprof: %v", err)
267+
t.Fatalf("error opening %v: %v", profFile, err)
276268
}
277269
defer originalPprofFile.Close()
278270

279271
p, err := profile.Parse(originalPprofFile)
280272
if err != nil {
281-
t.Fatalf("error parsing inline_hot.pprof: %v", err)
273+
t.Fatalf("error parsing %v: %v", profFile, err)
282274
}
283275

284276
// Move the samples count value-type to the 0 index.
@@ -289,14 +281,14 @@ func TestPGOSingleIndex(t *testing.T) {
289281
s.Value = []int64{s.Value[tc.originalIndex]}
290282
}
291283

292-
modifiedPprofFile, err := os.Create(filepath.Join(dir, "inline_hot.pprof"))
284+
modifiedPprofFile, err := os.Create(filepath.Join(dir, profFile))
293285
if err != nil {
294-
t.Fatalf("error creating inline_hot.pprof: %v", err)
286+
t.Fatalf("error creating %v: %v", profFile, err)
295287
}
296288
defer modifiedPprofFile.Close()
297289

298290
if err := p.Write(modifiedPprofFile); err != nil {
299-
t.Fatalf("error writing inline_hot.pprof: %v", err)
291+
t.Fatalf("error writing %v: %v", profFile, err)
300292
}
301293

302294
for _, file := range []string{"inline_hot.go", "inline_hot_test.go"} {
@@ -305,7 +297,7 @@ func TestPGOSingleIndex(t *testing.T) {
305297
}
306298
}
307299

308-
testPGOIntendedInlining(t, dir)
300+
testPGOIntendedInlining(t, dir, profFile)
309301
})
310302
}
311303
}
@@ -343,13 +335,13 @@ func TestPGOHash(t *testing.T) {
343335
// Copy the module to a scratch location so we can add a go.mod.
344336
dir := t.TempDir()
345337

346-
for _, file := range []string{"inline_hot.go", "inline_hot_test.go", "inline_hot.pprof"} {
338+
for _, file := range []string{"inline_hot.go", "inline_hot_test.go", profFile} {
347339
if err := copyFile(filepath.Join(dir, file), filepath.Join(srcDir, file)); err != nil {
348340
t.Fatalf("error copying %s: %v", file, err)
349341
}
350342
}
351343

352-
pprof := filepath.Join(dir, "inline_hot.pprof")
344+
pprof := filepath.Join(dir, profFile)
353345
// build with -trimpath so the source location (thus the hash)
354346
// does not depend on the temporary directory path.
355347
gcflag0 := fmt.Sprintf("-pgoprofile=%s -trimpath %s=>%s -d=pgoinlinebudget=160,pgoinlinecdfthreshold=90,pgodebug=1", pprof, dir, pkg)
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
GO PREPROFILE V1
2+
example.com/pgo/devirtualize.ExerciseFuncClosure
3+
example.com/pgo/devirtualize/mult%2epkg.MultClosure.func1
4+
18 93
5+
example.com/pgo/devirtualize.ExerciseIface
6+
example.com/pgo/devirtualize/mult%2epkg.NegMult.Multiply
7+
49 4
8+
example.com/pgo/devirtualize.ExerciseFuncConcrete
9+
example.com/pgo/devirtualize.AddFn
10+
48 103
11+
example.com/pgo/devirtualize.ExerciseFuncField
12+
example.com/pgo/devirtualize/mult%2epkg.NegMultFn
13+
23 8
14+
example.com/pgo/devirtualize.ExerciseFuncField
15+
example.com/pgo/devirtualize/mult%2epkg.MultFn
16+
23 94
17+
example.com/pgo/devirtualize.ExerciseIface
18+
example.com/pgo/devirtualize/mult%2epkg.Mult.Multiply
19+
49 40
20+
example.com/pgo/devirtualize.ExerciseIface
21+
example.com/pgo/devirtualize.Add.Add
22+
49 55
23+
example.com/pgo/devirtualize.ExerciseFuncConcrete
24+
example.com/pgo/devirtualize/mult%2epkg.NegMultFn
25+
48 8
26+
example.com/pgo/devirtualize.ExerciseFuncClosure
27+
example.com/pgo/devirtualize/mult%2epkg.NegMultClosure.func1
28+
18 10
29+
example.com/pgo/devirtualize.ExerciseIface
30+
example.com/pgo/devirtualize.Sub.Add
31+
49 7
32+
example.com/pgo/devirtualize.ExerciseFuncField
33+
example.com/pgo/devirtualize.AddFn
34+
23 101
35+
example.com/pgo/devirtualize.ExerciseFuncField
36+
example.com/pgo/devirtualize.SubFn
37+
23 12
38+
example.com/pgo/devirtualize.BenchmarkDevirtFuncConcrete
39+
example.com/pgo/devirtualize.ExerciseFuncConcrete
40+
1 2
41+
example.com/pgo/devirtualize.ExerciseFuncConcrete
42+
example.com/pgo/devirtualize/mult%2epkg.MultFn
43+
48 91
44+
example.com/pgo/devirtualize.ExerciseFuncConcrete
45+
example.com/pgo/devirtualize.SubFn
46+
48 5
47+
example.com/pgo/devirtualize.ExerciseFuncClosure
48+
example.com/pgo/devirtualize.Add.Add
49+
18 92
50+
example.com/pgo/devirtualize.ExerciseFuncClosure
51+
example.com/pgo/devirtualize.Sub.Add
52+
18 14
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
GO PREPROFILE V1
22
example.com/pgo/inline.benchmarkB
33
example.com/pgo/inline.A
4-
18 17 0 1 1
4+
18 1
55
example.com/pgo/inline.(*BS).NS
66
example.com/pgo/inline.T
7-
13 53 124 129 2
7+
8 3
88
example.com/pgo/inline.(*BS).NS
99
example.com/pgo/inline.T
10-
8 53 124 129 3
10+
13 2
1111
example.com/pgo/inline.A
1212
example.com/pgo/inline.(*BS).NS
13-
7 74 1 130 129
13+
7 129

0 commit comments

Comments
 (0)