Skip to content

Commit

Permalink
runtime: add testing framework and basic tests for GC pacer
Browse files Browse the repository at this point in the history
This change creates a formal exported interface for the GC pacer and
creates tests for it that simulate some series of GC cycles. The tests
are completely driven by the real pacer implementation, except for
assists, which are idealized (though revise is called repeatedly).

For #44167.

Change-Id: I0112242b07e7702595ca71001d781ad6c1fddd2d
Reviewed-on: https://go-review.googlesource.com/c/go/+/353354
Trust: Michael Knyszek <mknyszek@google.com>
Run-TryBot: Michael Knyszek <mknyszek@google.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
  • Loading branch information
mknyszek committed Oct 29, 2021
1 parent 5ec139f commit 994049a
Show file tree
Hide file tree
Showing 2 changed files with 668 additions and 0 deletions.
78 changes: 78 additions & 0 deletions src/runtime/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1230,3 +1230,81 @@ func GCTestPointerClass(p unsafe.Pointer) string {
}

const Raceenabled = raceenabled

const (
GCBackgroundUtilization = gcBackgroundUtilization
GCGoalUtilization = gcGoalUtilization
)

type GCController struct {
gcControllerState
}

func NewGCController(gcPercent int) *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)).(*GCController)
g.init(int32(gcPercent))
return g
}

func (c *GCController) StartCycle(stackSize, globalsSize uint64, scannableFrac float64, gomaxprocs int) {
c.scannableStackSize = stackSize
c.globalsScan = globalsSize
c.heapLive = c.trigger
c.heapScan += uint64(float64(c.trigger-c.heapMarked) * scannableFrac)
c.startCycle(0, gomaxprocs)
}

func (c *GCController) AssistWorkPerByte() float64 {
return c.assistWorkPerByte.Load()
}

func (c *GCController) HeapGoal() uint64 {
return c.heapGoal
}

func (c *GCController) HeapLive() uint64 {
return c.heapLive
}

func (c *GCController) HeapMarked() uint64 {
return c.heapMarked
}

func (c *GCController) Trigger() uint64 {
return c.trigger
}

type GCControllerReviseDelta struct {
HeapLive int64
HeapScan int64
HeapScanWork int64
StackScanWork int64
GlobalsScanWork int64
}

func (c *GCController) Revise(d GCControllerReviseDelta) {
c.heapLive += uint64(d.HeapLive)
c.heapScan += uint64(d.HeapScan)
c.scanWork += d.HeapScanWork + d.StackScanWork + d.GlobalsScanWork
c.revise()
}

func (c *GCController) EndCycle(bytesMarked uint64, assistTime, elapsed int64, gomaxprocs int) {
c.assistTime = assistTime
triggerRatio := c.endCycle(elapsed, gomaxprocs, false)
c.resetLive(bytesMarked)
c.commit(triggerRatio)
}

var escapeSink interface{}

//go:noinline
func escape(x interface{}) interface{} {
escapeSink = x
escapeSink = nil
return x
}
Loading

0 comments on commit 994049a

Please sign in to comment.