From aa6def790eb5a3a37572a91a6ecb1c766614bb90 Mon Sep 17 00:00:00 2001 From: wshwsh12 <793703860@qq.com> Date: Wed, 23 Nov 2022 16:18:48 +0800 Subject: [PATCH 1/4] set fallback percentage 1.1 --- util/gctuner/memory_limit_tuner.go | 13 ++++++++----- util/gctuner/memory_limit_tuner_test.go | 7 +++---- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/util/gctuner/memory_limit_tuner.go b/util/gctuner/memory_limit_tuner.go index 9dba1bd0bd546..90e8e6b9effb9 100644 --- a/util/gctuner/memory_limit_tuner.go +++ b/util/gctuner/memory_limit_tuner.go @@ -38,6 +38,9 @@ type memoryLimitTuner struct { nextGCTriggeredByMemoryLimit atomicutil.Bool } +// fallbackPercentage indicates the fallback memory limit percentage when turning. +const fallbackPercentage float64 = 1.1 + // tuning check the memory nextGC and judge whether this GC is trigger by memory limit. // Go runtime ensure that it will be called serially. func (t *memoryLimitTuner) tuning() { @@ -61,7 +64,7 @@ func (t *memoryLimitTuner) tuning() { go func() { memory.MemoryLimitGCLast.Store(time.Now()) memory.MemoryLimitGCTotal.Add(1) - debug.SetMemoryLimit(math.MaxInt64) + debug.SetMemoryLimit(t.calcMemoryLimit(fallbackPercentage)) resetInterval := 1 * time.Minute // Wait 1 minute and set back, to avoid frequent GC failpoint.Inject("testMemoryLimitTuner", func(val failpoint.Value) { if val, ok := val.(bool); val && ok { @@ -69,7 +72,7 @@ func (t *memoryLimitTuner) tuning() { } }) time.Sleep(resetInterval) - debug.SetMemoryLimit(t.calcMemoryLimit()) + debug.SetMemoryLimit(t.calcMemoryLimit(t.GetPercentage())) for !t.waitingReset.CompareAndSwap(true, false) { continue } @@ -106,7 +109,7 @@ func (t *memoryLimitTuner) GetPercentage() float64 { // UpdateMemoryLimit updates the memory limit. // This function should be called when `tidb_server_memory_limit` or `tidb_server_memory_limit_gc_trigger` is modified. func (t *memoryLimitTuner) UpdateMemoryLimit() { - var memoryLimit = t.calcMemoryLimit() + var memoryLimit = t.calcMemoryLimit(t.GetPercentage()) if memoryLimit == math.MaxInt64 { t.isTuning.Store(false) } else { @@ -115,8 +118,8 @@ func (t *memoryLimitTuner) UpdateMemoryLimit() { debug.SetMemoryLimit(memoryLimit) } -func (t *memoryLimitTuner) calcMemoryLimit() int64 { - memoryLimit := int64(float64(memory.ServerMemoryLimit.Load()) * t.percentage.Load()) // `tidb_server_memory_limit` * `tidb_server_memory_limit_gc_trigger` +func (t *memoryLimitTuner) calcMemoryLimit(percentage float64) int64 { + memoryLimit := int64(float64(memory.ServerMemoryLimit.Load()) * percentage) // `tidb_server_memory_limit` * `tidb_server_memory_limit_gc_trigger` if memoryLimit == 0 { memoryLimit = math.MaxInt64 } diff --git a/util/gctuner/memory_limit_tuner_test.go b/util/gctuner/memory_limit_tuner_test.go index 47d1d8409d8b5..c908ad384a25d 100644 --- a/util/gctuner/memory_limit_tuner_test.go +++ b/util/gctuner/memory_limit_tuner_test.go @@ -15,7 +15,6 @@ package gctuner import ( - "math" "runtime" "runtime/debug" "testing" @@ -76,7 +75,7 @@ func TestGlobalMemoryTuner(t *testing.T) { checkNextGCEqualMemoryLimit := func() { runtime.ReadMemStats(r) nextGC := r.NextGC - memoryLimit := GlobalMemoryLimitTuner.calcMemoryLimit() + memoryLimit := GlobalMemoryLimitTuner.calcMemoryLimit(GlobalMemoryLimitTuner.GetPercentage()) // In golang source, nextGC = memoryLimit - three parts memory. So check 90%~100% here. require.True(t, nextGC < uint64(memoryLimit)) require.True(t, nextGC > uint64(memoryLimit)/10*9) @@ -91,7 +90,7 @@ func TestGlobalMemoryTuner(t *testing.T) { require.True(t, gcNum < getNowGCNum()) // Test waiting for reset time.Sleep(500 * time.Millisecond) - require.Equal(t, int64(math.MaxInt64), debug.SetMemoryLimit(-1)) + require.Equal(t, GlobalMemoryLimitTuner.calcMemoryLimit(fallbackPercentage), debug.SetMemoryLimit(-1)) gcNum = getNowGCNum() memory100mb := allocator.alloc(100 << 20) time.Sleep(100 * time.Millisecond) @@ -102,7 +101,7 @@ func TestGlobalMemoryTuner(t *testing.T) { runtime.GC() // Trigger GC in 80% again time.Sleep(500 * time.Millisecond) - require.Equal(t, GlobalMemoryLimitTuner.calcMemoryLimit(), debug.SetMemoryLimit(-1)) + require.Equal(t, GlobalMemoryLimitTuner.calcMemoryLimit(GlobalMemoryLimitTuner.GetPercentage()), debug.SetMemoryLimit(-1)) time.Sleep(100 * time.Millisecond) gcNum = getNowGCNum() checkNextGCEqualMemoryLimit() From f61a61a6ed19d2330796d9765a9963a7d46c0220 Mon Sep 17 00:00:00 2001 From: wshwsh12 <793703860@qq.com> Date: Wed, 23 Nov 2022 17:23:27 +0800 Subject: [PATCH 2/4] fix-test --- util/gctuner/memory_limit_tuner_test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/util/gctuner/memory_limit_tuner_test.go b/util/gctuner/memory_limit_tuner_test.go index c908ad384a25d..c6f63215c01dd 100644 --- a/util/gctuner/memory_limit_tuner_test.go +++ b/util/gctuner/memory_limit_tuner_test.go @@ -76,9 +76,8 @@ func TestGlobalMemoryTuner(t *testing.T) { runtime.ReadMemStats(r) nextGC := r.NextGC memoryLimit := GlobalMemoryLimitTuner.calcMemoryLimit(GlobalMemoryLimitTuner.GetPercentage()) - // In golang source, nextGC = memoryLimit - three parts memory. So check 90%~100% here. + // In golang source, nextGC = memoryLimit - three parts memory. require.True(t, nextGC < uint64(memoryLimit)) - require.True(t, nextGC > uint64(memoryLimit)/10*9) } memory600mb := allocator.alloc(600 << 20) From 261741cf8ba26659540f84d2e5f4201203f0cbbf Mon Sep 17 00:00:00 2001 From: wshwsh12 <793703860@qq.com> Date: Wed, 23 Nov 2022 21:20:40 +0800 Subject: [PATCH 3/4] fix lint --- util/gctuner/memory_limit_tuner.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/gctuner/memory_limit_tuner.go b/util/gctuner/memory_limit_tuner.go index 90e8e6b9effb9..208d5d749e430 100644 --- a/util/gctuner/memory_limit_tuner.go +++ b/util/gctuner/memory_limit_tuner.go @@ -118,7 +118,7 @@ func (t *memoryLimitTuner) UpdateMemoryLimit() { debug.SetMemoryLimit(memoryLimit) } -func (t *memoryLimitTuner) calcMemoryLimit(percentage float64) int64 { +func (*memoryLimitTuner) calcMemoryLimit(percentage float64) int64 { memoryLimit := int64(float64(memory.ServerMemoryLimit.Load()) * percentage) // `tidb_server_memory_limit` * `tidb_server_memory_limit_gc_trigger` if memoryLimit == 0 { memoryLimit = math.MaxInt64 From 83cc0b6249d054b829c4c4baca77f4cc16287db9 Mon Sep 17 00:00:00 2001 From: wshwsh12 <793703860@qq.com> Date: Mon, 28 Nov 2022 14:45:01 +0800 Subject: [PATCH 4/4] reset memorylimit when disable global mmeory control --- util/gctuner/memory_limit_tuner.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/util/gctuner/memory_limit_tuner.go b/util/gctuner/memory_limit_tuner.go index 208d5d749e430..1679e012579d0 100644 --- a/util/gctuner/memory_limit_tuner.go +++ b/util/gctuner/memory_limit_tuner.go @@ -112,6 +112,7 @@ func (t *memoryLimitTuner) UpdateMemoryLimit() { var memoryLimit = t.calcMemoryLimit(t.GetPercentage()) if memoryLimit == math.MaxInt64 { t.isTuning.Store(false) + memoryLimit = initGOMemoryLimitValue } else { t.isTuning.Store(true) } @@ -126,6 +127,9 @@ func (*memoryLimitTuner) calcMemoryLimit(percentage float64) int64 { return memoryLimit } +var initGOMemoryLimitValue int64 + func init() { + initGOMemoryLimitValue = debug.SetMemoryLimit(-1) GlobalMemoryLimitTuner.Start() }