]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile/internal/inline: revise -m=2 status messages
authorThan McIntosh <thanm@google.com>
Tue, 7 Nov 2023 15:28:56 +0000 (10:28 -0500)
committerThan McIntosh <thanm@google.com>
Tue, 21 Nov 2023 20:07:48 +0000 (20:07 +0000)
This patch revises the compiler's "-m=2" status messages related to
inlining. The "can inline" remarks will continue to use the same
format, but the remarks when a specific call site is inlined will be
changed to refer to the score used; before we had

  runtime/traceback.go:1131:28: inlining call to gotraceback
  runtime/traceback.go:1183:25: inlining call to readgstatus

and with GOEXPERIMENT=newinliner the new messages will be:

  runtime/traceback.go:1131:28: inlining call to gotraceback with score 62
  runtime/traceback.go:1183:25: inlining call to readgstatus with score 9

Change-Id: Ia86cf5351d29eda64a5426ca0a2a2ec0c2900d81
Reviewed-on: https://go-review.googlesource.com/c/go/+/540775
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>

src/cmd/compile/internal/inline/inl.go
src/cmd/compile/internal/inline/inlheur/analyze.go
src/cmd/compile/internal/inline/inlheur/scoring.go

index 74f0d341c72868725a392ad251677a3503d102a7..b365008c764c2d18eaab8939afa862587158b708 100644 (file)
@@ -29,6 +29,7 @@ package inline
 import (
        "fmt"
        "go/constant"
+       "internal/buildcfg"
        "strconv"
 
        "cmd/compile/internal/base"
@@ -327,14 +328,22 @@ func CanInline(fn *ir.Func, profile *pgo.Profile) {
 
                CanDelayResults: canDelayResults(fn),
        }
+       if base.Flag.LowerM != 0 || logopt.Enabled() {
+               noteInlinableFunc(n, fn, budget-visitor.budget)
+       }
+}
 
+// noteInlinableFunc issues a message to the user that the specified
+// function is inlinable.
+func noteInlinableFunc(n *ir.Name, fn *ir.Func, cost int32) {
        if base.Flag.LowerM > 1 {
-               fmt.Printf("%v: can inline %v with cost %d as: %v { %v }\n", ir.Line(fn), n, budget-visitor.budget, fn.Type(), ir.Nodes(fn.Body))
+               fmt.Printf("%v: can inline %v with cost %d as: %v { %v }\n", ir.Line(fn), n, cost, fn.Type(), ir.Nodes(fn.Body))
        } else if base.Flag.LowerM != 0 {
                fmt.Printf("%v: can inline %v\n", ir.Line(fn), n)
        }
+       // JSON optimization log output.
        if logopt.Enabled() {
-               logopt.LogOpt(fn.Pos(), "canInlineFunction", "inline", ir.FuncName(fn), fmt.Sprintf("cost: %d", budget-visitor.budget))
+               logopt.LogOpt(fn.Pos(), "canInlineFunction", "inline", ir.FuncName(fn), fmt.Sprintf("cost: %d", cost))
        }
 }
 
@@ -558,7 +567,7 @@ opSwitch:
                        // Check whether we'd actually inline this call. Set
                        // log == false since we aren't actually doing inlining
                        // yet.
