diff options
| author | Keith Randall <khr@golang.org> | 2021-08-28 15:50:52 -0700 |
|---|---|---|
| committer | Keith Randall <khr@google.com> | 2022-05-12 22:32:42 +0000 |
| commit | 016d7552138077741a9c3fdadc73c0179f5d3ff7 (patch) | |
| tree | cfe978bcbb00bb7e67a610af16fe5706cd181723 /src/runtime/stack_test.go | |
| parent | da0a6f4b57fc9eb4779c295bc9620c5ed271a641 (diff) | |
| download | go-016d7552138077741a9c3fdadc73c0179f5d3ff7.tar.xz | |
runtime: measure stack usage; start stacks larger if needed
Measure the average stack size used by goroutines at every GC. When
starting a new goroutine, allocate an initial goroutine stack of that
average size. Intuition is that we'll waste at most 2x in stack space
because only half the goroutines can be below average. In turn, we
avoid some of the early stack growth / copying needed in the average
case.
More details in the design doc at: https://docs.google.com/document/d/1YDlGIdVTPnmUiTAavlZxBI1d9pwGQgZT7IKFKlIXohQ/edit?usp=sharing
name old time/op new time/op delta
Issue18138 95.3µs ± 0% 67.3µs ±13% -29.35% (p=0.000 n=9+10)
Fixes #18138
Change-Id: Iba34d22ed04279da7e718bbd569bbf2734922eaa
Reviewed-on: https://go-review.googlesource.com/c/go/+/345889
Run-TryBot: Keith Randall <khr@golang.org>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@google.com>
Diffstat (limited to 'src/runtime/stack_test.go')
| -rw-r--r-- | src/runtime/stack_test.go | 33 |
1 files changed, 33 insertions, 0 deletions
diff --git a/src/runtime/stack_test.go b/src/runtime/stack_test.go index 1a59086901..dfb29a99bc 100644 --- a/src/runtime/stack_test.go +++ b/src/runtime/stack_test.go @@ -597,6 +597,39 @@ func BenchmarkStackCopyWithStkobj(b *testing.B) { } } +func BenchmarkIssue18138(b *testing.B) { + // Channel with N "can run a goroutine" tokens + const N = 10 + c := make(chan []byte, N) + for i := 0; i < N; i++ { + c <- make([]byte, 1) + } + + for i := 0; i < b.N; i++ { + <-c // get token + go func() { + useStackPtrs(1000, false) // uses ~1MB max + m := make([]byte, 8192) // make GC trigger occasionally + c <- m // return token + }() + } +} + +func useStackPtrs(n int, b bool) { + if b { + // This code contributes to the stack frame size, and hence to the + // stack copying cost. But since b is always false, it costs no + // execution time (not even the zeroing of a). + var a [128]*int // 1KB of pointers + a[n] = &n + n = *a[0] + } + if n == 0 { + return + } + useStackPtrs(n-1, b) +} + type structWithMethod struct{} func (s structWithMethod) caller() string { |
