cmd/compile/internal/pgo: error parsing profile (for pgo) after scaling

If a valid profile is scaled such that the samples/counts become 0,
an empty graph in which the compiler complain that we never saw a start line
since the graph has no nodes which is a misleading error message.

src/cmd/internal/pgo/pprof.go was modified to check if the graph is empty
return an empty profile.

GitHub-Pull-Request: golang/go#73640
Change-Id: If3f7ab8af6fcf77b2e29ae1df154f87bee377ab0
Reviewed-on: https://go-review.googlesource.com/c/go/+/725120
Reviewed-by: Michael Pratt <mpratt@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Carlos Amedee <carlos@golang.org>
Auto-Submit: Michael Pratt <mpratt@google.com>
This commit is contained in:
Ryan Diep 2025-11-28 03:27:09 -05:00 committed by Gopher Robot
parent 6b7206feb2
commit a1150b5017
2 changed files with 56 additions and 0 deletions

View file

@ -365,3 +365,53 @@ func TestPGOHash(t *testing.T) {
t.Errorf("output contains unexpected source line, out:\n%s", out)
}
}
// TestPGOZeroValues tests that a profile with all sample values scaled to zero
// is treated as empty, ensuring the build succeeds without error.
func TestPGOZeroValues(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()
originalPprofFile, err := os.Open(filepath.Join(srcDir, profFile))
if err != nil {
t.Fatalf("error opening %v: %v", profFile, err)
}
defer originalPprofFile.Close()
p, err := profile.Parse(originalPprofFile)
if err != nil {
t.Fatalf("error parsing %v: %v", profFile, err)
}
// Zero out all samples to simulate a profile with all samples scaled away
for _, s := range p.Sample {
for i := range s.Value {
s.Value[i] = 0
}
}
emptyProf, err := os.Create(filepath.Join(dir, profFile))
if err != nil {
t.Fatalf("error creating %v: %v", profFile, err)
}
defer emptyProf.Close()
if err := p.Write(emptyProf); err != nil {
t.Fatalf("error writing %v: %v", profFile, err)
}
for _, file := range []string{"inline_hot.go", "inline_hot_test.go"} {
if err := copyFile(filepath.Join(dir, file), filepath.Join(srcDir, file)); err != nil {
t.Fatalf("error copying %s: %v", file, err)
}
}
gcflag := fmt.Sprintf("-pgoprofile=%s", profFile)
buildPGOInliningTest(t, dir, gcflag)
}

View file

@ -50,6 +50,12 @@ func FromPProf(r io.Reader) (*Profile, error) {
SampleValue: func(v []int64) int64 { return v[valueIndex] },
})
if len(g.Nodes) == 0 {
// If all sample values are 0, the graph will have no nodes.
// In this case, treat it as an empty profile.
return emptyProfile(), nil
}
namedEdgeMap, totalWeight, err := createNamedEdgeMap(g)
if err != nil {
return nil, err