summaryrefslogtreecommitdiff
path: root/src/sync/pool_test.go
diff options
context:
space:
mode:
authorAustin Clements <austin@google.com>2019-03-02 15:16:29 -0500
committerAustin Clements <austin@google.com>2019-04-05 18:49:08 +0000
commit2dcbf8b3691e72d1b04e9376488cef3b6f93b286 (patch)
tree39495d33b1c89c600db20e6141fd25fac24ddd0a /src/sync/pool_test.go
parentd5fd2dd6a17a816b7dfd99d4df70a85f1bf0de31 (diff)
downloadgo-git-2dcbf8b3691e72d1b04e9376488cef3b6f93b286.tar.gz
sync: smooth out Pool behavior over GC with a victim cache
Currently, every Pool is cleared completely at the start of each GC. This is a problem for heavy users of Pool because it causes an allocation spike immediately after Pools are clear, which impacts both throughput and latency. This CL fixes this by introducing a victim cache mechanism. Instead of clearing Pools, the victim cache is dropped and the primary cache is moved to the victim cache. As a result, in steady-state, there are (roughly) no new allocations, but if Pool usage drops, objects will still be collected within two GCs (as opposed to one). This victim cache approach also improves Pool's impact on GC dynamics. The current approach causes all objects in Pools to be short lived. However, if an application is in steady state and is just going to repopulate its Pools, then these objects impact the live heap size *as if* they were long lived. Since Pooled objects count as short lived when computing the GC trigger and goal, but act as long lived objects in the live heap, this causes GC to trigger too frequently. If Pooled objects are a non-trivial portion of an application's heap, this increases the CPU overhead of GC. The victim cache lets Pooled objects affect the GC trigger and goal as long-lived objects. This has no impact on Get/Put performance, but substantially reduces the impact to the Pool user when a GC happens. PoolExpensiveNew demonstrates this in the substantially reduction in the rate at which the "New" function is called. name old time/op new time/op delta Pool-12 2.21ns ±36% 2.00ns ± 0% ~ (p=0.070 n=19+16) PoolOverflow-12 587ns ± 1% 583ns ± 1% -0.77% (p=0.000 n=18+18) PoolSTW-12 5.57µs ± 3% 4.52µs ± 4% -18.82% (p=0.000 n=20+19) PoolExpensiveNew-12 3.69ms ± 7% 1.25ms ± 5% -66.25% (p=0.000 n=20+19) name old p50-ns/STW new p50-ns/STW delta PoolSTW-12 5.48k ± 2% 4.53k ± 2% -17.32% (p=0.000 n=20+20) name old p95-ns/STW new p95-ns/STW delta PoolSTW-12 6.69k ± 4% 5.13k ± 3% -23.31% (p=0.000 n=19+18) name old GCs/op new GCs/op delta PoolExpensiveNew-12 0.39 ± 1% 0.32 ± 2% -17.95% (p=0.000 n=18+20) name old New/op new New/op delta PoolExpensiveNew-12 40.0 ± 6% 12.4 ± 6% -68.91% (p=0.000 n=20+19) (https://perf.golang.org/search?q=upload:20190311.2) Fixes #22950. Change-Id: If2e183d948c650417283076aacc20739682cdd70 Reviewed-on: https://go-review.googlesource.com/c/go/+/166961 Run-TryBot: Austin Clements <austin@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: David Chase <drchase@google.com>
Diffstat (limited to 'src/sync/pool_test.go')
-rw-r--r--src/sync/pool_test.go15
1 files changed, 12 insertions, 3 deletions
diff --git a/src/sync/pool_test.go b/src/sync/pool_test.go
index 5649a9dc83..796a5a0a73 100644
--- a/src/sync/pool_test.go
+++ b/src/sync/pool_test.go
@@ -41,11 +41,20 @@ func TestPool(t *testing.T) {
}
Runtime_procUnpin()
- p.Put("c")
- debug.SetGCPercent(100) // to allow following GC to actually run
+ // Put in a large number of objects so they spill into
+ // stealable space.
+ for i := 0; i < 100; i++ {
+ p.Put("c")
+ }
+ // After one GC, the victim cache should keep them alive.
+ runtime.GC()
+ if g := p.Get(); g != "c" {
+ t.Fatalf("got %#v; want c after GC", g)
+ }
+ // A second GC should drop the victim cache.
runtime.GC()
if g := p.Get(); g != nil {
- t.Fatalf("got %#v; want nil after GC", g)
+ t.Fatalf("got %#v; want nil after second GC", g)
}
}