From: Michael Pratt Date: Fri, 28 Apr 2023 19:52:16 +0000 (-0400) Subject: cmd/compile: escape package path for PGO symbol matching X-Git-Tag: go1.21rc1~744 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=0fd6ae548f550bdbee4a434285ff052fb9dc7417;p=gostls13.git 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 Auto-Submit: Michael Pratt Run-TryBot: Michael Pratt TryBot-Result: Gopher Robot --- 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 "" @@ -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 "" @@ -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 "" + } + 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) } } }