Skip to content

Commit 63deaf0

Browse files
prattmicgopherbot
authored andcommitted
cmd/compile,cmd/preprofile: move logic to shared common package
The processing performed in cmd/preprofile is a simple version of the same initial processing performed by cmd/compile/internal/pgo. Refactor this processing into the new IR-independent cmd/internal/pgo package. Now cmd/preprofile and cmd/compile run the same code for initial processing of a pprof profile, guaranteeing that they always stay in sync. Since it is now trivial, this CL makes one change to the serialization format: the entries are ordered by weight. This allows us to avoid sorting ByWeight on deserialization. Impact on PGO parsing when compiling cmd/compile with PGO: * Without preprocessing: PGO parsing ~13.7% of CPU time * With preprocessing (unsorted): ~2.9% of CPU time (sorting ~1.7%) * With preprocessing (sorted): ~1.3% of CPU time The remaining 1.3% of CPU time approximately breaks down as: * ~0.5% parsing the preprocessed profile * ~0.7% building weighted IR call graph * ~0.5% walking function IR to find direct calls * ~0.2% performing lookups for indirect calls targets For #58102. Change-Id: Iaba425ea30b063ca195fb2f7b29342961c8a64c2 Reviewed-on: https://go-review.googlesource.com/c/go/+/569337 LUCI-TryBot-Result: Go LUCI <[email protected]> Auto-Submit: Michael Pratt <[email protected]> Reviewed-by: Cherry Mui <[email protected]>
1 parent 2860e01 commit 63deaf0

File tree

16 files changed

+685
-443
lines changed

16 files changed

+685
-443
lines changed

src/cmd/compile/internal/devirtualize/pgo_test.go

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ package devirtualize
77
import (
88
"cmd/compile/internal/base"
99
"cmd/compile/internal/ir"
10-
"cmd/compile/internal/pgo"
10+
pgoir "cmd/compile/internal/pgo"
1111
"cmd/compile/internal/typecheck"
1212
"cmd/compile/internal/types"
1313
"cmd/internal/obj"
14+
"cmd/internal/pgo"
1415
"cmd/internal/src"
1516
"testing"
1617
)
@@ -32,32 +33,32 @@ func makePos(b *src.PosBase, line, col uint) src.XPos {
3233
}
3334

3435
type profileBuilder struct {
35-
p *pgo.Profile
36+
p *pgoir.Profile
3637
}
3738

