diff options
Diffstat (limited to '8004-runtime-change-gcBackgroundUtilization-optional.patch')
-rw-r--r-- | 8004-runtime-change-gcBackgroundUtilization-optional.patch | 442 |
1 files changed, 0 insertions, 442 deletions
diff --git a/8004-runtime-change-gcBackgroundUtilization-optional.patch b/8004-runtime-change-gcBackgroundUtilization-optional.patch deleted file mode 100644 index 978c028..0000000 --- a/8004-runtime-change-gcBackgroundUtilization-optional.patch +++ /dev/null @@ -1,442 +0,0 @@ -From b270dd5d3dc1cef48866a9b29d26a3745e5dee67 Mon Sep 17 00:00:00 2001 -From: jinye <jinye10@huawei.com> -Date: Wed, 6 Aug 2025 17:20:28 +0800 -Subject: [PATCH] runtime:change gcBackgroundUtilization optional - ---- - src/runtime/export_test.go | 9 ++-- - src/runtime/mgc.go | 8 ++-- - src/runtime/mgclimit.go | 2 +- - src/runtime/mgclimit_test.go | 12 +++--- - src/runtime/mgcpacer.go | 80 +++++++++++++++++++++++------------- - src/runtime/mgcpacer_test.go | 24 ++++++++++- - 6 files changed, 90 insertions(+), 45 deletions(-) - -diff --git a/src/runtime/export_test.go b/src/runtime/export_test.go -index 79d83b3a..29341dd2 100644 ---- a/src/runtime/export_test.go -+++ b/src/runtime/export_test.go -@@ -1324,25 +1324,26 @@ func GCTestPointerClass(p unsafe.Pointer) string { - const Raceenabled = raceenabled - - const ( -- GCBackgroundUtilization = gcBackgroundUtilization -- GCGoalUtilization = gcGoalUtilization - DefaultHeapMinimum = defaultHeapMinimum - MemoryLimitHeapGoalHeadroomPercent = memoryLimitHeapGoalHeadroomPercent - MemoryLimitMinHeapGoalHeadroom = memoryLimitMinHeapGoalHeadroom - ) - -+var GCBackgroundUtilization = gcController.gcRatio -+var GCGoalUtilization = gcGoalUtilization -+ - type GCController struct { - gcControllerState - } - --func NewGCController(gcPercent int, memoryLimit int64) *GCController { -+func NewGCController(gcPercent int, memoryLimit int64, gcRatio float64) *GCController { - // Force the controller to escape. We're going to - // do 64-bit atomics on it, and if it gets stack-allocated - // on a 32-bit architecture, it may get allocated unaligned - // space. - g := Escape(new(GCController)) - g.gcControllerState.test = true // Mark it as a test copy. -- g.init(int32(gcPercent), memoryLimit) -+ g.init(int32(gcPercent), memoryLimit, gcRatio) - return g - } - -diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go -index 48001cfd..b8646679 100644 ---- a/src/runtime/mgc.go -+++ b/src/runtime/mgc.go -@@ -184,7 +184,7 @@ func gcinit() { - // Initialize GC pacer state. - // Use the environment variable GOGC for the initial gcPercent value. - // Use the environment variable GOMEMLIMIT for the initial memoryLimit value. -- gcController.init(readGOGC(), readGOMEMLIMIT()) -+ gcController.init(readGOGC(), readGOMEMLIMIT(), readGOGCRATIO()) - - work.startSema = 1 - work.markDoneSema = 1 -@@ -270,12 +270,12 @@ const ( - - // gcMarkWorkerFractionalMode indicates that a P is currently - // running the "fractional" mark worker. The fractional worker -- // is necessary when GOMAXPROCS*gcBackgroundUtilization is not -+ // is necessary when GOMAXPROCS*gcController.gcRatio is not - // an integer and using only dedicated workers would result in -- // utilization too far from the target of gcBackgroundUtilization. -+ // utilization too far from the target of gcController.gcRatio. - // The fractional worker should run until it is preempted and - // will be scheduled to pick up the fractional part of -- // GOMAXPROCS*gcBackgroundUtilization. -+ // GOMAXPROCS*gcController.gcRatio. - gcMarkWorkerFractionalMode - - // gcMarkWorkerIdleMode indicates that a P is running the mark -diff --git a/src/runtime/mgclimit.go b/src/runtime/mgclimit.go -index ad86fbd6..ae35ee8d 100644 ---- a/src/runtime/mgclimit.go -+++ b/src/runtime/mgclimit.go -@@ -230,7 +230,7 @@ func (l *gcCPULimiterState) updateLocked(now int64) { - // Compute total GC time. - windowGCTime := assistTime - if l.gcEnabled { -- windowGCTime += int64(float64(windowTotalTime) * gcBackgroundUtilization) -+ windowGCTime += int64(float64(windowTotalTime) * gcController.gcRatio) - } - - // Subtract out all idle time from the total time. Do this after computing -diff --git a/src/runtime/mgclimit_test.go b/src/runtime/mgclimit_test.go -index 124da03e..8d3eaa6b 100644 ---- a/src/runtime/mgclimit_test.go -+++ b/src/runtime/mgclimit_test.go -@@ -76,13 +76,13 @@ func TestGCCPULimiter(t *testing.T) { - // Test passing time without assists during a GC. Specifically, just enough to drain the bucket to - // exactly procs nanoseconds (easier to get to because of rounding). - // -- // The window we need to drain the bucket is 1/(1-2*gcBackgroundUtilization) times the current fill: -+ // The window we need to drain the bucket is 1/(1-2*gcController.gcRatio) times the current fill: - // -- // fill + (window * procs * gcBackgroundUtilization - window * procs * (1-gcBackgroundUtilization)) = n -- // fill = n - (window * procs * gcBackgroundUtilization - window * procs * (1-gcBackgroundUtilization)) -- // fill = n + window * procs * ((1-gcBackgroundUtilization) - gcBackgroundUtilization) -- // fill = n + window * procs * (1-2*gcBackgroundUtilization) -- // window = (fill - n) / (procs * (1-2*gcBackgroundUtilization))) -+ // fill + (window * procs * gcController.gcRatio - window * procs * (1-gcController.gcRatio)) = n -+ // fill = n - (window * procs * gcController.gcRatio - window * procs * (1-gcController.gcRatio)) -+ // fill = n + window * procs * ((1-gcController.gcRatio) - gcController.gcRatio) -+ // fill = n + window * procs * (1-2*gcController.gcRatio) -+ // window = (fill - n) / (procs * (1-2*gcController.gcRatio))) - // - // And here we want n=procs: - factor := (1 / (1 - 2*GCBackgroundUtilization)) -diff --git a/src/runtime/mgcpacer.go b/src/runtime/mgcpacer.go -index 3e80fae4..20630c3f 100644 ---- a/src/runtime/mgcpacer.go -+++ b/src/runtime/mgcpacer.go -@@ -12,30 +12,6 @@ import ( - ) - - const ( -- // gcGoalUtilization is the goal CPU utilization for -- // marking as a fraction of GOMAXPROCS. -- // -- // Increasing the goal utilization will shorten GC cycles as the GC -- // has more resources behind it, lessening costs from the write barrier, -- // but comes at the cost of increasing mutator latency. -- gcGoalUtilization = gcBackgroundUtilization -- -- // gcBackgroundUtilization is the fixed CPU utilization for background -- // marking. It must be <= gcGoalUtilization. The difference between -- // gcGoalUtilization and gcBackgroundUtilization will be made up by -- // mark assists. The scheduler will aim to use within 50% of this -- // goal. -- // -- // As a general rule, there's little reason to set gcBackgroundUtilization -- // < gcGoalUtilization. One reason might be in mostly idle applications, -- // where goroutines are unlikely to assist at all, so the actual -- // utilization will be lower than the goal. But this is moot point -- // because the idle mark workers already soak up idle CPU resources. -- // These two values are still kept separate however because they are -- // distinct conceptually, and in previous iterations of the pacer the -- // distinction was more important. -- gcBackgroundUtilization = 0.25 -- - // gcCreditSlack is the amount of scan work credit that can - // accumulate locally before updating gcController.heapScanWork and, - // optionally, gcController.bgScanCredit. Lower values give a more -@@ -72,6 +48,15 @@ const ( - // to maintain the memory limit. - memoryLimitHeapGoalHeadroomPercent = 3 - ) -+// gcGoalUtilization is the goal CPU utilization for -+// marking as a fraction of GOMAXPROCS. -+// -+// Increasing the goal utilization will shorten GC cycles as the GC -+// has more resources behind it, lessening costs from the write barrier, -+// but comes at the cost of increasing mutator latency. -+var gcGoalUtilization = gcController.gcRatio -+ -+ - - // gcController implements the GC pacing controller that determines - // when to trigger concurrent garbage collection and how much marking -@@ -88,6 +73,11 @@ const ( - var gcController gcControllerState - - type gcControllerState struct { -+ // gcController.gcRatio be optional, value equals gcratio/100.0. -+ // Initialized from GOGCRATIO, which in the range of (1, 99). -+ // Default GOGCRATIO is 25. -+ gcRatio float64 -+ - // Initialized from GOGC. GOGC=off means no GC. - gcPercent atomic.Int32 - -@@ -366,11 +356,12 @@ type gcControllerState struct { - _ cpu.CacheLinePad - } - --func (c *gcControllerState) init(gcPercent int32, memoryLimit int64) { -+func (c *gcControllerState) init(gcPercent int32, memoryLimit int64, gcRatio float64) { - c.heapMinimum = defaultHeapMinimum - c.triggered = ^uint64(0) - c.setGCPercent(gcPercent) - c.setMemoryLimit(memoryLimit) -+ c.setGOGCRatio(gcRatio) - c.commit(true) // No sweep phase in the first GC cycle. - // N.B. Don't bother calling traceHeapGoal. Tracing is never enabled at - // initialization time. -@@ -398,13 +389,13 @@ func (c *gcControllerState) startCycle(markStartTime int64, procs int, trigger g - // dedicated workers so that the utilization is closest to - // 25%. For small GOMAXPROCS, this would introduce too much - // error, so we add fractional workers in that case. -- totalUtilizationGoal := float64(procs) * gcBackgroundUtilization -+ totalUtilizationGoal := float64(procs) * gcController.gcRatio - dedicatedMarkWorkersNeeded := int64(totalUtilizationGoal + 0.5) - utilError := float64(dedicatedMarkWorkersNeeded)/totalUtilizationGoal - 1 - const maxUtilError = 0.3 - if utilError < -maxUtilError || utilError > maxUtilError { - // Rounding put us more than 30% off our goal. With -- // gcBackgroundUtilization of 25%, this happens for -+ // gcController.gcRatio of 25%, this happens for - // GOMAXPROCS<=3 or GOMAXPROCS=6. Enable fractional - // workers to compensate. - if float64(dedicatedMarkWorkersNeeded) > totalUtilizationGoal { -@@ -604,7 +595,7 @@ func (c *gcControllerState) endCycle(now int64, procs int, userForced bool) { - assistDuration := now - c.markStartTime - - // Assume background mark hit its utilization goal. -- utilization := gcBackgroundUtilization -+ utilization := gcController.gcRatio - // Add assist utilization; avoid divide by zero. - if assistDuration > 0 { - utilization += float64(c.assistTime.Load()) / float64(assistDuration*int64(procs)) -@@ -1344,6 +1335,39 @@ func readGOMEMLIMIT() int64 { - return n - } - -+func (c *gcControllerState) setGOGCRatio(in float64) float64 { -+ if !c.test { -+ assertWorldStoppedOrLockHeld(&mheap_.lock) -+ } -+ -+ out := c.gcRatio -+ c.gcRatio = in -+ -+ return out -+} -+ -+func readGOGCRATIO() float64 { -+ p := gogetenv("GOGCRATIO") -+ if p == "" { -+ return 0.25 -+ } -+ n, ok := parseByteCount(p) -+ if !ok { -+ print("GOGCRATIO=", p, "\n") -+ throw("malformed GOGCRATIO; get the wrong value") -+ } -+ -+ if n < 1 { -+ n = 1 -+ } else if n > 99 { -+ n = 99 -+ } -+ -+ out := float64(n)/100.0 -+ -+ return out -+} -+ - // addIdleMarkWorker attempts to add a new idle mark worker. - // - // If this returns true, the caller must become an idle mark worker unless -diff --git a/src/runtime/mgcpacer_test.go b/src/runtime/mgcpacer_test.go -index ef1483d6..32d4943c 100644 ---- a/src/runtime/mgcpacer_test.go -+++ b/src/runtime/mgcpacer_test.go -@@ -24,6 +24,7 @@ func TestGcPacer(t *testing.T) { - name: "Steady", - gcPercent: 100, - memoryLimit: math.MaxInt64, -+ gcRatio: 0.25, - globalsBytes: 32 << 10, - nCores: 8, - allocRate: constant(33.0), -@@ -49,6 +50,7 @@ func TestGcPacer(t *testing.T) { - name: "SteadyBigStacks", - gcPercent: 100, - memoryLimit: math.MaxInt64, -+ gcRatio: 0.25, - globalsBytes: 32 << 10, - nCores: 8, - allocRate: constant(132.0), -@@ -77,6 +79,7 @@ func TestGcPacer(t *testing.T) { - name: "SteadyBigGlobals", - gcPercent: 100, - memoryLimit: math.MaxInt64, -+ gcRatio: 0.25, - globalsBytes: 128 << 20, - nCores: 8, - allocRate: constant(132.0), -@@ -105,6 +108,7 @@ func TestGcPacer(t *testing.T) { - name: "StepAlloc", - gcPercent: 100, - memoryLimit: math.MaxInt64, -+ gcRatio: 0.25, - globalsBytes: 32 << 10, - nCores: 8, - allocRate: constant(33.0).sum(ramp(66.0, 1).delay(50)), -@@ -128,6 +132,7 @@ func TestGcPacer(t *testing.T) { - name: "HeavyStepAlloc", - gcPercent: 100, - memoryLimit: math.MaxInt64, -+ gcRatio: 0.25, - globalsBytes: 32 << 10, - nCores: 8, - allocRate: constant(33).sum(ramp(330, 1).delay(50)), -@@ -151,6 +156,7 @@ func TestGcPacer(t *testing.T) { - name: "StepScannableFrac", - gcPercent: 100, - memoryLimit: math.MaxInt64, -+ gcRatio: 0.25, - globalsBytes: 32 << 10, - nCores: 8, - allocRate: constant(128.0), -@@ -176,6 +182,7 @@ func TestGcPacer(t *testing.T) { - name: "HighGOGC", - gcPercent: 1500, - memoryLimit: math.MaxInt64, -+ gcRatio: 0.25, - globalsBytes: 32 << 10, - nCores: 8, - allocRate: random(7, 0x53).offset(165), -@@ -217,6 +224,7 @@ func TestGcPacer(t *testing.T) { - name: "OscAlloc", - gcPercent: 100, - memoryLimit: math.MaxInt64, -+ gcRatio: 0.25, - globalsBytes: 32 << 10, - nCores: 8, - allocRate: oscillate(13, 0, 8).offset(67), -@@ -241,6 +249,7 @@ func TestGcPacer(t *testing.T) { - name: "JitterAlloc", - gcPercent: 100, - memoryLimit: math.MaxInt64, -+ gcRatio: 0.25, - globalsBytes: 32 << 10, - nCores: 8, - allocRate: random(13, 0xf).offset(132), -@@ -266,6 +275,7 @@ func TestGcPacer(t *testing.T) { - name: "HeavyJitterAlloc", - gcPercent: 100, - memoryLimit: math.MaxInt64, -+ gcRatio: 0.25, - globalsBytes: 32 << 10, - nCores: 8, - allocRate: random(33.0, 0x0).offset(330), -@@ -295,6 +305,7 @@ func TestGcPacer(t *testing.T) { - name: "SmallHeapSlowAlloc", - gcPercent: 100, - memoryLimit: math.MaxInt64, -+ gcRatio: 0.25, - globalsBytes: 32 << 10, - nCores: 8, - allocRate: constant(1.0), -@@ -332,6 +343,7 @@ func TestGcPacer(t *testing.T) { - name: "MediumHeapSlowAlloc", - gcPercent: 100, - memoryLimit: math.MaxInt64, -+ gcRatio: 0.25, - globalsBytes: 32 << 10, - nCores: 8, - allocRate: constant(1.0), -@@ -369,6 +381,7 @@ func TestGcPacer(t *testing.T) { - name: "LargeHeapSlowAlloc", - gcPercent: 100, - memoryLimit: math.MaxInt64, -+ gcRatio: 0.25, - globalsBytes: 32 << 10, - nCores: 8, - allocRate: constant(1.0), -@@ -407,6 +420,7 @@ func TestGcPacer(t *testing.T) { - name: "SteadyMemoryLimit", - gcPercent: 100, - memoryLimit: 512 << 20, -+ gcRatio: 0.25, - globalsBytes: 32 << 10, - nCores: 8, - allocRate: constant(33.0), -@@ -436,6 +450,7 @@ func TestGcPacer(t *testing.T) { - name: "SteadyMemoryLimitNoGCPercent", - gcPercent: -1, - memoryLimit: 512 << 20, -+ gcRatio: 0.25, - globalsBytes: 32 << 10, - nCores: 8, - allocRate: constant(33.0), -@@ -465,6 +480,7 @@ func TestGcPacer(t *testing.T) { - name: "ExceedMemoryLimit", - gcPercent: 100, - memoryLimit: 512 << 20, -+ gcRatio: 0.25, - globalsBytes: 32 << 10, - nCores: 8, - allocRate: constant(33.0), -@@ -499,6 +515,7 @@ func TestGcPacer(t *testing.T) { - name: "ExceedMemoryLimitNoGCPercent", - gcPercent: -1, - memoryLimit: 512 << 20, -+ gcRatio: 0.25, - globalsBytes: 32 << 10, - nCores: 8, - allocRate: constant(33.0), -@@ -538,6 +555,7 @@ func TestGcPacer(t *testing.T) { - name: "MaintainMemoryLimit", - gcPercent: 100, - memoryLimit: 512 << 20, -+ gcRatio: 0.25, - globalsBytes: 32 << 10, - nCores: 8, - allocRate: constant(33.0), -@@ -571,6 +589,7 @@ func TestGcPacer(t *testing.T) { - name: "MaintainMemoryLimitNoGCPercent", - gcPercent: -1, - memoryLimit: 512 << 20, -+ gcRatio: 0.25, - globalsBytes: 32 << 10, - nCores: 8, - allocRate: constant(33.0), -@@ -607,7 +626,7 @@ func TestGcPacer(t *testing.T) { - t.Run(e.name, func(t *testing.T) { - t.Parallel() - -- c := NewGCController(e.gcPercent, e.memoryLimit) -+ c := NewGCController(e.gcPercent, e.memoryLimit, e.gcRatio) - var bytesAllocatedBlackLast int64 - results := make([]gcCycleResult, 0, e.length) - for i := 0; i < e.length; i++ { -@@ -762,6 +781,7 @@ type gcExecTest struct { - - gcPercent int - memoryLimit int64 -+ gcRatio float64 - globalsBytes uint64 - nCores int - -@@ -1034,7 +1054,7 @@ func applyMemoryLimitHeapGoalHeadroom(goal uint64) uint64 { - - func TestIdleMarkWorkerCount(t *testing.T) { - const workers = 10 -- c := NewGCController(100, math.MaxInt64) -+ c := NewGCController(100, math.MaxInt64, 0.25) - c.SetMaxIdleMarkWorkers(workers) - for i := 0; i < workers; i++ { - if !c.NeedIdleMarkWorker() { --- -2.33.0 - |