mirror of
https://github.com/golang/go
synced 2024-11-26 04:07:59 -07:00
cmd/compile/internal/inline: revise -m=2 status messages
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>
This commit is contained in:
parent
2e77b51df5
commit
cfb281754e
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user