Skip to content

Commit 14283cd

Browse files
committed
cmd/compile: add ast nodes and basic block counters
Current patch adds the counters to the AST and SSA nodes. The counters are loaded from the pprof file, no profile format changes needed. To use basic block counters you should add an option -pgobb: go build -a -pgobb -pgo=file.prof Fixes golang#65466 Change-Id: I5d6be7d87f384625259a9ba794744a652060de4e
1 parent 7a072fc commit 14283cd

File tree

23 files changed

+1281
-70
lines changed

23 files changed

+1281
-70
lines changed

src/cmd/compile/internal/base/flag.go

+1
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ type CmdFlags struct {
126126
TrimPath string "help:\"remove `prefix` from recorded source file paths\""
127127
WB bool "help:\"enable write barrier\"" // TODO: remove
128128
PgoProfile string "help:\"read profile or pre-process profile from `file`\""
129+
PgoBbProfile bool "help:\"use basic block counters in pgo mode\""
129130
ErrorURL bool "help:\"print explanatory URL with error message if applicable\""
130131

131132
// Configuration derived from flags; not a flag itself.

src/cmd/compile/internal/gc/compile.go

+4
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,10 @@ func compileFunctions(profile *pgoir.Profile) {
180180
for _, fn := range fns {
181181
fn := fn
182182
queue(func(worker int) {
183+
if base.Flag.PgoBbProfile && profile != nil {
184+
pgoir.CorrectProfileAfterInline(profile.Prof, fn)
185+
}
186+
183187
ssagen.Compile(fn, worker, profile)
184188
compile(fn.Closures)
185189
wg.Done()

src/cmd/compile/internal/ir/fmt.go

+31-24
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ func fmtNode(n Node, s fmt.State, verb rune) {
133133
// %+v prints Dump.
134134
// Otherwise we print Go syntax.
135135
if s.Flag('+') && verb == 'v' {
136-
dumpNode(s, n, 1)
136+
dumpNode(s, n, 1, nil)
137137
return
138138
}
139139

@@ -872,7 +872,7 @@ func ellipsisIf(b bool) string {
872872
func (l Nodes) Format(s fmt.State, verb rune) {
873873
if s.Flag('+') && verb == 'v' {
874874
// %+v is DumpList output
875-
dumpNodes(s, l, 1)
875+
dumpNodes(s, l, 1, nil)
876876
return
877877
}
878878

@@ -904,20 +904,23 @@ func Dump(s string, n Node) {
904904
// DumpList prints the message s followed by a debug dump of each node in the list.
905905
func DumpList(s string, list Nodes) {
906906
var buf bytes.Buffer
907-
FDumpList(&buf, s, list)
907+
FDumpList(&buf, s, list, nil)
908908
os.Stdout.Write(buf.Bytes())
909909
}
910910

911911
// FDumpList prints to w the message s followed by a debug dump of each node in the list.
912-
func FDumpList(w io.Writer, s string, list Nodes) {
912+
func FDumpList(w io.Writer, s string, list Nodes, f *Func) {
913913
io.WriteString(w, s)
914-
dumpNodes(w, list, 1)
914+
dumpNodes(w, list, 1, f)
915915
io.WriteString(w, "\n")
916916
}
917917

918918
// indent prints indentation to w.
919-
func indent(w io.Writer, depth int) {
919+
func indent(w io.Writer, depth int, counter int64) {
920920
fmt.Fprint(w, "\n")
921+
if base.Flag.PgoBbProfile {
922+
fmt.Fprintf(w, "%d ", counter)
923+
}
921924
for i := 0; i < depth; i++ {
922925
fmt.Fprint(w, ". ")
923926
}
@@ -1048,8 +1051,8 @@ func dumpNodeHeader(w io.Writer, n Node) {
10481051
}
10491052
}
10501053

1051-
func dumpNode(w io.Writer, n Node, depth int) {
1052-
indent(w, depth)
1054+
func dumpNode(w io.Writer, n Node, depth int, f *Func) {
1055+
indent(w, depth, GetCounter(f, n))
10531056
if depth > 40 {
10541057
fmt.Fprint(w, "...")
10551058
return
@@ -1062,8 +1065,8 @@ func dumpNode(w io.Writer, n Node, depth int) {
10621065

10631066
if len(n.Init()) != 0 {
10641067
fmt.Fprintf(w, "%+v-init", n.Op())
1065-
dumpNodes(w, n.Init(), depth+1)
1066-
indent(w, depth)
1068+
dumpNodes(w, n.Init(), depth+1, f)
1069+
indent(w, depth, GetCounter(f, n))
10671070
}
10681071

10691072
switch n.Op() {
@@ -1116,23 +1119,23 @@ func dumpNode(w io.Writer, n Node, depth int) {
11161119
dumpNodeHeader(w, n)
11171120
fn := n
11181121
if len(fn.Dcl) > 0 {
1119-
indent(w, depth)
1122+
indent(w, depth, GetCounter(f, n))
11201123
fmt.Fprintf(w, "%+v-Dcl", n.Op())
11211124
for _, dcl := range n.Dcl {
1122-
dumpNode(w, dcl, depth+1)
1125+
dumpNode(w, dcl, depth+1, f)
11231126
}
11241127
}
11251128
if len(fn.ClosureVars) > 0 {
1126-
indent(w, depth)
1129+
indent(w, depth, GetCounter(f, n))
11271130
fmt.Fprintf(w, "%+v-ClosureVars", n.Op())
11281131
for _, cv := range fn.ClosureVars {
1129-
dumpNode(w, cv, depth+1)
1132+
dumpNode(w, cv, depth+1, f)
11301133
}
11311134
}
11321135
if len(fn.Body) > 0 {
1133-
indent(w, depth)
1136+
indent(w, depth, GetCounter(f, n))
11341137
fmt.Fprintf(w, "%+v-body", n.Op())
1135-
dumpNodes(w, fn.Body, depth+1)
1138+
dumpNodes(w, fn.Body, depth+1, f)
11361139
}
11371140
return
11381141
}
@@ -1164,30 +1167,34 @@ func dumpNode(w io.Writer, n Node, depth int) {
11641167
switch val := vf.Interface().(type) {
11651168
case Node:
11661169
if name != "" {
1167-
indent(w, depth)
1170+
indent(w, depth, GetCounter(f, n))
11681171
fmt.Fprintf(w, "%+v-%s", n.Op(), name)
11691172
}
1170-
dumpNode(w, val, depth+1)
1173+
dumpNode(w, val, depth+1, f)
11711174
case Nodes:
11721175
if len(val) == 0 {
11731176
continue
11741177
}
11751178
if name != "" {
1176-
indent(w, depth)
1179+
c := GetCounter(f, n)
1180+
if len(val) > 0 {
1181+
c = GetCounter(f, val[0])
1182+
}
1183+
indent(w, depth, c)
11771184
fmt.Fprintf(w, "%+v-%s", n.Op(), name)
11781185
}
1179-
dumpNodes(w, val, depth+1)
1186+
dumpNodes(w, val, depth+1, f)
11801187
default:
11811188
if vf.Kind() == reflect.Slice && vf.Type().Elem().Implements(nodeType) {
11821189
if vf.Len() == 0 {
11831190
continue
11841191
}
11851192
if name != "" {
1186-
indent(w, depth)
1193+
indent(w, depth, GetCounter(f, n))
11871194
fmt.Fprintf(w, "%+v-%s", n.Op(), name)
11881195
}
11891196
for i, n := 0, vf.Len(); i < n; i++ {
1190-
dumpNode(w, vf.Index(i).Interface().(Node), depth+1)
1197+
dumpNode(w, vf.Index(i).Interface().(Node), depth+1, f)
11911198
}
11921199
}
11931200
}
@@ -1196,13 +1203,13 @@ func dumpNode(w io.Writer, n Node, depth int) {
11961203

11971204
var nodeType = reflect.TypeOf((*Node)(nil)).Elem()
11981205

1199-
func dumpNodes(w io.Writer, list Nodes, depth int) {
1206+
func dumpNodes(w io.Writer, list Nodes, depth int, f *Func) {
12001207
if len(list) == 0 {
12011208
fmt.Fprintf(w, " <nil>")
12021209
return
12031210
}
12041211

12051212
for _, n := range list {
1206-
dumpNode(w, n, depth)
1213+
dumpNode(w, n, depth, f)
12071214
}
12081215
}

src/cmd/compile/internal/ir/func.go

+50
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,56 @@ type Func struct {
142142
// WasmImport is used by the //go:wasmimport directive to store info about
143143
// a WebAssembly function import.
144144
WasmImport *WasmImport
145+
146+
ProfTable NodeProfTable
147+
}
148+
149+
// The type of a counter in node
150+
type Counter = int64
151+
152+
// The type of index in the function counter table
153+
type counterIndex = string
154+
155+
// The type of a table with counters
156+
type NodeProfTable = map[counterIndex]Counter
157+
158+
// ShouldSetCounter returns true if this node type should have a counter
159+
func ShouldSetCounter(n Node) bool {
160+
op := n.Op()
161+
return op != ONAME && op != OLITERAL
162+
}
163+
164+
// Set the counter c to the node n in the function fn
165+
func SetCounter(fn *Func, n Node, c Counter) {
166+
if !ShouldSetCounter(n) {
167+
return
168+
}
169+
170+
idx := fmt.Sprintf("%d:%d", n.Pos().FileIndex(), n.Pos().Line())
171+
t := fn.ProfTable
172+
if t == nil {
173+
// TODO why
174+
return
175+
}
176+
t[idx] = c
177+
}
178+
179+
// Get the counter c to the node n in the function fn
180+
func GetCounter(fn *Func, n Node) Counter {
181+
if !ShouldSetCounter(n) {
182+
return 0
183+
}
184+
185+
idx := fmt.Sprintf("%d:%d", n.Pos().FileIndex(), n.Pos().Line())
186+
t := fn.ProfTable
187+
return t[idx]
188+
}
189+
190+
// Get the counter c to the node n in the function fn
191+
func GetCounterByPos(fn *Func, p src.XPos) Counter {
192+
idx := fmt.Sprintf("%d:%d", p.FileIndex(), p.Line())
193+
t := fn.ProfTable
194+
return t[idx]
145195
}
146196

147197
// WasmImport stores metadata associated with the //go:wasmimport pragma.

src/cmd/compile/internal/ir/sizeof_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ func TestSizeof(t *testing.T) {
2020
_32bit uintptr // size on 32bit platforms
2121
_64bit uintptr // size on 64bit platforms
2222
}{
23-
{Func{}, 176, 296},
24-
{Name{}, 96, 168},
23+
{Func{}, 176, 304},
24+
{Name{}, 104, 168},
2525
}
2626

2727
for _, tt := range tests {

0 commit comments

Comments
 (0)