已合并
runtime:change gcBackgroundUtilization optional #70
rfwang07创建于 5月18日
runtime:change gcBackgroundUtilization optional #70
已合并
共 6 个文件变更+89-45
| @@ -1324,25 +1324,26 @@ func GCTestPointerClass(p unsafe.Pointer) string { | |||
| 1324 | const Raceenabled = raceenabled | 1324 | const Raceenabled = raceenabled |
| 1325 | 1325 | ||
| 1326 | const ( | 1326 | const ( |
| 1327 | - GCBackgroundUtilization = gcBackgroundUtilization | ||
| 1328 | - GCGoalUtilization = gcGoalUtilization | ||
| 1329 | DefaultHeapMinimum = defaultHeapMinimum | 1327 | DefaultHeapMinimum = defaultHeapMinimum |
| 1330 | MemoryLimitHeapGoalHeadroomPercent = memoryLimitHeapGoalHeadroomPercent | 1328 | MemoryLimitHeapGoalHeadroomPercent = memoryLimitHeapGoalHeadroomPercent |
| 1331 | MemoryLimitMinHeapGoalHeadroom = memoryLimitMinHeapGoalHeadroom | 1329 | MemoryLimitMinHeapGoalHeadroom = memoryLimitMinHeapGoalHeadroom |
| 1332 | ) | 1330 | ) |
| 1333 | 1331 | ||
| 1332 | +var GCBackgroundUtilization = gcController.gcRatio | ||
| 1333 | +var GCGoalUtilization = gcGoalUtilization | ||
| 1334 | + | ||
| 1334 | type GCController struct { | 1335 | type GCController struct { |
| 1335 | gcControllerState | 1336 | gcControllerState |
| 1336 | } | 1337 | } |
| 1337 | 1338 | ||
| 1338 | -func NewGCController(gcPercent int, memoryLimit int64) *GCController { | 1339 | +func NewGCController(gcPercent int, memoryLimit int64, gcRatio float64) *GCController { |
| 1339 | // Force the controller to escape. We're going to | 1340 | // Force the controller to escape. We're going to |
| 1340 | // do 64-bit atomics on it, and if it gets stack-allocated | 1341 | // do 64-bit atomics on it, and if it gets stack-allocated |
| 1341 | // on a 32-bit architecture, it may get allocated unaligned | 1342 | // on a 32-bit architecture, it may get allocated unaligned |
| 1342 | // space. | 1343 | // space. |
| 1343 | g := Escape(new(GCController)) | 1344 | g := Escape(new(GCController)) |
| 1344 | g.gcControllerState.test = true // Mark it as a test copy. | 1345 | g.gcControllerState.test = true // Mark it as a test copy. |
| 1345 | - g.init(int32(gcPercent), memoryLimit) | 1346 | + g.init(int32(gcPercent), memoryLimit, gcRatio) |
| 1346 | return g | 1347 | return g |
| 1347 | } | 1348 | } |
| 1348 | 1349 | ||
| @@ -184,7 +184,7 @@ func gcinit() { | |||
| 184 | // Initialize GC pacer state. | 184 | // Initialize GC pacer state. |
| 185 | // Use the environment variable GOGC for the initial gcPercent value. | 185 | // Use the environment variable GOGC for the initial gcPercent value. |
| 186 | // Use the environment variable GOMEMLIMIT for the initial memoryLimit value. | 186 | // Use the environment variable GOMEMLIMIT for the initial memoryLimit value. |
| 187 | - gcController.init(readGOGC(), readGOMEMLIMIT()) | 187 | + gcController.init(readGOGC(), readGOMEMLIMIT(), readGOGCRATIO()) |
| 188 | 188 | ||
| 189 | work.startSema = 1 | 189 | work.startSema = 1 |
| 190 | work.markDoneSema = 1 | 190 | work.markDoneSema = 1 |
| @@ -270,12 +270,12 @@ const ( | |||
| 270 | 270 | ||
| 271 | // gcMarkWorkerFractionalMode indicates that a P is currently | 271 | // gcMarkWorkerFractionalMode indicates that a P is currently |
| 272 | // running the "fractional" mark worker. The fractional worker | 272 | // running the "fractional" mark worker. The fractional worker |
| 273 | - // is necessary when GOMAXPROCS*gcBackgroundUtilization is not | 273 | + // is necessary when GOMAXPROCS*gcController.gcRatio is not |
| 274 | // an integer and using only dedicated workers would result in | 274 | // an integer and using only dedicated workers would result in |
| 275 | - // utilization too far from the target of gcBackgroundUtilization. | 275 | + // utilization too far from the target of gcController.gcRatio. |
| 276 | // The fractional worker should run until it is preempted and | 276 | // The fractional worker should run until it is preempted and |
| 277 | // will be scheduled to pick up the fractional part of | 277 | // will be scheduled to pick up the fractional part of |
| 278 | - // GOMAXPROCS*gcBackgroundUtilization. | 278 | + // GOMAXPROCS*gcController.gcRatio. |
| 279 | gcMarkWorkerFractionalMode | 279 | gcMarkWorkerFractionalMode |
| 280 | 280 | ||
| 281 | // gcMarkWorkerIdleMode indicates that a P is running the mark | 281 | // gcMarkWorkerIdleMode indicates that a P is running the mark |
| @@ -230,7 +230,7 @@ func (l *gcCPULimiterState) updateLocked(now int64) { | |||
| 230 | // Compute total GC time. | 230 | // Compute total GC time. |
| 231 | windowGCTime := assistTime | 231 | windowGCTime := assistTime |
| 232 | if l.gcEnabled { | 232 | if l.gcEnabled { |
| 233 | - windowGCTime += int64(float64(windowTotalTime) * gcBackgroundUtilization) | 233 | + windowGCTime += int64(float64(windowTotalTime) * gcController.gcRatio) |
| 234 | } | 234 | } |
| 235 | 235 | ||
| 236 | // Subtract out all idle time from the total time. Do this after computing | 236 | // Subtract out all idle time from the total time. Do this after computing |
| @@ -76,13 +76,13 @@ func TestGCCPULimiter(t *testing.T) { | |||
| 76 | // Test passing time without assists during a GC. Specifically, just enough to drain the bucket to | 76 | // Test passing time without assists during a GC. Specifically, just enough to drain the bucket to |
| 77 | // exactly procs nanoseconds (easier to get to because of rounding). | 77 | // exactly procs nanoseconds (easier to get to because of rounding). |
| 78 | // | 78 | // |
| 79 | - // The window we need to drain the bucket is 1/(1-2*gcBackgroundUtilization) times the current fill: | 79 | + // The window we need to drain the bucket is 1/(1-2*gcController.gcRatio) times the current fill: |
| 80 | // | 80 | // |
| 81 | - // fill + (window * procs * gcBackgroundUtilization - window * procs * (1-gcBackgroundUtilization)) = n | 81 | + // fill + (window * procs * gcController.gcRatio - window * procs * (1-gcController.gcRatio)) = n |
| 82 | - // fill = n - (window * procs * gcBackgroundUtilization - window * procs * (1-gcBackgroundUtilization)) | 82 | + // fill = n - (window * procs * gcController.gcRatio - window * procs * (1-gcController.gcRatio)) |
| 83 | - // fill = n + window * procs * ((1-gcBackgroundUtilization) - gcBackgroundUtilization) | 83 | + // fill = n + window * procs * ((1-gcController.gcRatio) - gcController.gcRatio) |
| 84 | - // fill = n + window * procs * (1-2*gcBackgroundUtilization) | 84 | + // fill = n + window * procs * (1-2*gcController.gcRatio) |
| 85 | - // window = (fill - n) / (procs * (1-2*gcBackgroundUtilization))) | 85 | + // window = (fill - n) / (procs * (1-2*gcController.gcRatio))) |
| 86 | // | 86 | // |
| 87 | // And here we want n=procs: | 87 | // And here we want n=procs: |
| 88 | factor := (1 / (1 - 2*GCBackgroundUtilization)) | 88 | factor := (1 / (1 - 2*GCBackgroundUtilization)) |
| @@ -12,30 +12,6 @@ import ( | |||
| 12 | ) | 12 | ) |
| 13 | 13 | ||
| 14 | const ( | 14 | const ( |
| 15 | - // gcGoalUtilization is the goal CPU utilization for | ||
| 16 | - // marking as a fraction of GOMAXPROCS. | ||
| 17 | - // | ||
| 18 | - // Increasing the goal utilization will shorten GC cycles as the GC | ||
| 19 | - // has more resources behind it, lessening costs from the write barrier, | ||
| 20 | - // but comes at the cost of increasing mutator latency. | ||
| 21 | - gcGoalUtilization = gcBackgroundUtilization | ||
| 22 | - | ||
| 23 | - // gcBackgroundUtilization is the fixed CPU utilization for background | ||
| 24 | - // marking. It must be <= gcGoalUtilization. The difference between | ||
| 25 | - // gcGoalUtilization and gcBackgroundUtilization will be made up by | ||
| 26 | - // mark assists. The scheduler will aim to use within 50% of this | ||
| 27 | - // goal. | ||
| 28 | - // | ||
| 29 | - // As a general rule, there's little reason to set gcBackgroundUtilization | ||
| 30 | - // < gcGoalUtilization. One reason might be in mostly idle applications, | ||
| 31 | - // where goroutines are unlikely to assist at all, so the actual | ||
| 32 | - // utilization will be lower than the goal. But this is moot point | ||
| 33 | - // because the idle mark workers already soak up idle CPU resources. | ||
| 34 | - // These two values are still kept separate however because they are | ||
| 35 | - // distinct conceptually, and in previous iterations of the pacer the | ||
| 36 | - // distinction was more important. | ||
| 37 | - gcBackgroundUtilization = 0.25 | ||
| 38 | - | ||
| 39 | // gcCreditSlack is the amount of scan work credit that can | 15 | // gcCreditSlack is the amount of scan work credit that can |
| 40 | // accumulate locally before updating gcController.heapScanWork and, | 16 | // accumulate locally before updating gcController.heapScanWork and, |
| 41 | // optionally, gcController.bgScanCredit. Lower values give a more | 17 | // optionally, gcController.bgScanCredit. Lower values give a more |
| @@ -73,6 +49,14 @@ const ( | |||
| 73 | memoryLimitHeapGoalHeadroomPercent = 3 | 49 | memoryLimitHeapGoalHeadroomPercent = 3 |
| 74 | ) | 50 | ) |
| 75 | 51 | ||
| 52 | +// gcGoalUtilization is the goal CPU utilization for | ||
| 53 | +// marking as a fraction of GOMAXPROCS. | ||
| 54 | +// | ||
| 55 | +// Increasing the goal utilization will shorten GC cycles as the GC | ||
| 56 | +// has more resources behind it, lessening costs from the write barrier, | ||
| 57 | +// but comes at the cost of increasing mutator latency. | ||
| 58 | +var gcGoalUtilization = gcController.gcRatio | ||
| 59 | + | ||
| 76 | // gcController implements the GC pacing controller that determines | 60 | // gcController implements the GC pacing controller that determines |
| 77 | // when to trigger concurrent garbage collection and how much marking | 61 | // when to trigger concurrent garbage collection and how much marking |
| 78 | // work to do in mutator assists and background marking. | 62 | // work to do in mutator assists and background marking. |
| @@ -88,6 +72,11 @@ const ( | |||
| 88 | var gcController gcControllerState | 72 | var gcController gcControllerState |
| 89 | 73 | ||
| 90 | type gcControllerState struct { | 74 | type gcControllerState struct { |
| 75 | + // gcController.gcRatio be optional, value equals gcratio/100.0. | ||
| 76 | + // Initialized from GOGCRATIO, which in the range of (1, 99). | ||
| 77 | + // Default GOGCRATIO is 25. | ||
| 78 | + gcRatio float64 | ||
| 79 | + | ||
| 91 | // Initialized from GOGC. GOGC=off means no GC. | 80 | // Initialized from GOGC. GOGC=off means no GC. |
| 92 | gcPercent atomic.Int32 | 81 | gcPercent atomic.Int32 |
| 93 | 82 | ||
| @@ -366,11 +355,12 @@ type gcControllerState struct { | |||
| 366 | _ cpu.CacheLinePad | 355 | _ cpu.CacheLinePad |
| 367 | } | 356 | } |
| 368 | 357 | ||
| 369 | -func (c *gcControllerState) init(gcPercent int32, memoryLimit int64) { | 358 | +func (c *gcControllerState) init(gcPercent int32, memoryLimit int64, gcRatio float64) { |
| 370 | c.heapMinimum = defaultHeapMinimum | 359 | c.heapMinimum = defaultHeapMinimum |
| 371 | c.triggered = ^uint64(0) | 360 | c.triggered = ^uint64(0) |
| 372 | c.setGCPercent(gcPercent) | 361 | c.setGCPercent(gcPercent) |
| 373 | c.setMemoryLimit(memoryLimit) | 362 | c.setMemoryLimit(memoryLimit) |
| 363 | + c.setGOGCRatio(gcRatio) | ||
| 374 | c.commit(true) // No sweep phase in the first GC cycle. | 364 | c.commit(true) // No sweep phase in the first GC cycle. |
| 375 | // N.B. Don't bother calling traceHeapGoal. Tracing is never enabled at | 365 | // N.B. Don't bother calling traceHeapGoal. Tracing is never enabled at |
| 376 | // initialization time. | 366 | // initialization time. |
| @@ -398,13 +388,13 @@ func (c *gcControllerState) startCycle(markStartTime int64, procs int, trigger g | |||
| 398 | // dedicated workers so that the utilization is closest to | 388 | // dedicated workers so that the utilization is closest to |
| 399 | // 25%. For small GOMAXPROCS, this would introduce too much | 389 | // 25%. For small GOMAXPROCS, this would introduce too much |
| 400 | // error, so we add fractional workers in that case. | 390 | // error, so we add fractional workers in that case. |
| 401 | - totalUtilizationGoal := float64(procs) * gcBackgroundUtilization | 391 | + totalUtilizationGoal := float64(procs) * gcController.gcRatio |
| 402 | dedicatedMarkWorkersNeeded := int64(totalUtilizationGoal + 0.5) | 392 | dedicatedMarkWorkersNeeded := int64(totalUtilizationGoal + 0.5) |
| 403 | utilError := float64(dedicatedMarkWorkersNeeded)/totalUtilizationGoal - 1 | 393 | utilError := float64(dedicatedMarkWorkersNeeded)/totalUtilizationGoal - 1 |
| 404 | const maxUtilError = 0.3 | 394 | const maxUtilError = 0.3 |
| 405 | if utilError < -maxUtilError || utilError > maxUtilError { | 395 | if utilError < -maxUtilError || utilError > maxUtilError { |
| 406 | // Rounding put us more than 30% off our goal. With | 396 | // Rounding put us more than 30% off our goal. With |
| 407 | - // gcBackgroundUtilization of 25%, this happens for | 397 | + // gcController.gcRatio of 25%, this happens for |
| 408 | // GOMAXPROCS<=3 or GOMAXPROCS=6. Enable fractional | 398 | // GOMAXPROCS<=3 or GOMAXPROCS=6. Enable fractional |
| 409 | // workers to compensate. | 399 | // workers to compensate. |
| 410 | if float64(dedicatedMarkWorkersNeeded) > totalUtilizationGoal { | 400 | if float64(dedicatedMarkWorkersNeeded) > totalUtilizationGoal { |
| @@ -604,7 +594,7 @@ func (c *gcControllerState) endCycle(now int64, procs int, userForced bool) { | |||
| 604 | assistDuration := now - c.markStartTime | 594 | assistDuration := now - c.markStartTime |
| 605 | 595 | ||
| 606 | // Assume background mark hit its utilization goal. | 596 | // Assume background mark hit its utilization goal. |
| 607 | - utilization := gcBackgroundUtilization | 597 | + utilization := gcController.gcRatio |
| 608 | // Add assist utilization; avoid divide by zero. | 598 | // Add assist utilization; avoid divide by zero. |
| 609 | if assistDuration > 0 { | 599 | if assistDuration > 0 { |
| 610 | utilization += float64(c.assistTime.Load()) / float64(assistDuration*int64(procs)) | 600 | utilization += float64(c.assistTime.Load()) / float64(assistDuration*int64(procs)) |
| @@ -1344,6 +1334,39 @@ func readGOMEMLIMIT() int64 { | |||
| 1344 | return n | 1334 | return n |
| 1345 | } | 1335 | } |
| 1346 | 1336 | ||
| 1337 | +func (c *gcControllerState) setGOGCRatio(in float64) float64 { | ||
| 1338 | + if !c.test { | ||
| 1339 | + assertWorldStoppedOrLockHeld(&mheap_.lock) | ||
| 1340 | + } | ||
| 1341 | + | ||
| 1342 | + out := c.gcRatio | ||
| 1343 | + c.gcRatio = in | ||
| 1344 | + | ||
| 1345 | + return out | ||
| 1346 | +} | ||
| 1347 | + | ||
| 1348 | +func readGOGCRATIO() float64 { | ||
| 1349 | + p := gogetenv("GOGCRATIO") | ||
| 1350 | + if p == "" { | ||
| 1351 | + return 0.25 | ||
| 1352 | + } | ||
| 1353 | + n, ok := parseByteCount(p) | ||
| 1354 | + if !ok { | ||
| 1355 | + print("GOGCRATIO=", p, "\n") | ||
| 1356 | + throw("malformed GOGCRATIO; get the wrong value") | ||
| 1357 | + } | ||
| 1358 | + | ||
| 1359 | + if n < 1 { | ||
| 1360 | + n = 1 | ||
| 1361 | + } else if n > 99 { | ||
| 1362 | + n = 99 | ||
| 1363 | + } | ||
| 1364 | + | ||
| 1365 | + out := float64(n) / 100.0 | ||
| 1366 | + | ||
| 1367 | + return out | ||
| 1368 | +} | ||
| 1369 | + | ||
| 1347 | // addIdleMarkWorker attempts to add a new idle mark worker. | 1370 | // addIdleMarkWorker attempts to add a new idle mark worker. |
| 1348 | // | 1371 | // |
| 1349 | // If this returns true, the caller must become an idle mark worker unless | 1372 | // If this returns true, the caller must become an idle mark worker unless |
| @@ -24,6 +24,7 @@ func TestGcPacer(t *testing.T) { | |||
| 24 | name: "Steady", | 24 | name: "Steady", |
| 25 | gcPercent: 100, | 25 | gcPercent: 100, |
| 26 | memoryLimit: math.MaxInt64, | 26 | memoryLimit: math.MaxInt64, |
| 27 | + gcRatio: 0.25, | ||
| 27 | globalsBytes: 32 << 10, | 28 | globalsBytes: 32 << 10, |
| 28 | nCores: 8, | 29 | nCores: 8, |
| 29 | allocRate: constant(33.0), | 30 | allocRate: constant(33.0), |
| @@ -49,6 +50,7 @@ func TestGcPacer(t *testing.T) { | |||
| 49 | name: "SteadyBigStacks", | 50 | name: "SteadyBigStacks", |
| 50 | gcPercent: 100, | 51 | gcPercent: 100, |
| 51 | memoryLimit: math.MaxInt64, | 52 | memoryLimit: math.MaxInt64, |
| 53 | + gcRatio: 0.25, | ||
| 52 | globalsBytes: 32 << 10, | 54 | globalsBytes: 32 << 10, |
| 53 | nCores: 8, | 55 | nCores: 8, |
| 54 | allocRate: constant(132.0), | 56 | allocRate: constant(132.0), |
| @@ -77,6 +79,7 @@ func TestGcPacer(t *testing.T) { | |||
| 77 | name: "SteadyBigGlobals", | 79 | name: "SteadyBigGlobals", |
| 78 | gcPercent: 100, | 80 | gcPercent: 100, |
| 79 | memoryLimit: math.MaxInt64, | 81 | memoryLimit: math.MaxInt64, |
| 82 | + gcRatio: 0.25, | ||
| 80 | globalsBytes: 128 << 20, | 83 | globalsBytes: 128 << 20, |
| 81 | nCores: 8, | 84 | nCores: 8, |
| 82 | allocRate: constant(132.0), | 85 | allocRate: constant(132.0), |
| @@ -105,6 +108,7 @@ func TestGcPacer(t *testing.T) { | |||
| 105 | name: "StepAlloc", | 108 | name: "StepAlloc", |
| 106 | gcPercent: 100, | 109 | gcPercent: 100, |
| 107 | memoryLimit: math.MaxInt64, | 110 | memoryLimit: math.MaxInt64, |
| 111 | + gcRatio: 0.25, | ||
| 108 | globalsBytes: 32 << 10, | 112 | globalsBytes: 32 << 10, |
| 109 | nCores: 8, | 113 | nCores: 8, |
| 110 | allocRate: constant(33.0).sum(ramp(66.0, 1).delay(50)), | 114 | allocRate: constant(33.0).sum(ramp(66.0, 1).delay(50)), |
| @@ -128,6 +132,7 @@ func TestGcPacer(t *testing.T) { | |||
| 128 | name: "HeavyStepAlloc", | 132 | name: "HeavyStepAlloc", |
| 129 | gcPercent: 100, | 133 | gcPercent: 100, |
| 130 | memoryLimit: math.MaxInt64, | 134 | memoryLimit: math.MaxInt64, |
| 135 | + gcRatio: 0.25, | ||
| 131 | globalsBytes: 32 << 10, | 136 | globalsBytes: 32 << 10, |
| 132 | nCores: 8, | 137 | nCores: 8, |
| 133 | allocRate: constant(33).sum(ramp(330, 1).delay(50)), | 138 | allocRate: constant(33).sum(ramp(330, 1).delay(50)), |
| @@ -151,6 +156,7 @@ func TestGcPacer(t *testing.T) { | |||
| 151 | name: "StepScannableFrac", | 156 | name: "StepScannableFrac", |
| 152 | gcPercent: 100, | 157 | gcPercent: 100, |
| 153 | memoryLimit: math.MaxInt64, | 158 | memoryLimit: math.MaxInt64, |
| 159 | + gcRatio: 0.25, | ||
| 154 | globalsBytes: 32 << 10, | 160 | globalsBytes: 32 << 10, |
| 155 | nCores: 8, | 161 | nCores: 8, |
| 156 | allocRate: constant(128.0), | 162 | allocRate: constant(128.0), |
| @@ -176,6 +182,7 @@ func TestGcPacer(t *testing.T) { | |||
| 176 | name: "HighGOGC", | 182 | name: "HighGOGC", |
| 177 | gcPercent: 1500, | 183 | gcPercent: 1500, |
| 178 | memoryLimit: math.MaxInt64, | 184 | memoryLimit: math.MaxInt64, |
| 185 | + gcRatio: 0.25, | ||
| 179 | globalsBytes: 32 << 10, | 186 | globalsBytes: 32 << 10, |
| 180 | nCores: 8, | 187 | nCores: 8, |
| 181 | allocRate: random(7, 0x53).offset(165), | 188 | allocRate: random(7, 0x53).offset(165), |
| @@ -217,6 +224,7 @@ func TestGcPacer(t *testing.T) { | |||
| 217 | name: "OscAlloc", | 224 | name: "OscAlloc", |
| 218 | gcPercent: 100, | 225 | gcPercent: 100, |
| 219 | memoryLimit: math.MaxInt64, | 226 | memoryLimit: math.MaxInt64, |
| 227 | + gcRatio: 0.25, | ||
| 220 | globalsBytes: 32 << 10, | 228 | globalsBytes: 32 << 10, |
| 221 | nCores: 8, | 229 | nCores: 8, |
| 222 | allocRate: oscillate(13, 0, 8).offset(67), | 230 | allocRate: oscillate(13, 0, 8).offset(67), |
| @@ -241,6 +249,7 @@ func TestGcPacer(t *testing.T) { | |||
| 241 | name: "JitterAlloc", | 249 | name: "JitterAlloc", |
| 242 | gcPercent: 100, | 250 | gcPercent: 100, |
| 243 | memoryLimit: math.MaxInt64, | 251 | memoryLimit: math.MaxInt64, |
| 252 | + gcRatio: 0.25, | ||
| 244 | globalsBytes: 32 << 10, | 253 | globalsBytes: 32 << 10, |
| 245 | nCores: 8, | 254 | nCores: 8, |
| 246 | allocRate: random(13, 0xf).offset(132), | 255 | allocRate: random(13, 0xf).offset(132), |
| @@ -266,6 +275,7 @@ func TestGcPacer(t *testing.T) { | |||
| 266 | name: "HeavyJitterAlloc", | 275 | name: "HeavyJitterAlloc", |
| 267 | gcPercent: 100, | 276 | gcPercent: 100, |
| 268 | memoryLimit: math.MaxInt64, | 277 | memoryLimit: math.MaxInt64, |
| 278 | + gcRatio: 0.25, | ||
| 269 | globalsBytes: 32 << 10, | 279 | globalsBytes: 32 << 10, |
| 270 | nCores: 8, | 280 | nCores: 8, |
| 271 | allocRate: random(33.0, 0x0).offset(330), | 281 | allocRate: random(33.0, 0x0).offset(330), |
| @@ -295,6 +305,7 @@ func TestGcPacer(t *testing.T) { | |||
| 295 | name: "SmallHeapSlowAlloc", | 305 | name: "SmallHeapSlowAlloc", |
| 296 | gcPercent: 100, | 306 | gcPercent: 100, |
| 297 | memoryLimit: math.MaxInt64, | 307 | memoryLimit: math.MaxInt64, |
| 308 | + gcRatio: 0.25, | ||
| 298 | globalsBytes: 32 << 10, | 309 | globalsBytes: 32 << 10, |
| 299 | nCores: 8, | 310 | nCores: 8, |
| 300 | allocRate: constant(1.0), | 311 | allocRate: constant(1.0), |
| @@ -332,6 +343,7 @@ func TestGcPacer(t *testing.T) { | |||
| 332 | name: "MediumHeapSlowAlloc", | 343 | name: "MediumHeapSlowAlloc", |
| 333 | gcPercent: 100, | 344 | gcPercent: 100, |
| 334 | memoryLimit: math.MaxInt64, | 345 | memoryLimit: math.MaxInt64, |
| 346 | + gcRatio: 0.25, | ||
| 335 | globalsBytes: 32 << 10, | 347 | globalsBytes: 32 << 10, |
| 336 | nCores: 8, | 348 | nCores: 8, |
| 337 | allocRate: constant(1.0), | 349 | allocRate: constant(1.0), |
| @@ -369,6 +381,7 @@ func TestGcPacer(t *testing.T) { | |||
| 369 | name: "LargeHeapSlowAlloc", | 381 | name: "LargeHeapSlowAlloc", |
| 370 | gcPercent: 100, | 382 | gcPercent: 100, |
| 371 | memoryLimit: math.MaxInt64, | 383 | memoryLimit: math.MaxInt64, |
| 384 | + gcRatio: 0.25, | ||
| 372 | globalsBytes: 32 << 10, | 385 | globalsBytes: 32 << 10, |
| 373 | nCores: 8, | 386 | nCores: 8, |
| 374 | allocRate: constant(1.0), | 387 | allocRate: constant(1.0), |
| @@ -407,6 +420,7 @@ func TestGcPacer(t *testing.T) { | |||
| 407 | name: "SteadyMemoryLimit", | 420 | name: "SteadyMemoryLimit", |
| 408 | gcPercent: 100, | 421 | gcPercent: 100, |
| 409 | memoryLimit: 512 << 20, | 422 | memoryLimit: 512 << 20, |
| 423 | + gcRatio: 0.25, | ||
| 410 | globalsBytes: 32 << 10, | 424 | globalsBytes: 32 << 10, |
| 411 | nCores: 8, | 425 | nCores: 8, |
| 412 | allocRate: constant(33.0), | 426 | allocRate: constant(33.0), |
| @@ -436,6 +450,7 @@ func TestGcPacer(t *testing.T) { | |||
| 436 | name: "SteadyMemoryLimitNoGCPercent", | 450 | name: "SteadyMemoryLimitNoGCPercent", |
| 437 | gcPercent: -1, | 451 | gcPercent: -1, |
| 438 | memoryLimit: 512 << 20, | 452 | memoryLimit: 512 << 20, |
| 453 | + gcRatio: 0.25, | ||
| 439 | globalsBytes: 32 << 10, | 454 | globalsBytes: 32 << 10, |
| 440 | nCores: 8, | 455 | nCores: 8, |
| 441 | allocRate: constant(33.0), | 456 | allocRate: constant(33.0), |
| @@ -465,6 +480,7 @@ func TestGcPacer(t *testing.T) { | |||
| 465 | name: "ExceedMemoryLimit", | 480 | name: "ExceedMemoryLimit", |
| 466 | gcPercent: 100, | 481 | gcPercent: 100, |
| 467 | memoryLimit: 512 << 20, | 482 | memoryLimit: 512 << 20, |
| 483 | + gcRatio: 0.25, | ||
| 468 | globalsBytes: 32 << 10, | 484 | globalsBytes: 32 << 10, |
| 469 | nCores: 8, | 485 | nCores: 8, |
| 470 | allocRate: constant(33.0), | 486 | allocRate: constant(33.0), |
| @@ -499,6 +515,7 @@ func TestGcPacer(t *testing.T) { | |||
| 499 | name: "ExceedMemoryLimitNoGCPercent", | 515 | name: "ExceedMemoryLimitNoGCPercent", |
| 500 | gcPercent: -1, | 516 | gcPercent: -1, |
| 501 | memoryLimit: 512 << 20, | 517 | memoryLimit: 512 << 20, |
| 518 | + gcRatio: 0.25, | ||
| 502 | globalsBytes: 32 << 10, | 519 | globalsBytes: 32 << 10, |
| 503 | nCores: 8, | 520 | nCores: 8, |
| 504 | allocRate: constant(33.0), | 521 | allocRate: constant(33.0), |
| @@ -538,6 +555,7 @@ func TestGcPacer(t *testing.T) { | |||
| 538 | name: "MaintainMemoryLimit", | 555 | name: "MaintainMemoryLimit", |
| 539 | gcPercent: 100, | 556 | gcPercent: 100, |
| 540 | memoryLimit: 512 << 20, | 557 | memoryLimit: 512 << 20, |
| 558 | + gcRatio: 0.25, | ||
| 541 | globalsBytes: 32 << 10, | 559 | globalsBytes: 32 << 10, |
| 542 | nCores: 8, | 560 | nCores: 8, |
| 543 | allocRate: constant(33.0), | 561 | allocRate: constant(33.0), |
| @@ -571,6 +589,7 @@ func TestGcPacer(t *testing.T) { | |||
| 571 | name: "MaintainMemoryLimitNoGCPercent", | 589 | name: "MaintainMemoryLimitNoGCPercent", |
| 572 | gcPercent: -1, | 590 | gcPercent: -1, |
| 573 | memoryLimit: 512 << 20, | 591 | memoryLimit: 512 << 20, |
| 592 | + gcRatio: 0.25, | ||
| 574 | globalsBytes: 32 << 10, | 593 | globalsBytes: 32 << 10, |
| 575 | nCores: 8, | 594 | nCores: 8, |
| 576 | allocRate: constant(33.0), | 595 | allocRate: constant(33.0), |
| @@ -607,7 +626,7 @@ func TestGcPacer(t *testing.T) { | |||
| 607 | t.Run(e.name, func(t *testing.T) { | 626 | t.Run(e.name, func(t *testing.T) { |
| 608 | t.Parallel() | 627 | t.Parallel() |
| 609 | 628 | ||
| 610 | - c := NewGCController(e.gcPercent, e.memoryLimit) | 629 | + c := NewGCController(e.gcPercent, e.memoryLimit, e.gcRatio) |
| 611 | var bytesAllocatedBlackLast int64 | 630 | var bytesAllocatedBlackLast int64 |
| 612 | results := make([]gcCycleResult, 0, e.length) | 631 | results := make([]gcCycleResult, 0, e.length) |
| 613 | for i := 0; i < e.length; i++ { | 632 | for i := 0; i < e.length; i++ { |
| @@ -762,6 +781,7 @@ type gcExecTest struct { | |||
| 762 | 781 | ||
| 763 | gcPercent int | 782 | gcPercent int |
| 764 | memoryLimit int64 | 783 | memoryLimit int64 |
| 784 | + gcRatio float64 | ||
| 765 | globalsBytes uint64 | 785 | globalsBytes uint64 |
| 766 | nCores int | 786 | nCores int |
| 767 | 787 | ||
| @@ -1034,7 +1054,7 @@ func applyMemoryLimitHeapGoalHeadroom(goal uint64) uint64 { | |||
| 1034 | 1054 | ||
| 1035 | func TestIdleMarkWorkerCount(t *testing.T) { | 1055 | func TestIdleMarkWorkerCount(t *testing.T) { |
| 1036 | const workers = 10 | 1056 | const workers = 10 |
| 1037 | - c := NewGCController(100, math.MaxInt64) | 1057 | + c := NewGCController(100, math.MaxInt64, 0.25) |
| 1038 | c.SetMaxIdleMarkWorkers(workers) | 1058 | c.SetMaxIdleMarkWorkers(workers) |
| 1039 | for i := 0; i < workers; i++ { | 1059 | for i := 0; i < workers; i++ { |
| 1040 | if !c.NeedIdleMarkWorker() { | 1060 | if !c.NeedIdleMarkWorker() { |