runtime: add GODEBUG gcshrinkstackoff, gcstackbarrieroff, and gcstoptheworld variables
While we're here, update the documentation and delete variables with no effect.
Change-Id: I4df0d266dff880df61b488ed547c2870205862f0
Reviewed-on: https://go-review.googlesource.com/10790
Reviewed-by: Austin Clements <austin@google.com>
diff --git a/src/runtime/extern.go b/src/runtime/extern.go
index 476c3c5..3882229 100644
--- a/src/runtime/extern.go
+++ b/src/runtime/extern.go
@@ -21,8 +21,8 @@
The runtime/debug package's SetGCPercent function allows changing this
percentage at run time. See http://golang.org/pkg/runtime/debug/#SetGCPercent.
-The GODEBUG variable controls debug output from the runtime. GODEBUG value is
-a comma-separated list of name=val pairs. Supported names are:
+The GODEBUG variable controls debugging variables within the runtime.
+It is a comma-separated list of name=val pairs setting these named variables:
allocfreetrace: setting allocfreetrace=1 causes every allocation to be
profiled and a stack trace printed on each object's allocation and free.
@@ -31,13 +31,34 @@
where each object is allocated on a unique page and addresses are
never recycled.
+ gccheckmark: setting gccheckmark=1 enables verification of the
+ garbage collector's concurrent mark phase by performing a
+ second mark pass while the world is stopped. If the second
+ pass finds a reachable object that was not found by concurrent
+ mark, the garbage collector will panic.
+
+ gcpacertrace: setting gcpacertrace=1 causes the garbage collector to
+ print information about the internal state of the concurrent pacer.
+
+ gcshrinkstackoff: setting gcshrinkstackoff=1 disables moving goroutines
+ onto smaller stacks. In this mode, a goroutine's stack can only grow.
+
+ gcstackbarrieroff: setting gcstackbarrieroff=1 disables the use of stack barriers
+ that allow the garbage collector to avoid repeating a stack scan during the
+ mark termination phase.
+
+ gcstoptheworld: setting gcstoptheworld=1 disables concurrent garbage collection,
+ making every garbage collection a stop-the-world event. Setting gcstoptheworld=2
+ also disables concurrent sweeping after the garbage collection finishes.
+
gctrace: setting gctrace=1 causes the garbage collector to emit a single line to standard
error at each collection, summarizing the amount of memory collected and the
length of the pause. Setting gctrace=2 emits the same summary but also
repeats each collection.
- gcdead: setting gcdead=1 causes the garbage collector to clobber all stack slots
- that it thinks are dead.
+ memprofilerate: setting memprofilerate=X will update the value of runtime.MemProfileRate.
+ When set to 0 memory profiling is disabled. Refer to the description of
+ MemProfileRate for the default value.
invalidptr: defaults to invalidptr=1, causing the garbage collector and stack
copier to crash the program if an invalid pointer value (for example, 1)
@@ -45,9 +66,11 @@
This should only be used as a temporary workaround to diagnose buggy code.
The real fix is to not store integers in pointer-typed locations.
- memprofilerate: setting memprofilerate=X will update the value of runtime.MemProfileRate.
- When set to 0 memory profiling is disabled. Refer to the description of
- MemProfileRate for the default value.
+ sbrk: setting sbrk=1 replaces the memory allocator and garbage collector
+ with a trivial allocator that obtains memory from the operating system and
+ never reclaims any memory.
+
+ scavenge: scavenge=1 enables debugging mode of heap scavenger.
scheddetail: setting schedtrace=X and scheddetail=1 causes the scheduler to emit
detailed multiline info every X milliseconds, describing state of the scheduler,
@@ -56,14 +79,6 @@
schedtrace: setting schedtrace=X causes the scheduler to emit a single line to standard
error every X milliseconds, summarizing the scheduler state.
- scavenge: scavenge=1 enables debugging mode of heap scavenger.
-
- gccheckmark: setting gccheckmark=1 enables verification of the
- garbage collector's concurrent mark phase by performing a
- second mark pass while the world is stopped. If the second
- pass finds a reachable object that was not found by concurrent
- mark, the garbage collector will panic.
-
The GOMAXPROCS variable limits the number of operating system threads that
can execute user-level Go code simultaneously. There is no limit to the number of threads
that can be blocked in system calls on behalf of Go code; those do not count against
diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go
index 53d6797..b7b9ac1 100644
--- a/src/runtime/mgc.go
+++ b/src/runtime/mgc.go
@@ -740,6 +740,12 @@
releasem(mp)
mp = nil
+ if debug.gcstoptheworld == 1 {
+ mode = gcForceMode
+ } else if debug.gcstoptheworld == 2 {
+ mode = gcForceBlockMode
+ }
+
if mode != gcBackgroundMode {
// special synchronous cases
gc(mode)
diff --git a/src/runtime/mgcmark.go b/src/runtime/mgcmark.go
index dead22a..f5fa52d 100644
--- a/src/runtime/mgcmark.go
+++ b/src/runtime/mgcmark.go
@@ -327,6 +327,10 @@
barrierOffset = firstStackBarrierOffset
nextBarrier = sp + barrierOffset
+ if debug.gcstackbarrieroff > 0 {
+ 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.
diff --git a/src/runtime/runtime1.go b/src/runtime/runtime1.go
index ea38830..e483178 100644
--- a/src/runtime/runtime1.go
+++ b/src/runtime/runtime1.go
@@ -306,33 +306,37 @@
// existing int var for that value, which may
// already have an initial value.
var debug struct {
- allocfreetrace int32
- efence int32
- gcdead int32
- gctrace int32
- invalidptr int32
- scavenge int32
- scheddetail int32
- schedtrace int32
- wbshadow int32
- gccheckmark int32
- sbrk int32
- gcpacertrace int32
+ allocfreetrace int32
+ efence int32
+ gccheckmark int32
+ gcpacertrace int32
+ gcshrinkstackoff int32
+ gcstackbarrieroff int32
+ gcstoptheworld int32
+ gctrace int32
+ invalidptr int32
+ sbrk int32
+ scavenge int32
+ scheddetail int32
+ schedtrace int32
+ wbshadow int32
}
var dbgvars = []dbgVar{
{"allocfreetrace", &debug.allocfreetrace},
{"efence", &debug.efence},
- {"gcdead", &debug.gcdead},
+ {"gccheckmark", &debug.gccheckmark},
+ {"gcpacertrace", &debug.gcpacertrace},
+ {"gcshrinkstackoff", &debug.gcshrinkstackoff},
+ {"gcstackbarrieroff", &debug.gcstackbarrieroff},
+ {"gcstoptheworld", &debug.gcstoptheworld},
{"gctrace", &debug.gctrace},
{"invalidptr", &debug.invalidptr},
+ {"sbrk", &debug.sbrk},
{"scavenge", &debug.scavenge},
{"scheddetail", &debug.scheddetail},
{"schedtrace", &debug.schedtrace},
{"wbshadow", &debug.wbshadow},
- {"gccheckmark", &debug.gccheckmark},
- {"sbrk", &debug.sbrk},
- {"gcpacertrace", &debug.gcpacertrace},
}
func parsedebugvars() {
diff --git a/src/runtime/stack1.go b/src/runtime/stack1.go
index 1965e9e..933e3d0 100644
--- a/src/runtime/stack1.go
+++ b/src/runtime/stack1.go
@@ -826,6 +826,10 @@
throw("missing stack in shrinkstack")
}
+ if debug.gcshrinkstackoff > 0 {
+ return
+ }
+
oldsize := gp.stackAlloc
newsize := oldsize / 2
if newsize < _FixedStack {