Skip to content

Commit 994049a

Browse files
committed
runtime: add testing framework and basic tests for GC pacer
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>
1 parent 5ec139f commit 994049a

File tree

2 files changed

+668
-0
lines changed

2 files changed

+668
-0
lines changed

src/runtime/export_test.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1230,3 +1230,81 @@ func GCTestPointerClass(p unsafe.Pointer) string {
12301230
}
12311231

12321232
const Raceenabled = raceenabled
1233+
1234+
const (
1235+
GCBackgroundUtilization = gcBackgroundUtilization
1236+
GCGoalUtilization = gcGoalUtilization
1237+
)
1238+
1239+
type GCController struct {
1240+
gcControllerState
1241+
}
1242+
1243+
func NewGCController(gcPercent int) *GCController {
1244+
// Force the controller to escape. We're going to
1245+
// do 64-bit atomics on it, and if it gets stack-allocated
1246+
// on a 32-bit architecture, it may get allocated unaligned
1247+
// space.
1248+
g := escape(new(GCController)).(*GCController)
1249+
g.init(int32(gcPercent))
1250+
return g
1251+
}
1252+
1253+
func (c *GCController) StartCycle(stackSize, globalsSize uint64, scannableFrac float64, gomaxprocs int) {
1254+
c.scannableStackSize = stackSize
1255+
c.globalsScan = globalsSize
1256+
c.heapLive = c.trigger
1257+
c.heapScan += uint64(float64(c.trigger-c.heapMarked) * scannableFrac)
1258+
c.startCycle(0, gomaxprocs)
1259+
}
1260+
1261+
func (c *GCController) AssistWorkPerByte() float64 {
1262+
return c.assistWorkPerByte.Load()
1263+
}
1264+
1265+
func (c *GCController) HeapGoal() uint64 {
1266+
return c.heapGoal
1267+
}
1268+
1269+
func (c *GCController) HeapLive() uint64 {
1270+
return c.heapLive
1271+
}
1272+
1273+
func (c *GCController) HeapMarked() uint64 {
1274+
return c.heapMarked
1275+
}
1276+
1277+
func (c *GCController) Trigger() uint64 {
1278+
return c.trigger
1279+
}
1280+
1281+
type GCControllerReviseDelta struct {
1282+
HeapLive int64
1283+
HeapScan int64
1284+
HeapScanWork int64
1285+
StackScanWork int64
1286+
GlobalsScanWork int64
1287+
}
1288+
1289+
func (c *GCController) Revise(d GCControllerReviseDelta) {
1290+
c.heapLive += uint64(d.HeapLive)
1291+
c.heapScan += uint64(d.HeapScan)
1292+
c.scanWork += d.HeapScanWork + d.StackScanWork + d.GlobalsScanWork
1293+
c.revise()
1294+
}
1295+
1296+
func (c *GCController) EndCycle(bytesMarked uint64, assistTime, elapsed int64, gomaxprocs int) {
1297+
c.assistTime = assistTime
1298+
triggerRatio := c.endCycle(elapsed, gomaxprocs, false)
1299+
c.resetLive(bytesMarked)
1300+
c.commit(triggerRatio)
1301+
}
1302+
1303+
var escapeSink interface{}
1304+
1305+
//go:noinline
1306+
func escape(x interface{}) interface{} {
1307+
escapeSink = x
1308+
escapeSink = nil
1309+
return x
1310+
}

0 commit comments

Comments
 (0)