]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: do not scan stack by frames during garbage collection
authorRuss Cox <rsc@golang.org>
Wed, 2 Oct 2013 15:59:53 +0000 (11:59 -0400)
committerRuss Cox <rsc@golang.org>
Wed, 2 Oct 2013 15:59:53 +0000 (11:59 -0400)
Walking the stack by frames is ~3x more expensive
than not, and since it didn't end up being precise,
there is not enough benefit to outweigh the cost.

This is the conservative choice: this CL makes the
stack scanning behavior the same as it was in Go 1.1.

Add benchmarks to package runtime so that we have
them when we re-enable this feature during the
Go 1.3 development.

benchmark                     old ns/op    new ns/op    delta
BenchmarkGoroutineSelect        3194909      1272092  -60.18%
BenchmarkGoroutineBlocking      3120282       866366  -72.23%
BenchmarkGoroutineForRange      3256179       939902  -71.13%
BenchmarkGoroutineIdle          2005571       482982  -75.92%

The Go 1 benchmarks, just to add more data.
As far as I can tell the changes are mainly noise.

benchmark                         old ns/op    new ns/op    delta
BenchmarkBinaryTree17            4409403046   4414734932   +0.12%
BenchmarkFannkuch11              3407708965   3378306120   -0.86%
BenchmarkFmtFprintfEmpty                100           99   -0.60%
BenchmarkFmtFprintfString               242          239   -1.24%
BenchmarkFmtFprintfInt                  204          206   +0.98%
BenchmarkFmtFprintfIntInt               320          316   -1.25%
BenchmarkFmtFprintfPrefixedInt          295          299   +1.36%
BenchmarkFmtFprintfFloat                442          435   -1.58%
BenchmarkFmtManyArgs                   1246         1216   -2.41%
BenchmarkGobDecode                 10186951     10051210   -1.33%
BenchmarkGobEncode                 16504381     16445650   -0.36%
BenchmarkGzip                     447030885    447056865   +0.01%
BenchmarkGunzip                   111056154    111696305   +0.58%
BenchmarkHTTPClientServer             89973        93040   +3.41%
BenchmarkJSONEncode                28174182     27933893   -0.85%
BenchmarkJSONDecode               106353777    110443817   +3.85%
BenchmarkMandelbrot200              4822289      4806083   -0.34%
BenchmarkGoParse                    6102436      6142734   +0.66%
BenchmarkRegexpMatchEasy0_32            133          132   -0.75%
BenchmarkRegexpMatchEasy0_1K            372          373   +0.27%
BenchmarkRegexpMatchEasy1_32            113          111   -1.77%
BenchmarkRegexpMatchEasy1_1K            964          940   -2.49%
BenchmarkRegexpMatchMedium_32           202          205   +1.49%
BenchmarkRegexpMatchMedium_1K         68862        68858   -0.01%
BenchmarkRegexpMatchHard_32            3480         3407   -2.10%
BenchmarkRegexpMatchHard_1K          108255       112614   +4.03%
BenchmarkRevcomp                  751393035    743929976   -0.99%
BenchmarkTemplate                 139637041    135402220   -3.03%
BenchmarkTimeParse                      479          475   -0.84%
BenchmarkTimeFormat                     460          466   +1.30%

benchmark                          old MB/s     new MB/s  speedup
BenchmarkGobDecode                    75.34        76.36    1.01x
BenchmarkGobEncode                    46.50        46.67    1.00x
BenchmarkGzip                         43.41        43.41    1.00x
BenchmarkGunzip                      174.73       173.73    0.99x
BenchmarkJSONEncode                   68.87        69.47    1.01x
BenchmarkJSONDecode                   18.25        17.57    0.96x
BenchmarkGoParse                       9.49         9.43    0.99x
BenchmarkRegexpMatchEasy0_32         239.58       241.74    1.01x
BenchmarkRegexpMatchEasy0_1K        2749.74      2738.00    1.00x
BenchmarkRegexpMatchEasy1_32         282.49       286.32    1.01x
BenchmarkRegexpMatchEasy1_1K        1062.00      1088.96    1.03x
BenchmarkRegexpMatchMedium_32          4.93         4.86    0.99x
BenchmarkRegexpMatchMedium_1K         14.87        14.87    1.00x
BenchmarkRegexpMatchHard_32            9.19         9.39    1.02x
BenchmarkRegexpMatchHard_1K            9.46         9.09    0.96x
BenchmarkRevcomp                     338.26       341.65    1.01x
BenchmarkTemplate                     13.90        14.33    1.03x

