diff options
| author | Than McIntosh <thanm@google.com> | 2023-08-11 09:40:31 -0400 |
|---|---|---|
| committer | Than McIntosh <thanm@google.com> | 2023-09-14 19:43:26 +0000 |
| commit | 0b07bbd2be98f80f3d447a266803f1d68aee2902 (patch) | |
| tree | 92297f27acc5d3a0b6bcdb1ae997bd2ebc1a9639 /src | |
| parent | 7d0b611dbee183ada5e16be9884b90c3cf64fe3f (diff) | |
| download | go-0b07bbd2be98f80f3d447a266803f1d68aee2902.tar.xz | |
cmd/compile/internal/inl: inline based on scoring when GOEXPERIMENT=newinliner
This patch changes the inliner to use callsite scores when deciding to
inline as opposed to looking only at callee cost/hairyness.
For this to work, we have to relax the inline budget cutoff as part of
CanInline to allow for the possibility that a given function might
start off with a cost of N where N > 80, but then be called from a
callsites whose score is less than 80. Once a given function F in
package P has been approved by CanInline (based on the relaxed budget)
it will then be emitted as part of the export data, meaning that other
packages importing P will need to also need to compute callsite scores
appropriately.
For a function F that calls function G, if G is marked as potentially
inlinable then the hairyness computation for F will use G's cost for
the call to G as opposed to the default call cost; for this to work
with the new scheme (given relaxed cost change described above) we
use G's cost only if it falls below inlineExtraCallCost, otherwise
just use inlineExtraCallCost.
Included in this patch are a bunch of skips and workarounds to
selected 'errorcheck' tests in the <GOROOT>/test directory to deal
with the additional "can inline" messages emitted when the new inliner
is turned on.
Change-Id: I9be5f8cd0cd8676beb4296faf80d2f6be7246335
Reviewed-on: https://go-review.googlesource.com/c/go/+/519197
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Diffstat (limited to 'src')
| -rw-r--r-- | src/cmd/compile/internal/inline/inl.go | 53 | ||||
| -rw-r--r-- | src/cmd/compile/internal/inline/inlheur/callsite.go | 8 |
2 files changed, 52 insertions, 9 deletions
diff --git a/src/cmd/compile/internal/inline/inl.go b/src/cmd/compile/internal/inline/inl.go index acb06ee5d7..436b353eb9 100644 --- a/src/cmd/compile/internal/inline/inl.go +++ b/src/cmd/compile/internal/inline/inl.go @@ -267,9 +267,12 @@ func garbageCollectUnreferencedHiddenClosures() { // inlineBudget determines the max budget for function 'fn' prior to // analyzing the hairyness of the body of 'fn'. We pass in the pgo -// profile if available, which can change the budget. If 'verbose' is -// set, then print a remark where we boost the budget due to PGO. -func inlineBudget(fn *ir.Func, profile *pgo.Profile, verbose bool) int32 { +// profile if available (which can change the budget), also a +// 'relaxed' flag, which expands the budget slightly to allow for the +// possibility that a call to the function might have its score +// adjusted downwards. If 'verbose' is set, then print a remark where +// we boost the budget due to PGO. +func inlineBudget(fn *ir.Func, profile *pgo.Profile, relaxed bool, verbose bool) int32 { // Update the budget for profile-guided inlining. budget := int32(inlineMaxBudget) if profile != nil { @@ -282,6 +285,9 @@ func inlineBudget(fn *ir.Func, profile *pgo.Profile, verbose bool) int32 { } } } + if relaxed { + budget += inlineMaxBudget + } return budget } @@ -332,8 +338,13 @@ func CanInline(fn *ir.Func, profile *pgo.Profile) { cc = 1 // this appears to yield better performance than 0. } - // Compute the inline budget for this function. - budget := inlineBudget(fn, profile, base.Debug.PGODebug > 0) + // Used a "relaxed" inline budget if goexperiment.NewInliner is in + // effect, or if we're producing a debugging dump for unit testing. + relaxed := goexperiment.NewInliner || + (base.Debug.DumpInlFuncProps != "") + + // Compute the inline budget for this func. + budget := inlineBudget(fn, profile, relaxed, base.Debug.PGODebug > 0) // At this point in the game the function we're looking at may // have "stale" autos, vars that still appear in the Dcl list, but @@ -604,8 +615,23 @@ opSwitch: } if fn := inlCallee(v.curFunc, n.X, v.profile); fn != nil && typecheck.HaveInlineBody(fn) { - v.budget -= fn.Inl.Cost - break + // In the existing inliner, it makes sense to use fn.Inl.Cost + // here due to the fact that an "inline F everywhere if F inlinable" + // strategy is used. With the new inliner, however, it is not + // a given that we'll inline a specific callsite -- it depends + // on what score we assign to the callsite. For now, use the + // computed cost if lower than the call cost, otherwise + // use call cost (we can eventually do away with this when + // we move to the "min-heap of callsites" scheme. + if !goexperiment.NewInliner { + v.budget -= fn.Inl.Cost + break + } else { + if fn.Inl.Cost < inlineExtraCallCost { + v.budget -= fn.Inl.Cost + break + } + } } // Call cost for non-leaf inlining. @@ -977,7 +1003,16 @@ func inlineCostOK(n *ir.CallExpr, caller, callee *ir.Func, bigCaller bool) (bool maxCost = inlineBigFunctionMaxCost } - if callee.Inl.Cost <= maxCost { + metric := callee.Inl.Cost + if goexperiment.NewInliner { + ok, score := inlheur.GetCallSiteScore(n) + if ok { + metric = int32(score) + } + + } + + if metric <= maxCost { // Simple case. Function is already cheap enough. return true, 0 } @@ -1001,7 +1036,7 @@ func inlineCostOK(n *ir.CallExpr, caller, callee *ir.Func, bigCaller bool) (bool return false, maxCost } - if callee.Inl.Cost > inlineHotMaxBudget { + if metric > inlineHotMaxBudget { return false, inlineHotMaxBudget } diff --git a/src/cmd/compile/internal/inline/inlheur/callsite.go b/src/cmd/compile/internal/inline/inlheur/callsite.go index 0ec7c52183..5b75a67243 100644 --- a/src/cmd/compile/internal/inline/inlheur/callsite.go +++ b/src/cmd/compile/internal/inline/inlheur/callsite.go @@ -44,6 +44,14 @@ type CallSiteTab map[*ir.CallExpr]*CallSite // Package-level table of callsites. var cstab = CallSiteTab{} +func GetCallSiteScore(ce *ir.CallExpr) (bool, int) { + cs, ok := cstab[ce] + if !ok { + return false, 0 + } + return true, cs.Score +} + type CSPropBits uint32 const ( |
