cmd/compile: fix PGO cross-package inlining

With CL 447015, we identify hot callees from edge weights, but
the code only traverses edges for calls from the current package.
If the callee is in a different package, when compiling that
package, the edge was not visited, so the callee was not actually
marked inline candidate. This CL fixes it by traversing all hot
edges.

Change-Id: If668c1a16ebe34e3474376b88ab3a84be76b8562
Reviewed-on: https://go-review.googlesource.com/c/go/+/448015
Run-TryBot: Cherry Mui <cherryyz@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Michael Pratt <mpratt@google.com>
This commit is contained in:
Cherry Mui 2022-11-04 13:54:59 -04:00
parent 0758a7d82d
commit ada9385a5f

View file

@ -87,7 +87,8 @@ func pgoInlinePrologue(p *pgo.Profile) {
if s, err := strconv.ParseFloat(base.Debug.InlineHotCallSiteCDFThreshold, 64); err == nil { if s, err := strconv.ParseFloat(base.Debug.InlineHotCallSiteCDFThreshold, 64); err == nil {
inlineCDFHotCallSiteThresholdPercent = s inlineCDFHotCallSiteThresholdPercent = s
} }
inlineHotCallSiteThresholdPercent = computeThresholdFromCDF(p) var hotCallsites []pgo.NodeMapKey
inlineHotCallSiteThresholdPercent, hotCallsites = computeThresholdFromCDF(p)
if base.Debug.PGOInline > 0 { if base.Debug.PGOInline > 0 {
fmt.Printf("hot-callsite-thres-from-CDF=%v\n", inlineHotCallSiteThresholdPercent) fmt.Printf("hot-callsite-thres-from-CDF=%v\n", inlineHotCallSiteThresholdPercent)
} }
@ -96,6 +97,13 @@ func pgoInlinePrologue(p *pgo.Profile) {
inlineHotMaxBudget = int32(base.Debug.InlineHotBudget) inlineHotMaxBudget = int32(base.Debug.InlineHotBudget)
} }
// mark inlineable callees from hot edges
for _, n := range hotCallsites {
if fn := p.WeightedCG.IRNodes[n.CalleeName]; fn != nil {
candHotCalleeMap[fn] = struct{}{}
}
}
// mark hot call sites
ir.VisitFuncsBottomUp(typecheck.Target.Decls, func(list []*ir.Func, recursive bool) { ir.VisitFuncsBottomUp(typecheck.Target.Decls, func(list []*ir.Func, recursive bool) {
for _, f := range list { for _, f := range list {
name := ir.PkgFuncName(f) name := ir.PkgFuncName(f)
@ -107,7 +115,6 @@ func pgoInlinePrologue(p *pgo.Profile) {
csi := pgo.CallSiteInfo{Line: e.CallSite, Caller: n.AST} csi := pgo.CallSiteInfo{Line: e.CallSite, Caller: n.AST}
if _, ok := candHotEdgeMap[csi]; !ok { if _, ok := candHotEdgeMap[csi]; !ok {
candHotEdgeMap[csi] = struct{}{} candHotEdgeMap[csi] = struct{}{}
candHotCalleeMap[e.Dst] = struct{}{}
} }
} }
} }
@ -121,7 +128,10 @@ func pgoInlinePrologue(p *pgo.Profile) {
} }
} }
func computeThresholdFromCDF(p *pgo.Profile) float64 { // computeThresholdFromCDF computes an edge weight threshold based on the
// CDF of edge weights from the profile. Returns the threshold, and the
// list of edges that make up the given percentage of the CDF.
func computeThresholdFromCDF(p *pgo.Profile) (float64, []pgo.NodeMapKey) {
nodes := make([]pgo.NodeMapKey, len(p.NodeMap)) nodes := make([]pgo.NodeMapKey, len(p.NodeMap))
i := 0 i := 0
for n := range p.NodeMap { for n := range p.NodeMap {
@ -143,14 +153,14 @@ func computeThresholdFromCDF(p *pgo.Profile) float64 {
return ni.CallSite < nj.CallSite return ni.CallSite < nj.CallSite
}) })
cum := int64(0) cum := int64(0)
for _, n := range nodes { for i, n := range nodes {
w := p.NodeMap[n].EWeight w := p.NodeMap[n].EWeight
cum += w cum += w
if pgo.WeightInPercentage(cum, p.TotalEdgeWeight) > inlineCDFHotCallSiteThresholdPercent { if pgo.WeightInPercentage(cum, p.TotalEdgeWeight) > inlineCDFHotCallSiteThresholdPercent {
return pgo.WeightInPercentage(w, p.TotalEdgeWeight) return pgo.WeightInPercentage(w, p.TotalEdgeWeight), nodes[:i]
} }
} }
return 100 return 100, nil
} }
// pgoInlineEpilogue updates IRGraph after inlining. // pgoInlineEpilogue updates IRGraph after inlining.