mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
runtime: add GC CPU utilization limiter
This change adds a GC CPU utilization limiter to the GC. It disables assists to ensure GC CPU utilization remains under 50%. It uses a leaky bucket mechanism that will only fill if GC CPU utilization exceeds 50%. Once the bucket begins to overflow, GC assists are limited until the bucket empties, at the risk of GC overshoot. The limiter is primarily updated by assists. The scheduler may also update it, but only if the GC is on and a few milliseconds have passed since the last update. This second case exists to ensure that if the limiter is on, and no assists are happening, we're still updating the limiter regularly. The purpose of this limiter is to mitigate GC death spirals, opting to use more memory instead. This change turns the limiter on always. In practice, 50% overall GC CPU utilization is very difficult to hit unless you're trying; even the most allocation-heavy applications with complex heaps still need to do something with that memory. Note that small GOGC values (i.e. single-digit, or low teens) are more likely to trigger the limiter, which means the GOGC tradeoff may no longer be respected. Even so, it should still be relatively rare. This change also introduces the feature flag for code to support the memory limit feature. For #48409. Change-Id: Ia30f914e683e491a00900fd27868446c65e5d3c2 Reviewed-on: https://go-review.googlesource.com/c/go/+/353989 Reviewed-by: Michael Pratt <mpratt@google.com>
This commit is contained in:
parent
920b9ab57d
commit
01359b4681
7 changed files with 632 additions and 14 deletions
|
|
@ -1312,7 +1312,7 @@ func (c *GCController) Revise(d GCControllerReviseDelta) {
|
|||
}
|
||||
|
||||
func (c *GCController) EndCycle(bytesMarked uint64, assistTime, elapsed int64, gomaxprocs int) {
|
||||
c.assistTime = assistTime
|
||||
c.assistTime.Store(assistTime)
|
||||
c.endCycle(elapsed, gomaxprocs, false)
|
||||
c.resetLive(bytesMarked)
|
||||
c.commit()
|
||||
|
|
@ -1373,6 +1373,61 @@ func (c *PIController) Next(input, setpoint, period float64) (float64, bool) {
|
|||
return c.piController.next(input, setpoint, period)
|
||||
}
|
||||
|
||||
const (
|
||||
CapacityPerProc = capacityPerProc
|
||||
GCCPULimiterUpdatePeriod = gcCPULimiterUpdatePeriod
|
||||
)
|
||||
|
||||
type GCCPULimiter struct {
|
||||
limiter gcCPULimiterState
|
||||
}
|
||||
|
||||
func NewGCCPULimiter(now int64, gomaxprocs int32) *GCCPULimiter {
|
||||
// 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.
|
||||
l := escape(new(GCCPULimiter))
|
||||
l.limiter.resetCapacity(now, gomaxprocs)
|
||||
return l
|
||||
}
|
||||
|
||||
func (l *GCCPULimiter) Fill() uint64 {
|
||||
return l.limiter.bucket.fill
|
||||
}
|
||||
|
||||
func (l *GCCPULimiter) Capacity() uint64 {
|
||||
return l.limiter.bucket.capacity
|
||||
}
|
||||
|
||||
func (l *GCCPULimiter) Overflow() uint64 {
|
||||
return l.limiter.overflow
|
||||
}
|
||||
|
||||
func (l *GCCPULimiter) Limiting() bool {
|
||||
return l.limiter.limiting()
|
||||
}
|
||||
|
||||
func (l *GCCPULimiter) NeedUpdate(now int64) bool {
|
||||
return l.limiter.needUpdate(now)
|
||||
}
|
||||
|
||||
func (l *GCCPULimiter) StartGCTransition(enableGC bool, totalAssistTime, now int64) {
|
||||
l.limiter.startGCTransition(enableGC, totalAssistTime, now)
|
||||
}
|
||||
|
||||
func (l *GCCPULimiter) FinishGCTransition(now int64) {
|
||||
l.limiter.finishGCTransition(now)
|
||||
}
|
||||
|
||||
func (l *GCCPULimiter) Update(totalAssistTime int64, now int64) {
|
||||
l.limiter.update(totalAssistTime, now)
|
||||
}
|
||||
|
||||
func (l *GCCPULimiter) ResetCapacity(now int64, nprocs int32) {
|
||||
l.limiter.resetCapacity(now, nprocs)
|
||||
}
|
||||
|
||||
const ScavengePercent = scavengePercent
|
||||
|
||||
type Scavenger struct {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue