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>
This commit is contained in:
Michael Pratt 2023-04-28 15:52:16 -04:00 committed by Gopher Robot
parent 8b67cf0bc6
commit 0fd6ae548f
3 changed files with 35 additions and 20 deletions

View File

@ -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 {

View File

@ -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 {

View File

@ -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)
}
}
}