From 4dd00bcae293f4e13b5802cdf4a4fa73cd2a53ce Mon Sep 17 00:00:00 2001 From: Weizhen Wang Date: Mon, 14 Nov 2022 16:41:54 +0800 Subject: [PATCH] gogctuner: support Max/Min GOGC (#39109) close pingcap/tidb#39110 --- util/gctuner/tuner.go | 41 ++++++++++++++++++++++++++------------ util/gctuner/tuner_test.go | 24 +++++++++++----------- 2 files changed, 40 insertions(+), 25 deletions(-) diff --git a/util/gctuner/tuner.go b/util/gctuner/tuner.go index 08d2c06cb8..ec74f48ec4 100644 --- a/util/gctuner/tuner.go +++ b/util/gctuner/tuner.go @@ -23,22 +23,37 @@ import ( "github.com/pingcap/tidb/util" ) -const ( - // MaxGCPercent is the default max cost of memory. - MaxGCPercent uint32 = 500 - // MinGCPercent is the default min cost of memory. - MinGCPercent uint32 = 100 +var ( + maxGCPercent atomic.Uint32 + minGCPercent atomic.Uint32 + + // EnableGOGCTuner is to control whether enable the GOGC tuner. + EnableGOGCTuner atomic.Bool + + defaultGCPercent uint32 = 100 ) -var defaultGCPercent uint32 = 100 +const ( + defaultMaxGCPercent uint32 = 500 + defaultMinGCPercent uint32 = 100 +) -// EnableGOGCTuner is to control whether enable the GOGC tuner. -var EnableGOGCTuner atomic.Bool +// SetMaxGCPercent sets the max cost of memory. +func SetMaxGCPercent(percent uint32) { + maxGCPercent.Store(percent) +} + +// SetMinGCPercent sets the max cost of memory. +func SetMinGCPercent(percent uint32) { + minGCPercent.Store(percent) +} func init() { if val, err := strconv.Atoi(os.Getenv("GOGC")); err == nil { defaultGCPercent = uint32(val) } + SetMinGCPercent(defaultMinGCPercent) + SetMaxGCPercent(defaultMaxGCPercent) } // SetDefaultGOGC is to set the default GOGC value. @@ -151,13 +166,13 @@ func calcGCPercent(inuse, threshold uint64) uint32 { } // inuse heap larger than threshold, use min percent if threshold <= inuse { - return MinGCPercent + return minGCPercent.Load() } gcPercent := uint32(math.Floor(float64(threshold-inuse) / float64(inuse) * 100)) - if gcPercent < MinGCPercent { - return MinGCPercent - } else if gcPercent > MaxGCPercent { - return MaxGCPercent + if gcPercent < minGCPercent.Load() { + return minGCPercent.Load() + } else if gcPercent > maxGCPercent.Load() { + return maxGCPercent.Load() } return gcPercent } diff --git a/util/gctuner/tuner_test.go b/util/gctuner/tuner_test.go index e7b822aced..397f4a621c 100644 --- a/util/gctuner/tuner_test.go +++ b/util/gctuner/tuner_test.go @@ -37,15 +37,15 @@ func TestTuner(t *testing.T) { runtime.GC() for i := 0; i < 100; i++ { runtime.GC() - require.Equal(t, MaxGCPercent, tn.getGCPercent()) + require.Equal(t, maxGCPercent.Load(), tn.getGCPercent()) } // 1/4 threshold testHeap = make([]byte, threshold/4) for i := 0; i < 100; i++ { runtime.GC() - require.GreaterOrEqual(t, tn.getGCPercent(), MaxGCPercent/2) - require.LessOrEqual(t, tn.getGCPercent(), MaxGCPercent) + require.GreaterOrEqual(t, tn.getGCPercent(), maxGCPercent.Load()/2) + require.LessOrEqual(t, tn.getGCPercent(), maxGCPercent.Load()) } // 1/2 threshold @@ -53,8 +53,8 @@ func TestTuner(t *testing.T) { runtime.GC() for i := 0; i < 100; i++ { runtime.GC() - require.GreaterOrEqual(t, tn.getGCPercent(), MinGCPercent) - require.LessOrEqual(t, tn.getGCPercent(), MaxGCPercent/2) + require.GreaterOrEqual(t, tn.getGCPercent(), minGCPercent.Load()) + require.LessOrEqual(t, tn.getGCPercent(), maxGCPercent.Load()/2) } // 3/4 threshold @@ -62,7 +62,7 @@ func TestTuner(t *testing.T) { runtime.GC() for i := 0; i < 100; i++ { runtime.GC() - require.Equal(t, MinGCPercent, tn.getGCPercent()) + require.Equal(t, minGCPercent.Load(), tn.getGCPercent()) } // out of threshold @@ -70,7 +70,7 @@ func TestTuner(t *testing.T) { runtime.GC() for i := 0; i < 100; i++ { runtime.GC() - require.Equal(t, MinGCPercent, tn.getGCPercent()) + require.Equal(t, minGCPercent.Load(), tn.getGCPercent()) } } @@ -81,13 +81,13 @@ func TestCalcGCPercent(t *testing.T) { require.Equal(t, defaultGCPercent, calcGCPercent(0, 1)) require.Equal(t, defaultGCPercent, calcGCPercent(1, 0)) - require.Equal(t, MaxGCPercent, calcGCPercent(1, 3*gb)) - require.Equal(t, MaxGCPercent, calcGCPercent(gb/10, 4*gb)) - require.Equal(t, MaxGCPercent, calcGCPercent(gb/2, 4*gb)) + require.Equal(t, maxGCPercent.Load(), calcGCPercent(1, 3*gb)) + require.Equal(t, maxGCPercent.Load(), calcGCPercent(gb/10, 4*gb)) + require.Equal(t, maxGCPercent.Load(), calcGCPercent(gb/2, 4*gb)) require.Equal(t, uint32(300), calcGCPercent(1*gb, 4*gb)) require.Equal(t, uint32(166), calcGCPercent(1.5*gb, 4*gb)) require.Equal(t, uint32(100), calcGCPercent(2*gb, 4*gb)) require.Equal(t, uint32(100), calcGCPercent(3*gb, 4*gb)) - require.Equal(t, MinGCPercent, calcGCPercent(4*gb, 4*gb)) - require.Equal(t, MinGCPercent, calcGCPercent(5*gb, 4*gb)) + require.Equal(t, minGCPercent.Load(), calcGCPercent(4*gb, 4*gb)) + require.Equal(t, minGCPercent.Load(), calcGCPercent(5*gb, 4*gb)) }