]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile/internal/pgo: error parsing profile (for pgo) after scaling
authorRyan Diep <ryandiep5@gmail.com>
Fri, 28 Nov 2025 08:27:09 +0000 (03:27 -0500)
committerGopher Robot <gobot@golang.org>
Fri, 23 Jan 2026 16:26:16 +0000 (08:26 -0800)
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>

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

index 0859431b029edf35b568c28f67f4cd276de504fc..d9d133c8d9782971d990e2b1e7deebbdbc66a1ff 100644 (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)
+}
index 5e61a11141c048ee40e639dcb34a23bd56314287..5bcd8c588d75e04141428916861d84add886192c 100644 (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