]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: add -smallframes gc flag for GC latency diagnosis
authorDavid Chase <drchase@google.com>
Wed, 5 Jun 2019 18:53:28 +0000 (14:53 -0400)
committerDavid Chase <drchase@google.com>
Thu, 6 Jun 2019 11:38:40 +0000 (11:38 +0000)
Shrinks the size of things that can be stack allocated from
10M to 128k for declared variables and from 64k to 16k for
implicit allocations (new(T), &T{}, etc).

Usage: "go build -gcflags -smallframes hello.go"

An earlier GOEXPERIMENT version of this caused only one
problem, when a gc-should-detect-oversize-stack test no
longer had an oversized stack to detect.  The change was
converted to a flag to make it easier to access (for
diagnosing "long" GC-related single-thread pauses) and to
remove interference with the test.

Includes test to verify behavior.

Updates #27732.

Change-Id: I1255d484331e77185e07c78389a8b594041204c2
Reviewed-on: https://go-review.googlesource.com/c/go/+/180817
Run-TryBot: David Chase <drchase@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/cmd/compile/internal/gc/go.go
src/cmd/compile/internal/gc/main.go
src/cmd/compile/internal/gc/walk.go
test/fixedbugs/issue27732a.go [new file with mode: 0644]

index 6123e6acc17c5190c06535e76f924789677e059c..a776af9f66aa6c5540c07633d7d970c6bea382ec 100644 (file)
@@ -14,17 +14,21 @@ import (
 
 const (
        BADWIDTH = types.BADWIDTH
+)
 
+var (
        // maximum size variable which we will allocate on the stack.
        // This limit is for explicit variable declarations like "var x T" or "x := ...".
-       maxStackVarSize = 10 * 1024 * 1024
+       // Note: the flag smallframes can update this value.
+       maxStackVarSize = int64(10 * 1024 * 1024)
 
        // maximum size of implicit variables that we will allocate on the stack.
        //   p := new(T)          allocating T on the stack
        //   p := &T{}            allocating T on the stack
        //   s := make([]T, n)    allocating [n]T on the stack
        //   s := []byte("...")   allocating [n]byte on the stack
-       maxImplicitStackVarSize = 64 * 1024
+       // Note: the flag smallframes can update this value.
+       maxImplicitStackVarSize = int64(64 * 1024)
 )
 
 // isRuntimePkg reports whether p is package runtime.
index 51b60fb417b67b3c4e333cd1dc398c97ee61b313..b5b387868b4500820c0c0eec43b19625bafa1a15 100644 (file)
@@ -190,6 +190,10 @@ func Main(archInit func(*Arch)) {
        Nacl = objabi.GOOS == "nacl"
        Wasm := objabi.GOARCH == "wasm"
 
+       // Whether the limit for stack-allocated objects is much smaller than normal.
+       // This can be helpful for diagnosing certain causes of GC latency. See #27732.
+       smallFrames := false
+
        flag.BoolVar(&compiling_runtime, "+", false, "compiling runtime")
        flag.BoolVar(&compiling_std, "std", false, "compiling standard library")
        objabi.Flagcount("%", "debug non-static initializers", &Debug['%'])
@@ -261,13 +265,19 @@ func Main(archInit func(*Arch)) {
        flag.StringVar(&mutexprofile, "mutexprofile", "", "write mutex profile to `file`")
        flag.StringVar(&benchfile, "bench", "", "append benchmark times to `file`")
        flag.BoolVar(&newescape, "newescape", true, "enable new escape analysis")
+       flag.BoolVar(&smallFrames, "smallframes", false, "reduce the size limit for stack allocated objects")
        flag.BoolVar(&Ctxt.UseBASEntries, "dwarfbasentries", Ctxt.UseBASEntries, "use base address selection entries in DWARF")
        objabi.Flagparse(usage)
 
        // Record flags that affect the build result. (And don't
        // record flags that don't, since that would cause spurious
        // changes in the binary.)
-       recordFlags("B", "N", "l", "msan", "race", "shared", "dynlink", "dwarflocationlists", "newescape", "dwarfbasentries")
+       recordFlags("B", "N", "l", "msan", "race", "shared", "dynlink", "dwarflocationlists", "newescape", "dwarfbasentries", "smallFrames")
+
+       if smallFrames {
+               maxStackVarSize = 128 * 1024
+               maxImplicitStackVarSize = 16 * 1024
+       }
 
        Ctxt.Flag_shared = flag_dynlink || flag_shared
        Ctxt.Flag_dynlink = flag_dynlink
index 679c86fab615f8ec1d04a0907efdb39bb7224b95..a8cc313b7634fb09398c95b398e2bd4613f0a7a3 100644 (file)
@@ -1393,7 +1393,7 @@ opswitch:
                        // Allocate a [n]byte of the right size.
                        t := types.NewArray(types.Types[TUINT8], int64(len(sc)))
                        var a *Node
-                       if n.Esc == EscNone && len(sc) <= maxImplicitStackVarSize {
+                       if n.Esc == EscNone && len(sc) <= int(maxImplicitStackVarSize) {
                                a = nod(OADDR, temp(t), nil)
                        } else {
                                a = callnew(t)
diff --git a/test/fixedbugs/issue27732a.go b/test/fixedbugs/issue27732a.go
new file mode 100644 (file)
index 0000000..41b62a6
--- /dev/null
@@ -0,0 +1,23 @@
+// errorcheck -0 -m -l -smallframes -newescape=true
+
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This checks that the -smallframes flag forces a large variable to heap.
+
+package main
+
+const (
+       bufferLen = 200000
+)
+
+type kbyte []byte
+type circularBuffer [bufferLen]kbyte
+
+var sink byte
+
+func main() {
+       var c circularBuffer // ERROR "moved to heap: c$"
+       sink = c[0][0]
+}