-                       if canInlineCallExpr(v.curFunc, n, callee, v.isBigFunc, false) {
+                       if ok, _ := canInlineCallExpr(v.curFunc, n, callee, v.isBigFunc, false); ok {
                                // mkinlcall would inline this call [1], so use
                                // the cost of the inline body as the cost of
                                // the call, as that is what will actually
@@ -851,9 +860,10 @@ var InlineCall = func(callerfn *ir.Func, call *ir.CallExpr, fn *ir.Func, inlInde
 // inlineCostOK returns true if call n from caller to callee is cheap enough to
 // inline. bigCaller indicates that caller is a big function.
 //
-// If inlineCostOK returns false, it also returns the max cost that the callee
-// exceeded.
-func inlineCostOK(n *ir.CallExpr, caller, callee *ir.Func, bigCaller bool) (bool, int32) {
+// In addition to the "cost OK" boolean, it also returns the "max
+// cost" limit used to make the decision (which may differ depending
+// on func size), and the score assigned to this specific callsite.
+func inlineCostOK(n *ir.CallExpr, caller, callee *ir.Func, bigCaller bool) (bool, int32, int32) {
        maxCost := int32(inlineMaxBudget)
        if bigCaller {
                // We use this to restrict inlining into very big functions.
@@ -867,12 +877,11 @@ func inlineCostOK(n *ir.CallExpr, caller, callee *ir.Func, bigCaller bool) (bool
                if ok {
                        metric = int32(score)
                }
-
        }
 
        if metric <= maxCost {
                // Simple case. Function is already cheap enough.
-               return true, 0
+               return true, 0, metric
        }
 
        // We'll also allow inlining of hot functions below inlineHotMaxBudget,
@@ -882,7 +891,7 @@ func inlineCostOK(n *ir.CallExpr, caller, callee *ir.Func, bigCaller bool) (bool
        csi := pgo.CallSiteInfo{LineOffset: lineOffset, Caller: caller}
        if _, ok := candHotEdgeMap[csi]; !ok {
                // Cold
-               return false, maxCost
+               return false, maxCost, metric
        }
 
        // Hot
@@ -891,47 +900,49 @@ func inlineCostOK(n *ir.CallExpr, caller, callee *ir.Func, bigCaller bool) (bool
                if base.Debug.PGODebug > 0 {
                        fmt.Printf("hot-big check disallows inlining for call %s (cost %d) at %v in big function %s\n", ir.PkgFuncName(callee), callee.Inl.Cost, ir.Line(n), ir.PkgFuncName(caller))
                }
-               return false, maxCost
+               return false, maxCost, metric
        }
 
        if metric > inlineHotMaxBudget {
-               return false, inlineHotMaxBudget
+               return false, inlineHotMaxBudget, metric
        }
 
        if !base.PGOHash.MatchPosWithInfo(n.Pos(), "inline", nil) {
                // De-selected by PGO Hash.
-               return false, maxCost
+               return false, maxCost, metric
        }
 
        if base.Debug.PGODebug > 0 {
                fmt.Printf("hot-budget check allows inlining for call %s (cost %d) at %v in function %s\n", ir.PkgFuncName(callee), callee.Inl.Cost, ir.Line(n), ir.PkgFuncName(caller))
        }
 
-       return true, 0
+       return true, 0, metric
 }
 
-// canInlineCallsite returns true if the call n from caller to callee can be
-// inlined. bigCaller indicates that caller is a big function. log indicates
-// that the 'cannot inline' reason should be logged.
+// canInlineCallsite returns true if the call n from caller to callee
+// can be inlined, plus the score computed for the call expr in
+// question. bigCaller indicates that caller is a big function. log
+// indicates that the 'cannot inline' reason should be logged.
 //
 // Preconditions: CanInline(callee) has already been called.
-func canInlineCallExpr(callerfn *ir.Func, n *ir.CallExpr, callee *ir.Func, bigCaller bool, log bool) bool {
+func canInlineCallExpr(callerfn *ir.Func, n *ir.CallExpr, callee *ir.Func, bigCaller bool, log bool) (bool, int32) {
        if callee.Inl == nil {
                // callee is never inlinable.
                if log && logopt.Enabled() {
                        logopt.LogOpt(n.Pos(), "cannotInlineCall", "inline", ir.FuncName(callerfn),
                                fmt.Sprintf("%s cannot be inlined", ir.PkgFuncName(callee)))
                }
-               return false
+               return false, 0
        }
 
-       if ok, maxCost := inlineCostOK(n, callerfn, callee, bigCaller); !ok {
+       ok, maxCost, callSiteScore := inlineCostOK(n, callerfn, callee, bigCaller)
+       if !ok {
                // callee cost too high for this call site.
                if log && logopt.Enabled() {
                        logopt.LogOpt(n.Pos(), "cannotInlineCall", "inline", ir.FuncName(callerfn),
                                fmt.Sprintf("cost %d of %s exceeds max caller cost %d", callee.Inl.Cost, ir.PkgFuncName(callee), maxCost))
                }
-               return false
+               return false, 0
        }
 
        if callee == callerfn {
@@ -939,7 +950,7 @@ func canInlineCallExpr(callerfn *ir.Func, n *ir.CallExpr, callee *ir.Func, bigCa
                if log && logopt.Enabled() {
                        logopt.LogOpt(n.Pos(), "cannotInlineCall", "inline", fmt.Sprintf("recursive call to %s", ir.FuncName(callerfn)))
                }
-               return false
+               return false, 0
        }
 
        if base.Flag.Cfg.Instrumenting && types.IsNoInstrumentPkg(callee.Sym().Pkg) {
@@ -953,7 +964,7 @@ func canInlineCallExpr(callerfn *ir.Func, n *ir.CallExpr, callee *ir.Func, bigCa
                        logopt.LogOpt(n.Pos(), "cannotInlineCall", "inline", ir.FuncName(callerfn),
                                fmt.Sprintf("call to runtime function %s in instrumented build", ir.PkgFuncName(callee)))
                }
-               return false
+               return false, 0
        }
 
        if base.Flag.Race && types.IsNoRacePkg(callee.Sym().Pkg) {
@@ -961,7 +972,7 @@ func canInlineCallExpr(callerfn *ir.Func, n *ir.CallExpr, callee *ir.Func, bigCa
                        logopt.LogOpt(n.Pos(), "cannotInlineCall", "inline", ir.FuncName(callerfn),
                                fmt.Sprintf(`call to into "no-race" package function %s in race build`, ir.PkgFuncName(callee)))
                }
-               return false
+               return false, 0
        }
 
        // Check if we've already inlined this function at this particular
@@ -984,11 +995,11 @@ func canInlineCallExpr(callerfn *ir.Func, n *ir.CallExpr, callee *ir.Func, bigCa
                                                fmt.Sprintf("repeated recursive cycle to %s", ir.PkgFuncName(callee)))
                                }
                        }
-                       return false
+                       return false, 0
                }
        }
 
-       return true
+       return true, callSiteScore
 }
 
 // mkinlcall returns an OINLCALL node that can replace OCALLFUNC n, or
@@ -999,7 +1010,8 @@ func canInlineCallExpr(callerfn *ir.Func, n *ir.CallExpr, callee *ir.Func, bigCa
 //
 //     n.Left = mkinlcall(n.Left, fn, isddd)
 func mkinlcall(callerfn *ir.Func, n *ir.CallExpr, fn *ir.Func, bigCaller bool) *ir.InlinedCallExpr {
-       if !canInlineCallExpr(callerfn, n, fn, bigCaller, true) {
+       ok, score := canInlineCallExpr(callerfn, n, fn, bigCaller, true)
+       if !ok {
                return nil
        }
        typecheck.AssertFixedCall(n)
@@ -1058,7 +1070,12 @@ func mkinlcall(callerfn *ir.Func, n *ir.CallExpr, fn *ir.Func, bigCaller bool) *
        }
 
        if base.Flag.LowerM != 0 {
-               fmt.Printf("%v: inlining call to %v\n", ir.Line(n), fn)
+               if buildcfg.Experiment.NewInliner {
+                       fmt.Printf("%v: inlining call to %v with score %d\n",
+                               ir.Line(n), fn, score)
+               } else {
+                       fmt.Printf("%v: inlining call to %v\n", ir.Line(n), fn)
+               }
        }
        if base.Flag.LowerM > 2 {
                fmt.Printf("%v: Before inlining: %+v\n", ir.Line(n), n)
index 93073b9851f5f4883f83366947a92559710ff115..a1b6f358e17e8eeda955a40da06ebc612b73f653 100644 (file)
@@ -154,7 +154,7 @@ func revisitInlinability(fn *ir.Func, funcProps *FuncProps, budgetForFunc func(*
        if fn.Inl == nil {
                return
        }
-       maxAdj := int32(largestScoreAdjustment(fn, funcProps))
+       maxAdj := int32(LargestNegativeScoreAdjustment(fn, funcProps))
        budget := budgetForFunc(fn)
        if fn.Inl.Cost+maxAdj > budget {
                fn.Inl = nil
index efbca79ae355d687087e6d4eee9d6e7afe3a2f87..623ba8adf0e41aecb0b90c7fe96d87049d6eefe2 100644 (file)
@@ -354,7 +354,7 @@ func setupFlagToAdjMaps() {
        }
 }
 
-// largestScoreAdjustment tries to estimate the largest possible
+// LargestNegativeScoreAdjustment tries to estimate the largest possible
 // negative score adjustment that could be applied to a call of the
 // function with the specified props. Example:
 //
@@ -373,7 +373,7 @@ func setupFlagToAdjMaps() {
 // given call _could_ be rescored down as much as -35 points-- thus if
 // the size of "bar" is 100 (for example) then there is at least a
 // chance that scoring will enable inlining.
-func largestScoreAdjustment(fn *ir.Func, props *FuncProps) int {
+func LargestNegativeScoreAdjustment(fn *ir.Func, props *FuncProps) int {
        if resultFlagToPositiveAdj == nil {
                setupFlagToAdjMaps()
        }
@@ -398,6 +398,14 @@ func largestScoreAdjustment(fn *ir.Func, props *FuncProps) int {
        return score
 }
 
+// LargestPositiveScoreAdjustment tries to estimate the largest possible
+// positive score adjustment that could be applied to a given callsite.
+// At the moment we don't have very many positive score adjustments, so
+// this is just hard-coded, not table-driven.
+func LargestPositiveScoreAdjustment(fn *ir.Func) int {
+       return adjValues[panicPathAdj] + adjValues[initFuncAdj]
+}
+
 // callSiteTab contains entries for each call in the function
 // currently being processed by InlineCalls; this variable will either
 // be set to 'cstabCache' below (for non-inlinable routines) or to the