aboutsummaryrefslogtreecommitdiff
path: root/src/pkg/runtime
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2013-10-02 11:59:53 -0400
committerRuss Cox <rsc@golang.org>2013-10-02 11:59:53 -0400
commitc3dadca9776b6f1c32ee088698e8584636bba2fb (patch)
treea96014da528b8fe357c6d985356f0a587623f2b2 /src/pkg/runtime
parent6b188ef57a644838bd4c673d6d14b49879db6297 (diff)
downloadgo-c3dadca9776b6f1c32ee088698e8584636bba2fb.tar.xz
runtime: do not scan stack by frames during garbage collection
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
Diffstat (limited to 'src/pkg/runtime')
-rw-r--r--src/pkg/runtime/malloc_test.go89
-rw-r--r--src/pkg/runtime/mgc0.c3
2 files changed, 91 insertions, 1 deletions
diff --git a/src/pkg/runtime/malloc_test.go b/src/pkg/runtime/malloc_test.go
index 2b686a6e7e..128ec098cb 100644
--- a/src/pkg/runtime/malloc_test.go
+++ b/src/pkg/runtime/malloc_test.go
@@ -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)
+}
diff --git a/src/pkg/runtime/mgc0.c b/src/pkg/runtime/mgc0.c
index fe9c18177c..7ebc2912ea 100644
--- a/src/pkg/runtime/mgc0.c
+++ b/src/pkg/runtime/mgc0.c
@@ -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) {