mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile: simplify PGO hot caller/callee computation
Currently, we use CDF to compute a weight threshold and then use the weight threshold to determine whether a call site is hot. As when we compute the CDF we already have a list of hot call sites that make up the given percentage of the CDF, just use that list. Also, when computing the CDF threshold, include the very last node that makes it to go over the threshold. (I.e. if the CDF threshold is 50% and one hot node takes 60% of weight, we should include that node instead of excluding it. In practice it rarely matters, probably only for testing and micro-benchmarks.) Change-Id: I535ae9cd6b679609e247c3d0d9ee572c1a1187cc Reviewed-on: https://go-review.googlesource.com/c/go/+/450737 Reviewed-by: Austin Clements <austin@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Run-TryBot: Cherry Mui <cherryyz@google.com>
This commit is contained in:
parent
81c9b1d65f
commit
3f1bcc58b3
1 changed files with 28 additions and 31 deletions
|
|
@ -84,11 +84,15 @@ var (
|
||||||
|
|
||||||
// pgoInlinePrologue records the hot callsites from ir-graph.
|
// pgoInlinePrologue records the hot callsites from ir-graph.
|
||||||
func pgoInlinePrologue(p *pgo.Profile, decls []ir.Node) {
|
func pgoInlinePrologue(p *pgo.Profile, decls []ir.Node) {
|
||||||
if s, err := strconv.ParseFloat(base.Debug.PGOInlineCDFThreshold, 64); err == nil {
|
if base.Debug.PGOInlineCDFThreshold != "" {
|
||||||
|
if s, err := strconv.ParseFloat(base.Debug.PGOInlineCDFThreshold, 64); err == nil && s >= 0 && s <= 100 {
|
||||||
inlineCDFHotCallSiteThresholdPercent = s
|
inlineCDFHotCallSiteThresholdPercent = s
|
||||||
|
} else {
|
||||||
|
base.Fatalf("invalid PGOInlineCDFThreshold, must be between 0 and 100")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
var hotCallsites []pgo.NodeMapKey
|
var hotCallsites []pgo.NodeMapKey
|
||||||
inlineHotCallSiteThresholdPercent, hotCallsites = computeThresholdFromCDF(p)
|
inlineHotCallSiteThresholdPercent, hotCallsites = hotNodesFromCDF(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)
|
||||||
}
|
}
|
||||||
|
|
@ -97,41 +101,31 @@ func pgoInlinePrologue(p *pgo.Profile, decls []ir.Node) {
|
||||||
inlineHotMaxBudget = int32(x)
|
inlineHotMaxBudget = int32(x)
|
||||||
}
|
}
|
||||||
|
|
||||||
// mark inlineable callees from hot edges
|
|
||||||
for _, n := range hotCallsites {
|
for _, n := range hotCallsites {
|
||||||
if fn := p.WeightedCG.IRNodes[n.CalleeName]; fn != nil {
|
// mark inlineable callees from hot edges
|
||||||
candHotCalleeMap[fn] = struct{}{}
|
if callee := p.WeightedCG.IRNodes[n.CalleeName]; callee != nil {
|
||||||
}
|
candHotCalleeMap[callee] = struct{}{}
|
||||||
}
|
}
|
||||||
// mark hot call sites
|
// mark hot call sites
|
||||||
ir.VisitFuncsBottomUp(decls, func(list []*ir.Func, recursive bool) {
|
if caller := p.WeightedCG.IRNodes[n.CallerName]; caller != nil {
|
||||||
for _, f := range list {
|
csi := pgo.CallSiteInfo{LineOffset: n.CallSiteOffset, Caller: caller.AST}
|
||||||
name := ir.PkgFuncName(f)
|
|
||||||
if n, ok := p.WeightedCG.IRNodes[name]; ok {
|
|
||||||
for _, e := range p.WeightedCG.OutEdges[n] {
|
|
||||||
if e.Weight != 0 {
|
|
||||||
edgeweightpercent := pgo.WeightInPercentage(e.Weight, p.TotalEdgeWeight)
|
|
||||||
if edgeweightpercent > inlineHotCallSiteThresholdPercent {
|
|
||||||
csi := pgo.CallSiteInfo{LineOffset: e.CallSiteOffset, Caller: n.AST}
|
|
||||||
if _, ok := candHotEdgeMap[csi]; !ok {
|
|
||||||
candHotEdgeMap[csi] = struct{}{}
|
candHotEdgeMap[csi] = struct{}{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
if base.Debug.PGOInline >= 2 {
|
if base.Debug.PGOInline >= 2 {
|
||||||
fmt.Printf("hot-cg before inline in dot format:")
|
fmt.Printf("hot-cg before inline in dot format:")
|
||||||
p.PrintWeightedCallGraphDOT(inlineHotCallSiteThresholdPercent)
|
p.PrintWeightedCallGraphDOT(inlineHotCallSiteThresholdPercent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// computeThresholdFromCDF computes an edge weight threshold based on the
|
// hotNodesFromCDF computes an edge weight threshold and the list of hot
|
||||||
// CDF of edge weights from the profile. Returns the threshold, and the
|
// nodes that make up the given percentage of the CDF. The threshold, as
|
||||||
// list of edges that make up the given percentage of the CDF.
|
// a percent, is the lower bound of weight for nodes to be considered hot
|
||||||
func computeThresholdFromCDF(p *pgo.Profile) (float64, []pgo.NodeMapKey) {
|
// (currently only used in debug prints) (in case of equal weights,
|
||||||
|
// comparing with the threshold may not accurately reflect which nodes are
|
||||||
|
// considiered hot).
|
||||||
|
func hotNodesFromCDF(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 {
|
||||||
|
|
@ -157,10 +151,13 @@ func computeThresholdFromCDF(p *pgo.Profile) (float64, []pgo.NodeMapKey) {
|
||||||
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), nodes[:i]
|
// nodes[:i+1] to include the very last node that makes it to go over the threshold.
|
||||||
|
// (Say, if the CDF threshold is 50% and one hot node takes 60% of weight, we want to
|
||||||
|
// include that node instead of excluding it.)
|
||||||
|
return pgo.WeightInPercentage(w, p.TotalEdgeWeight), nodes[:i+1]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 100, nil
|
return 0, nodes
|
||||||
}
|
}
|
||||||
|
|
||||||
// pgoInlineEpilogue updates IRGraph after inlining.
|
// pgoInlineEpilogue updates IRGraph after inlining.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue