aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMichael Pratt <mpratt@google.com>2023-04-28 15:52:16 -0400
committerGopher Robot <gobot@golang.org>2023-04-28 20:33:34 +0000
commit0fd6ae548f550bdbee4a434285ff052fb9dc7417 (patch)
tree0ab63fdc3c231eaafa8da781d8c0667d8d271133 /src
parent8b67cf0bc6ad657fddcbaaa10729d0086f08f9a9 (diff)
downloadgo-0fd6ae548f550bdbee4a434285ff052fb9dc7417.tar.xz
cmd/compile: escape package path for PGO symbol matching
Symbol names in the final executable apply escaping to the final component of a package path (main in example.com becomes example%2ecom.main). ir.PkgFuncName does not perform this escaping, meaning we'd fail to match functions that are escaped in the profile. Add ir.LinkFuncName which does perform escaping and use it for PGO. Fixes #59887. Change-Id: I10634d63d99d0a6fd2f72b929ab35ea227e1336f Reviewed-on: https://go-review.googlesource.com/c/go/+/490555 Reviewed-by: Cherry Mui <cherryyz@google.com> Auto-Submit: Michael Pratt <mpratt@google.com> Run-TryBot: Michael Pratt <mpratt@google.com> TryBot-Result: Gopher Robot <gobot@golang.org>
Diffstat (limited to 'src')
-rw-r--r--src/cmd/compile/internal/inline/inl.go4
-rw-r--r--src/cmd/compile/internal/ir/func.go25
-rw-r--r--src/cmd/compile/internal/pgo/irgraph.go26
3 files changed, 35 insertions, 20 deletions
diff --git a/src/cmd/compile/internal/inline/inl.go b/src/cmd/compile/internal/inline/inl.go
index 1a65e16f51..df12f9a625 100644
--- a/src/cmd/compile/internal/inline/inl.go
+++ b/src/cmd/compile/internal/inline/inl.go
@@ -163,7 +163,7 @@ func pgoInlineEpilogue(p *pgo.Profile, decls []ir.Node) {
if base.Debug.PGOInline >= 2 {
ir.VisitFuncsBottomUp(decls, func(list []*ir.Func, recursive bool) {
for _, f := range list {
- name := ir.PkgFuncName(f)
+ name := ir.LinkFuncName(f)
if n, ok := p.WeightedCG.IRNodes[name]; ok {
p.RedirectEdges(n, inlinedCallSites)
}
@@ -352,7 +352,7 @@ func CanInline(fn *ir.Func, profile *pgo.Profile) {
// Update the budget for profile-guided inlining.
budget := int32(inlineMaxBudget)
if profile != nil {
- if n, ok := profile.WeightedCG.IRNodes[ir.PkgFuncName(fn)]; ok {
+ if n, ok := profile.WeightedCG.IRNodes[ir.LinkFuncName(fn)]; ok {
if _, ok := candHotCalleeMap[n]; ok {
budget = int32(inlineHotMaxBudget)
if base.Debug.PGOInline > 0 {
diff --git a/src/cmd/compile/internal/ir/func.go b/src/cmd/compile/internal/ir/func.go
index 2886185f0a..b36b1fa494 100644
--- a/src/cmd/compile/internal/ir/func.go
+++ b/src/cmd/compile/internal/ir/func.go
@@ -8,6 +8,7 @@ import (
"cmd/compile/internal/base"
"cmd/compile/internal/types"
"cmd/internal/obj"
+ "cmd/internal/objabi"
"cmd/internal/src"
"fmt"
)
@@ -263,7 +264,7 @@ func (f *Func) SetWBPos(pos src.XPos) {
}
}
-// FuncName returns the name (without the package) of the function n.
+// FuncName returns the name (without the package) of the function f.
func FuncName(f *Func) string {
if f == nil || f.Nname == nil {
return "<nil>"
@@ -271,10 +272,12 @@ func FuncName(f *Func) string {
return f.Sym().Name
}
-// PkgFuncName returns the name of the function referenced by n, with package prepended.
-// This differs from the compiler's internal convention where local functions lack a package
-// because the ultimate consumer of this is a human looking at an IDE; package is only empty
-// if the compilation package is actually the empty string.
+// PkgFuncName returns the name of the function referenced by f, with package
+// prepended.
+//
+// This differs from the compiler's internal convention where local functions
+// lack a package. This is primarily useful when the ultimate consumer of this
+// is a human looking at message.
func PkgFuncName(f *Func) string {
if f == nil || f.Nname == nil {
return "<nil>"
@@ -285,6 +288,18 @@ func PkgFuncName(f *Func) string {
return pkg.Path + "." + s.Name
}
+// LinkFuncName returns the name of the function f, as it will appear in the
+// symbol table of the final linked binary.
+func LinkFuncName(f *Func) string {
+ if f == nil || f.Nname == nil {
+ return "<nil>"
+ }
+ s := f.Sym()
+ pkg := s.Pkg
+
+ return objabi.PathToPrefix(pkg.Path) + "." + s.Name
+}
+
// IsEqOrHashFunc reports whether f is type eq/hash function.
func IsEqOrHashFunc(f *Func) bool {
if f == nil || f.Nname == nil {
diff --git a/src/cmd/compile/internal/pgo/irgraph.go b/src/cmd/compile/internal/pgo/irgraph.go
index ff0995eaea..72ffc8ce78 100644
--- a/src/cmd/compile/internal/pgo/irgraph.go
+++ b/src/cmd/compile/internal/pgo/irgraph.go
@@ -270,7 +270,7 @@ func (p *Profile) VisitIR(fn *ir.Func) {
if g.InEdges == nil {
g.InEdges = make(map[*IRNode][]*IREdge)
}
- name := ir.PkgFuncName(fn)
+ name := ir.LinkFuncName(fn)
node := new(IRNode)
node.AST = fn
if g.IRNodes[name] == nil {
@@ -308,7 +308,7 @@ func (p *Profile) addIREdge(caller *IRNode, callername string, call ir.Node, cal
// Create an IRNode for the callee.
calleenode := new(IRNode)
calleenode.AST = callee
- calleename := ir.PkgFuncName(callee)
+ calleename := ir.LinkFuncName(callee)
// Create key for NodeMapKey.
nodeinfo := NodeMapKey{
@@ -395,7 +395,7 @@ func (p *Profile) PrintWeightedCallGraphDOT(edgeThreshold float64) {
funcs := make(map[string]struct{})
ir.VisitFuncsBottomUp(typecheck.Target.Decls, func(list []*ir.Func, recursive bool) {
for _, f := range list {
- name := ir.PkgFuncName(f)
+ name := ir.LinkFuncName(f)
funcs[name] = struct{}{}
}
})
@@ -405,15 +405,15 @@ func (p *Profile) PrintWeightedCallGraphDOT(edgeThreshold float64) {
for name := range funcs {
if n, ok := p.WeightedCG.IRNodes[name]; ok {
for _, e := range p.WeightedCG.OutEdges[n] {
- if _, ok := nodes[ir.PkgFuncName(e.Src.AST)]; !ok {
- nodes[ir.PkgFuncName(e.Src.AST)] = e.Src.AST
+ if _, ok := nodes[ir.LinkFuncName(e.Src.AST)]; !ok {
+ nodes[ir.LinkFuncName(e.Src.AST)] = e.Src.AST
}
- if _, ok := nodes[ir.PkgFuncName(e.Dst.AST)]; !ok {
- nodes[ir.PkgFuncName(e.Dst.AST)] = e.Dst.AST
+ if _, ok := nodes[ir.LinkFuncName(e.Dst.AST)]; !ok {
+ nodes[ir.LinkFuncName(e.Dst.AST)] = e.Dst.AST
}
}
- if _, ok := nodes[ir.PkgFuncName(n.AST)]; !ok {
- nodes[ir.PkgFuncName(n.AST)] = n.AST
+ if _, ok := nodes[ir.LinkFuncName(n.AST)]; !ok {
+ nodes[ir.LinkFuncName(n.AST)] = n.AST
}
}
}
@@ -424,16 +424,16 @@ func (p *Profile) PrintWeightedCallGraphDOT(edgeThreshold float64) {
nodeweight := WeightInPercentage(n.Flat, p.TotalNodeWeight)
color := "black"
if ast.Inl != nil {
- fmt.Printf("\"%v\" [color=%v,label=\"%v,freq=%.2f,inl_cost=%d\"];\n", ir.PkgFuncName(ast), color, ir.PkgFuncName(ast), nodeweight, ast.Inl.Cost)
+ fmt.Printf("\"%v\" [color=%v,label=\"%v,freq=%.2f,inl_cost=%d\"];\n", ir.LinkFuncName(ast), color, ir.LinkFuncName(ast), nodeweight, ast.Inl.Cost)
} else {
- fmt.Printf("\"%v\" [color=%v, label=\"%v,freq=%.2f\"];\n", ir.PkgFuncName(ast), color, ir.PkgFuncName(ast), nodeweight)
+ fmt.Printf("\"%v\" [color=%v, label=\"%v,freq=%.2f\"];\n", ir.LinkFuncName(ast), color, ir.LinkFuncName(ast), nodeweight)
}
}
}
// Print edges.
ir.VisitFuncsBottomUp(typecheck.Target.Decls, func(list []*ir.Func, recursive bool) {
for _, f := range list {
- name := ir.PkgFuncName(f)
+ name := ir.LinkFuncName(f)
if n, ok := p.WeightedCG.IRNodes[name]; ok {
for _, e := range p.WeightedCG.OutEdges[n] {
edgepercent := WeightInPercentage(e.Weight, p.TotalEdgeWeight)
@@ -443,7 +443,7 @@ func (p *Profile) PrintWeightedCallGraphDOT(edgeThreshold float64) {
fmt.Printf("edge [color=black, style=solid];\n")
}
- fmt.Printf("\"%v\" -> \"%v\" [label=\"%.2f\"];\n", ir.PkgFuncName(n.AST), ir.PkgFuncName(e.Dst.AST), edgepercent)
+ fmt.Printf("\"%v\" -> \"%v\" [label=\"%.2f\"];\n", ir.LinkFuncName(n.AST), ir.LinkFuncName(e.Dst.AST), edgepercent)
}
}
}