Skip to content

Commit 0e406c8

Browse files
committed
cmd/compile/internal/pgo: fix hard-coded PGO sample data position
This patch detects at which index position profiling samples that have the value-type samples count are, instead of the previously hard-coded position of index 1. Runtime generated profiles always generate CPU profiling data with the 0 index being CPU nanoseconds, and samples count at index 1, which is why this previously hasn't come up. Fixes #58292
1 parent 2f2c5e4 commit 0e406c8

File tree

2 files changed

+69
-1
lines changed

2 files changed

+69
-1
lines changed

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

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,9 +140,22 @@ func New(profileFile string) *Profile {
140140
return nil
141141
}
142142

143+
samplesCountIndex := -1
144+
for i, s := range profile.SampleType {
145+
if s.Type == "samples" && s.Unit == "count" {
146+
samplesCountIndex = i
147+
break
148+
}
149+
}
150+
151+
if samplesCountIndex == -1 {
152+
log.Fatal("failed to find CPU samples count value-type in profile.")
153+
return nil
154+
}
155+
143156
g := newGraph(profile, &Options{
144157
CallTree: false,
145-
SampleValue: func(v []int64) int64 { return v[1] },
158+
SampleValue: func(v []int64) int64 { return v[samplesCountIndex] },
146159
})
147160

148161
p := &Profile{

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

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package test
77
import (
88
"bufio"
99
"fmt"
10+
"internal/profile"
1011
"internal/testenv"
1112
"io"
1213
"os"
@@ -213,6 +214,59 @@ func TestPGOIntendedInliningShiftedLines(t *testing.T) {
213214
testPGOIntendedInlining(t, dir)
214215
}
215216

217+
// TestPGONon1Index tests that the sample index can not be 1 and compilation
218+
// will not fail.
219+
func TestPGONon1Index(t *testing.T) {
220+
wd, err := os.Getwd()
221+
if err != nil {
222+
t.Fatalf("error getting wd: %v", err)
223+
}
224+
srcDir := filepath.Join(wd, "testdata/pgo/inline")
225+
226+
// Copy the module to a scratch location so we can add a go.mod.
227+
dir := t.TempDir()
228+
229+
originalPprofFile, err := os.Open(filepath.Join(srcDir, "inline_hot.pprof"))
230+
if err != nil {
231+
t.Fatalf("error opening inline_hot.pprof: %v", err)
232+
}
233+
defer originalPprofFile.Close()
234+
235+
p, err := profile.Parse(originalPprofFile)
236+
if err != nil {
237+
t.Fatalf("error parsing inline_hot.pprof: %v", err)
238+
}
239+
240+
// Move the samples count value-type to the 0 index.
241+
p.SampleType = []*profile.ValueType{{
242+
Type: "samples",
243+
Unit: "count",
244+
}}
245+
246+
// Ensure we only have a single set of sample values.
247+
for _, s := range p.Sample {
248+
s.Value = s.Value[:1]
249+
}
250+
251+
modifiedPprofFile, err := os.Create(filepath.Join(dir, "inline_hot.pprof"))
252+
if err != nil {
253+
t.Fatalf("error creating inline_hot.pprof: %v", err)
254+
}
255+
defer modifiedPprofFile.Close()
256+
257+
if err := p.Write(modifiedPprofFile); err != nil {
258+
t.Fatalf("error writing inline_hot.pprof: %v", err)
259+
}
260+
261+
for _, file := range []string{"inline_hot.go", "inline_hot_test.go"} {
262+
if err := copyFile(filepath.Join(dir, file), filepath.Join(srcDir, file)); err != nil {
263+
t.Fatalf("error copying %s: %v", file, err)
264+
}
265+
}
266+
267+
testPGOIntendedInlining(t, dir)
268+
}
269+
216270
func copyFile(dst, src string) error {
217271
s, err := os.Open(src)
218272
if err != nil {
@@ -228,4 +282,5 @@ func copyFile(dst, src string) error {
228282

229283
_, err = io.Copy(d, s)
230284
return err
285+
231286
}

0 commit comments

Comments
 (0)