Fixes #6482.

R=golang-dev, dave, r
CC=golang-dev
https://golang.org/cl/14257043

src/pkg/runtime/malloc_test.go
src/pkg/runtime/mgc0.c

index 2b686a6e7e5431413cbb751c41e24dabde6e1c58..128ec098cb5ca1ba784e6dbb8dff20ea38f4add1 100644 (file)
@@ -5,8 +5,10 @@
 package runtime_test
 
 import (
+       "flag"
        . "runtime"
        "testing"
+       "time"
        "unsafe"
 )
 
@@ -65,3 +67,90 @@ func BenchmarkMallocTypeInfo16(b *testing.B) {
        }
        mallocSink = x
 }
+
+var n = flag.Int("n", 1000, "number of goroutines")
+
+func BenchmarkGoroutineSelect(b *testing.B) {
+       quit := make(chan struct{})
+       read := func(ch chan struct{}) {
+               for {
+                       select {
+                       case _, ok := <-ch:
+                               if !ok {
+                                       return
+                               }
+                       case <-quit:
+                               return
+                       }
+               }
+       }
+       benchHelper(b, *n, read)
+}
+
+func BenchmarkGoroutineBlocking(b *testing.B) {
+       read := func(ch chan struct{}) {
+               for {
+                       if _, ok := <-ch; !ok {
+                               return
+                       }
+               }
+       }
+       benchHelper(b, *n, read)
+}
+
+func BenchmarkGoroutineForRange(b *testing.B) {
+       read := func(ch chan struct{}) {
+               for _ = range ch {
+               }
+       }
+       benchHelper(b, *n, read)
+}
+
+func benchHelper(b *testing.B, n int, read func(chan struct{})) {
+       m := make([]chan struct{}, n)
+       for i := range m {
+               m[i] = make(chan struct{}, 1)
+               go read(m[i])
+       }
+       b.StopTimer()
+       b.ResetTimer()
+       GC()
+
+       for i := 0; i < b.N; i++ {
+               for _, ch := range m {
+                       if ch != nil {
+                               ch <- struct{}{}
+                       }
+               }
+               time.Sleep(10 * time.Millisecond)
+               b.StartTimer()
+               GC()
+               b.StopTimer()
+       }
+
+       for _, ch := range m {
+               close(ch)
+       }
+       time.Sleep(10 * time.Millisecond)
+}
+
+func BenchmarkGoroutineIdle(b *testing.B) {
+       quit := make(chan struct{})
+       fn := func() {
+               <-quit
+       }
+       for i := 0; i < *n; i++ {
+               go fn()
+       }
+
+       GC()
+       b.ResetTimer()
+
+       for i := 0; i < b.N; i++ {
+               GC()
+       }
+
+       b.StopTimer()
+       close(quit)
+       time.Sleep(10 * time.Millisecond)
+}
index fe9c18177c96f7ea34f3300579247ebb748d4c74..7ebc2912ea8c5456567aa344b1d8270ddaeb683f 100644 (file)
@@ -19,7 +19,7 @@ enum {
        Debug = 0,
        DebugMark = 0,  // run second pass to check mark
        CollectStats = 0,
-       ScanStackByFrames = 1,
+       ScanStackByFrames = 0,
        IgnorePreciseGC = 0,
 
        // Four bits per word (see #defines below).
@@ -1474,6 +1474,7 @@ addstackroots(G *gp)
                USED(guard);
                runtime·gentraceback(pc, sp, lr, gp, 0, nil, 0x7fffffff, addframeroots, nil, false);
        } else {
+               USED(lr);
                USED(pc);
                n = 0;
                while(stk) {