]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: remove stack barriers during concurrent mark
authorAustin Clements <austin@google.com>
Wed, 2 Mar 2016 19:52:08 +0000 (14:52 -0500)
committerAustin Clements <austin@google.com>
Tue, 26 Apr 2016 23:40:01 +0000 (23:40 +0000)
Currently we remove stack barriers during STW mark termination, which
has a non-trivial per-goroutine cost and means that we have to touch
even clean stacks during mark termination. However, there's no problem
with leaving them in during the sweep phase. They just have to be out
by the time we install new stack barriers immediately prior to
scanning the stack such as during the mark phase of the next GC cycle
or during mark termination in a STW GC.

Hence, move the gcRemoveStackBarriers from STW mark termination to
just before we install new stack barriers during concurrent mark. This
removes the cost from STW. Furthermore, this combined with concurrent
stack shrinking means that the mark termination scan of a clean stack
is a complete no-op, which will make it possible to skip clean stacks
entirely during mark termination.

This has the downside that it will mess up anything outside of Go that
tries to walk Go stacks all the time instead of just some of the time.
This includes tools like GDB, perf, and VTune. We'll improve the
situation shortly.

Change-Id: Ia40baad8f8c16aeefac05425e00b0cf478137097
Reviewed-on: https://go-review.googlesource.com/20667
Reviewed-by: Rick Hudson <rlh@golang.org>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/runtime/mgcmark.go
src/runtime/mstkbar.go

index 838419040723a2e6af633ee1f50eef64b815397b..bad7c7e92bc2023129adf70a074c4eae1a62d65d 100644 (file)
@@ -602,9 +602,6 @@ func gcFlushBgCredit(scanWork int64) {
 //go:nowritebarrier
 func scanstack(gp *g) {
        if gp.gcscanvalid {
-               if gcphase == _GCmarktermination {
-                       gcRemoveStackBarriers(gp)
-               }
                return
        }
 
@@ -647,6 +644,7 @@ func scanstack(gp *g) {
        } else {
                sp = gp.sched.sp
        }
+       gcLockStackBarriers(gp) // Not necessary during mark term, but harmless.
        switch gcphase {
        case _GCmark:
                // Install stack barriers during stack scan.
@@ -657,16 +655,18 @@ func scanstack(gp *g) {
                        nextBarrier = ^uintptr(0)
                }
 
-               if gp.stkbarPos != 0 || len(gp.stkbar) != 0 {
-                       // If this happens, it's probably because we
-                       // scanned a stack twice in the same phase.
-                       print("stkbarPos=", gp.stkbarPos, " len(stkbar)=", len(gp.stkbar), " goid=", gp.goid, " gcphase=", gcphase, "\n")
-                       throw("g already has stack barriers")
-               }
-
-               gcLockStackBarriers(gp)
+               // Remove any existing stack barriers before we
+               // install new ones.
+               gcRemoveStackBarriers(gp)
 
        case _GCmarktermination:
+               if !work.markrootDone {
+                       // This is a STW GC. There may be stale stack
+                       // barriers from an earlier cycle since we
+                       // never passed through mark phase.
+                       gcRemoveStackBarriers(gp)
+               }
+
                if int(gp.stkbarPos) == len(gp.stkbar) {
                        // gp hit all of the stack barriers (or there
                        // were none). Re-scan the whole stack.
@@ -683,8 +683,6 @@ func scanstack(gp *g) {
                        }
                }
 
-               gcRemoveStackBarriers(gp)
-
        default:
                throw("scanstack in wrong phase")
        }
@@ -722,9 +720,7 @@ func scanstack(gp *g) {
        if gcphase == _GCmarktermination {
                gcw.dispose()
        }
-       if gcphase == _GCmark {
-               gcUnlockStackBarriers(gp)
-       }
+       gcUnlockStackBarriers(gp)
        gp.gcscanvalid = true
 }
 
index 016625ae9255fff364ae925d8d7c502761d00a7d..f320c351d0de688aea39daf172bc5cdb8ec9ed04 100644 (file)
@@ -214,14 +214,15 @@ func gcInstallStackBarrier(gp *g, frame *stkframe) bool {
 }
 
 // gcRemoveStackBarriers removes all stack barriers installed in gp's stack.
+//
+// gp's stack barriers must be locked.
+//
 //go:nowritebarrier
 func gcRemoveStackBarriers(gp *g) {
        if debugStackBarrier && gp.stkbarPos != 0 {
                print("hit ", gp.stkbarPos, " stack barriers, goid=", gp.goid, "\n")
        }
 
-       gcLockStackBarriers(gp)
-
        // Remove stack barriers that we didn't hit.
        for _, stkbar := range gp.stkbar[gp.stkbarPos:] {
                gcRemoveStackBarrier(gp, stkbar)
@@ -231,8 +232,6 @@ func gcRemoveStackBarriers(gp *g) {
        // adjust them.
        gp.stkbarPos = 0
        gp.stkbar = gp.stkbar[:0]
-
-       gcUnlockStackBarriers(gp)
 }
 
 // gcRemoveStackBarrier removes a single stack barrier. It is the