• Austin Clements's avatar
    sync: smooth out Pool behavior over GC with a victim cache · 2dcbf8b3
    Austin Clements authored
    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: default avatarDavid Chase <drchase@google.com>
    2dcbf8b3
pool.go 8.15 KB