Skip to content

Commit 9098d1d

Browse files
committed
runtime: debug code to catch bad gcWork.puts
This adds a debug check to throw immediately if any pointers are added to the gcWork buffer after the mark completion barrier. The intent is to catch the source of the cached GC work that occasionally produces "P has cached GC work at end of mark termination" failures. The result should be that we get "throwOnGCWork" throws instead of "P has cached GC work at end of mark termination" throws, but with useful stack traces. This should be reverted before the release. I've been unable to reproduce this issue locally, but this issue appears fairly regularly on the builders, so the intent is to catch it on the builders. This probably slows down the GC slightly. For #27993. Change-Id: I5035e14058ad313bfbd3d68c41ec05179147a85c Reviewed-on: https://go-review.googlesource.com/c/149969 Run-TryBot: Austin Clements <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Brad Fitzpatrick <[email protected]>
1 parent b8fad4b commit 9098d1d

File tree

3 files changed

+31
-2
lines changed

3 files changed

+31
-2
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ func TestIntendedInlining(t *testing.T) {
8585
"puintptr.ptr",
8686
"spanOf",
8787
"spanOfUnchecked",
88-
"(*gcWork).putFast",
88+
//"(*gcWork).putFast", // TODO(austin): For debugging #27993
8989
"(*gcWork).tryGetFast",
9090
"(*guintptr).set",
9191
"(*markBits).advance",

src/runtime/mgc.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1431,6 +1431,8 @@ top:
14311431
goto top
14321432
}
14331433

1434+
throwOnGCWork = true
1435+
14341436
// There was no global work, no local work, and no Ps
14351437
// communicated work since we took markDoneSema. Therefore
14361438
// there are no grey objects and no more objects can be
@@ -1924,7 +1926,7 @@ func gcMark(start_time int64) {
19241926
// ensured all reachable objects were marked, all of
19251927
// these must be pointers to black objects. Hence we
19261928
// can just discard the write barrier buffer.
1927-
if debug.gccheckmark > 0 {
1929+
if debug.gccheckmark > 0 || throwOnGCWork {
19281930
// For debugging, flush the buffer and make
19291931
// sure it really was all marked.
19301932
wbBufFlush1(p)
@@ -1956,6 +1958,8 @@ func gcMark(start_time int64) {
19561958
gcw.dispose()
19571959
}
19581960

1961+
throwOnGCWork = false
1962+
19591963
cachestats()
19601964

19611965
// Update the marked heap stat.

src/runtime/mgcwork.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@ const (
2222
workbufAlloc = 32 << 10
2323
)
2424

25+
// throwOnGCWork causes any operations that add pointers to a gcWork
26+
// buffer to throw.
27+
//
28+
// TODO(austin): This is a temporary debugging measure for issue
29+
// #27993. To be removed before release.
30+
var throwOnGCWork bool
31+
2532
func init() {
2633
if workbufAlloc%pageSize != 0 || workbufAlloc%_WorkbufSize != 0 {
2734
throw("bad workbufAlloc")
@@ -108,6 +115,10 @@ func (w *gcWork) init() {
108115
// obj must point to the beginning of a heap object or an oblet.
109116
//go:nowritebarrierrec
110117
func (w *gcWork) put(obj uintptr) {
118+
if throwOnGCWork {
119+
throw("throwOnGCWork")
120+
}
121+
111122
flushed := false
112123
wbuf := w.wbuf1
113124
if wbuf == nil {
@@ -142,6 +153,10 @@ func (w *gcWork) put(obj uintptr) {
142153
// otherwise it returns false and the caller needs to call put.
143154
//go:nowritebarrierrec
144155
func (w *gcWork) putFast(obj uintptr) bool {
156+
if throwOnGCWork {
157+
throw("throwOnGCWork")
158+
}
159+
145160
wbuf := w.wbuf1
146161
if wbuf == nil {
147162
return false
@@ -163,6 +178,10 @@ func (w *gcWork) putBatch(obj []uintptr) {
163178
return
164179
}
165180

181+
if throwOnGCWork {
182+
throw("throwOnGCWork")
183+
}
184+
166185
flushed := false
167186
wbuf := w.wbuf1
168187
if wbuf == nil {
@@ -284,10 +303,16 @@ func (w *gcWork) balance() {
284303
return
285304
}
286305
if wbuf := w.wbuf2; wbuf.nobj != 0 {
306+
if throwOnGCWork {
307+
throw("throwOnGCWork")
308+
}
287309
putfull(wbuf)
288310
w.flushedWork = true
289311
w.wbuf2 = getempty()
290312
} else if wbuf := w.wbuf1; wbuf.nobj > 4 {
313+
if throwOnGCWork {
314+
throw("throwOnGCWork")
315+
}
291316
w.wbuf1 = handoff(wbuf)
292317
w.flushedWork = true // handoff did putfull
293318
} else {

0 commit comments

Comments
 (0)