3839
func newProfileBuilder() *profileBuilder {
39-
// findHotConcreteCallee only uses pgo.Profile.WeightedCG, so we're
40+
// findHotConcreteCallee only uses pgoir.Profile.WeightedCG, so we're
4041
// going to take a shortcut and only construct that.
4142
return &profileBuilder{
42-
p: &pgo.Profile{
43-
WeightedCG: &pgo.IRGraph{
44-
IRNodes: make(map[string]*pgo.IRNode),
43+
p: &pgoir.Profile{
44+
WeightedCG: &pgoir.IRGraph{
45+
IRNodes: make(map[string]*pgoir.IRNode),
4546
},
4647
},
4748
}
4849
}
4950

5051
// Profile returns the constructed profile.
51-
func (p *profileBuilder) Profile() *pgo.Profile {
52+
func (p *profileBuilder) Profile() *pgoir.Profile {
5253
return p.p
5354
}
5455

5556
// NewNode creates a new IRNode and adds it to the profile.
5657
//
5758
// fn may be nil, in which case the node will set LinkerSymbolName.
58-
func (p *profileBuilder) NewNode(name string, fn *ir.Func) *pgo.IRNode {
59-
n := &pgo.IRNode{
60-
OutEdges: make(map[pgo.NamedCallEdge]*pgo.IREdge),
59+
func (p *profileBuilder) NewNode(name string, fn *ir.Func) *pgoir.IRNode {
60+
n := &pgoir.IRNode{
61+
OutEdges: make(map[pgo.NamedCallEdge]*pgoir.IREdge),
6162
}
6263
if fn != nil {
6364
n.AST = fn
@@ -69,13 +70,13 @@ func (p *profileBuilder) NewNode(name string, fn *ir.Func) *pgo.IRNode {
6970
}
7071

7172
// Add a new call edge from caller to callee.
72-
func addEdge(caller, callee *pgo.IRNode, offset int, weight int64) {
73+
func addEdge(caller, callee *pgoir.IRNode, offset int, weight int64) {
7374
namedEdge := pgo.NamedCallEdge{
7475
CallerName: caller.Name(),
7576
CalleeName: callee.Name(),
7677
CallSiteOffset: offset,
7778
}
78-
irEdge := &pgo.IREdge{
79+
irEdge := &pgoir.IREdge{
7980
Src: caller,
8081
Dst: callee,
8182
CallSiteOffset: offset,

src/cmd/compile/internal/inline/inl.go

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,11 @@ import (
3636
"cmd/compile/internal/inline/inlheur"
3737
"cmd/compile/internal/ir"
3838
"cmd/compile/internal/logopt"
39-
"cmd/compile/internal/pgo"
39+
pgoir "cmd/compile/internal/pgo"
4040
"cmd/compile/internal/typecheck"
4141
"cmd/compile/internal/types"
4242
"cmd/internal/obj"
43+
"cmd/internal/pgo"
4344
)
4445

4546
// Inlining budget parameters, gathered in one place
@@ -58,11 +59,11 @@ const (
5859
var (
5960
// List of all hot callee nodes.
6061
// TODO(prattmic): Make this non-global.
61-
candHotCalleeMap = make(map[*pgo.IRNode]struct{})
62+
candHotCalleeMap = make(map[*pgoir.IRNode]struct{})
6263

6364
// List of all hot call sites. CallSiteInfo.Callee is always nil.
6465
// TODO(prattmic): Make this non-global.
65-
candHotEdgeMap = make(map[pgo.CallSiteInfo]struct{})
66+
candHotEdgeMap = make(map[pgoir.CallSiteInfo]struct{})
6667

6768
// Threshold in percentage for hot callsite inlining.
6869
inlineHotCallSiteThresholdPercent float64
@@ -78,7 +79,7 @@ var (
7879
)
7980

8081
// PGOInlinePrologue records the hot callsites from ir-graph.
81-
func PGOInlinePrologue(p *pgo.Profile) {
82+
func PGOInlinePrologue(p *pgoir.Profile) {
8283
if base.Debug.PGOInlineCDFThreshold != "" {
8384
if s, err := strconv.ParseFloat(base.Debug.PGOInlineCDFThreshold, 64); err == nil && s >= 0 && s <= 100 {
8485
inlineCDFHotCallSiteThresholdPercent = s
@@ -103,7 +104,7 @@ func PGOInlinePrologue(p *pgo.Profile) {
103104
}
104105
// mark hot call sites
105106
if caller := p.WeightedCG.IRNodes[n.CallerName]; caller != nil && caller.AST != nil {
106-
csi := pgo.CallSiteInfo{LineOffset: n.CallSiteOffset, Caller: caller.AST}
107+
csi := pgoir.CallSiteInfo{LineOffset: n.CallSiteOffset, Caller: caller.AST}
107108
candHotEdgeMap[csi] = struct{}{}
108109
}
109110
}
@@ -120,7 +121,7 @@ func PGOInlinePrologue(p *pgo.Profile) {
120121
// (currently only used in debug prints) (in case of equal weights,
121122
// comparing with the threshold may not accurately reflect which nodes are
122123
// considered hot).
123-
func hotNodesFromCDF(p *pgo.Profile) (float64, []pgo.NamedCallEdge) {
124+
func hotNodesFromCDF(p *pgoir.Profile) (float64, []pgo.NamedCallEdge) {
124125
cum := int64(0)
125126
for i, n := range p.NamedEdgeMap.ByWeight {
126127
w := p.NamedEdgeMap.Weight[n]
@@ -136,7 +137,7 @@ func hotNodesFromCDF(p *pgo.Profile) (float64, []pgo.NamedCallEdge) {
136137
}
137138

138139
// CanInlineFuncs computes whether a batch of functions are inlinable.
139-
func CanInlineFuncs(funcs []*ir.Func, profile *pgo.Profile) {
140+
func CanInlineFuncs(funcs []*ir.Func, profile *pgoir.Profile) {
140141
if profile != nil {
141142
PGOInlinePrologue(profile)
142143
}
@@ -224,7 +225,7 @@ func GarbageCollectUnreferencedHiddenClosures() {
224225
// possibility that a call to the function might have its score
225226
// adjusted downwards. If 'verbose' is set, then print a remark where
226227
// we boost the budget due to PGO.
227-
func inlineBudget(fn *ir.Func, profile *pgo.Profile, relaxed bool, verbose bool) int32 {
228+
func inlineBudget(fn *ir.Func, profile *pgoir.Profile, relaxed bool, verbose bool) int32 {
228229
// Update the budget for profile-guided inlining.
229230
budget := int32(inlineMaxBudget)
230231
if profile != nil {
@@ -246,7 +247,7 @@ func inlineBudget(fn *ir.Func, profile *pgo.Profile, relaxed bool, verbose bool)
246247
// CanInline determines whether fn is inlineable.
247248
// If so, CanInline saves copies of fn.Body and fn.Dcl in fn.Inl.
248249
// fn and fn.Body will already have been typechecked.
249-
func CanInline(fn *ir.Func, profile *pgo.Profile) {
250+
func CanInline(fn *ir.Func, profile *pgoir.Profile) {
250251
if fn.Nname == nil {
251252
base.Fatalf("CanInline no nname %+v", fn)
252253
}
@@ -451,7 +452,7 @@ type hairyVisitor struct {
451452
extraCallCost int32
452453
usedLocals ir.NameSet
453454
do func(ir.Node) bool
454-
profile *pgo.Profile
455+
profile *pgoir.Profile
455456
}
456457

457458
func (v *hairyVisitor) tooHairy(fn *ir.Func) bool {
@@ -768,7 +769,7 @@ func IsBigFunc(fn *ir.Func) bool {
768769

769770
// TryInlineCall returns an inlined call expression for call, or nil
770771
// if inlining is not possible.
771-
func TryInlineCall(callerfn *ir.Func, call *ir.CallExpr, bigCaller bool, profile *pgo.Profile) *ir.InlinedCallExpr {
772+
func TryInlineCall(callerfn *ir.Func, call *ir.CallExpr, bigCaller bool, profile *pgoir.Profile) *ir.InlinedCallExpr {
772773
if base.Flag.LowerL == 0 {
773774
return nil
774775
}
@@ -804,7 +805,7 @@ func TryInlineCall(callerfn *ir.Func, call *ir.CallExpr, bigCaller bool, profile
804805

805806
// inlCallee takes a function-typed expression and returns the underlying function ONAME
806807
// that it refers to if statically known. Otherwise, it returns nil.
807-
func inlCallee(caller *ir.Func, fn ir.Node, profile *pgo.Profile) (res *ir.Func) {
808+
func inlCallee(caller *ir.Func, fn ir.Node, profile *pgoir.Profile) (res *ir.Func) {
808809
fn = ir.StaticValue(fn)
809810
switch fn.Op() {
810811
case ir.OMETHEXPR:
@@ -877,8 +878,8 @@ func inlineCostOK(n *ir.CallExpr, caller, callee *ir.Func, bigCaller bool) (bool
877878
// We'll also allow inlining of hot functions below inlineHotMaxBudget,
878879
// but only in small functions.
879880

880-
lineOffset := pgo.NodeLineOffset(n, caller)
881-
csi := pgo.CallSiteInfo{LineOffset: lineOffset, Caller: caller}
881+
lineOffset := pgoir.NodeLineOffset(n, caller)
882+
csi := pgoir.CallSiteInfo{LineOffset: lineOffset, Caller: caller}
882883
if _, ok := candHotEdgeMap[csi]; !ok {
883884
// Cold
884885
return false, maxCost, metric
@@ -1188,17 +1189,17 @@ func isAtomicCoverageCounterUpdate(cn *ir.CallExpr) bool {
11881189
return v
11891190
}
11901191

1191-
func PostProcessCallSites(profile *pgo.Profile) {
1192+
func PostProcessCallSites(profile *pgoir.Profile) {
11921193
if base.Debug.DumpInlCallSiteScores != 0 {
1193-
budgetCallback := func(fn *ir.Func, prof *pgo.Profile) (int32, bool) {
1194+
budgetCallback := func(fn *ir.Func, prof *pgoir.Profile) (int32, bool) {
11941195
v := inlineBudget(fn, prof, false, false)
11951196
return v, v == inlineHotMaxBudget
11961197
}
11971198
inlheur.DumpInlCallSiteScores(profile, budgetCallback)
11981199
}
11991200
}
12001201

1201-
func analyzeFuncProps(fn *ir.Func, p *pgo.Profile) {
1202+
func analyzeFuncProps(fn *ir.Func, p *pgoir.Profile) {
12021203
canInline := func(fn *ir.Func) { CanInline(fn, p) }
12031204
budgetForFunc := func(fn *ir.Func) int32 {
12041205
return inlineBudget(fn, p, true, false)

0 commit comments

Comments
 (0)