Skip to content

Commit f21378a

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 9deda35 commit f21378a

File tree

23 files changed

+1281
-69
lines changed

23 files changed

+1281
-69
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
@@ -186,6 +186,10 @@ func compileFunctions(profile *pgoir.Profile) {
186186
for _, fn := range fns {
187187
fn := fn
188188
queue(func(worker int) {
189+
if base.Flag.PgoBbProfile && profile != nil {
190+
pgoir.CorrectProfileAfterInline(profile.Prof, fn)
191+
}
192+
189193
ssagen.Compile(fn, worker, profile)
190194
compile(fn.Closures)
191195
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

+51
Original file line numberDiff line numberDiff line change
@@ -142,9 +142,60 @@ 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+
145146
// WasmExport is used by the //go:wasmexport directive to store info about
146147
// a WebAssembly function import.
147148
WasmExport *WasmExport
149+
150+
ProfTable NodeProfTable
151+
}
152+
153+
// The type of a counter in node
154+
type Counter = int64
155+
156+
// The type of index in the function counter table
157+
type counterIndex = string
158+
159+
// The type of a table with counters
160+
type NodeProfTable = map[counterIndex]Counter
161+
162+
// ShouldSetCounter returns true if this node type should have a counter
163+
func ShouldSetCounter(n Node) bool {
164+
op := n.Op()
165+
return op != ONAME && op != OLITERAL
166+
}
167+
168+
// Set the counter c to the node n in the function fn
169+
func SetCounter(fn *Func, n Node, c Counter) {
170+
if !ShouldSetCounter(n) {
171+
return
172+
}
173+
174+
idx := fmt.Sprintf("%d:%d", n.Pos().FileIndex(), n.Pos().Line())
175+
t := fn.ProfTable
176+
if t == nil {
177+
// TODO why
178+
return
179+
}
180+
t[idx] = c
181+
}
182+
183+
// Get the counter c to the node n in the function fn
184+
func GetCounter(fn *Func, n Node) Counter {
185+
if !ShouldSetCounter(n) {
186+
return 0
187+
}
188+
189+
idx := fmt.Sprintf("%d:%d", n.Pos().FileIndex(), n.Pos().Line())
190+
t := fn.ProfTable
191+
return t[idx]
192+
}
193+
194+
// Get the counter c to the node n in the function fn
195+
func GetCounterByPos(fn *Func, p src.XPos) Counter {
196+
idx := fmt.Sprintf("%d:%d", p.FileIndex(), p.Line())
197+
t := fn.ProfTable
198+
return t[idx]
148199
}
149200

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

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ func TestSizeof(t *testing.T) {
2121
_64bit uintptr // size on 64bit platforms
2222
}{
2323
{Func{}, 180, 304},
24-
{Name{}, 96, 168},
24+
{Name{}, 104, 168},
2525
}
2626

2727
for _, tt := range tests {

0 commit comments

Comments
 (0)