mirror of
https://github.com/golang/go
synced 2024-11-17 21:04:43 -07:00
runtime: test that periodic GC works
We've broken periodic GC a few times without noticing because there's no test for it, partly because you have to wait two minutes to see if it happens. This exposes control of the periodic GC timeout to runtime tests and adds a test that cranks it down to zero and sleeps for a bit to make sure periodic GCs happen. Change-Id: I3ec44e967e99f4eda752f85c329eebd18b87709e Reviewed-on: https://go-review.googlesource.com/13169 Reviewed-by: Rick Hudson <rlh@golang.org> Run-TryBot: Austin Clements <austin@google.com>
This commit is contained in:
parent
829cc349c5
commit
e01be84149
@ -155,3 +155,5 @@ const PtrSize = ptrSize
|
||||
|
||||
var TestingAssertE2I2GC = &testingAssertE2I2GC
|
||||
var TestingAssertE2T2GC = &testingAssertE2T2GC
|
||||
|
||||
var ForceGCPeriod = &forcegcperiod
|
||||
|
@ -199,6 +199,37 @@ func TestHugeGCInfo(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPeriodicGC(t *testing.T) {
|
||||
// Make sure we're not in the middle of a GC.
|
||||
runtime.GC()
|
||||
|
||||
var ms1, ms2 runtime.MemStats
|
||||
runtime.ReadMemStats(&ms1)
|
||||
|
||||
// Make periodic GC run continuously.
|
||||
orig := *runtime.ForceGCPeriod
|
||||
*runtime.ForceGCPeriod = 0
|
||||
|
||||
// Let some periodic GCs happen. In a heavily loaded system,
|
||||
// it's possible these will be delayed, so this is designed to
|
||||
// succeed quickly if things are working, but to give it some
|
||||
// slack if things are slow.
|
||||
var numGCs uint32
|
||||
const want = 2
|
||||
for i := 0; i < 20 && numGCs < want; i++ {
|
||||
time.Sleep(5 * time.Millisecond)
|
||||
|
||||
// Test that periodic GC actually happened.
|
||||
runtime.ReadMemStats(&ms2)
|
||||
numGCs = ms2.NumGC - ms1.NumGC
|
||||
}
|
||||
*runtime.ForceGCPeriod = orig
|
||||
|
||||
if numGCs < want {
|
||||
t.Fatalf("no periodic GC: got %v GCs, want >= 2", numGCs)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSetTypePtr(b *testing.B) {
|
||||
benchSetType(b, new(*byte))
|
||||
}
|
||||
|
@ -2962,10 +2962,14 @@ func checkdead() {
|
||||
throw("all goroutines are asleep - deadlock!")
|
||||
}
|
||||
|
||||
func sysmon() {
|
||||
// If we go two minutes without a garbage collection, force one to run.
|
||||
forcegcperiod := int64(2 * 60 * 1e9)
|
||||
// forcegcperiod is the maximum time in nanoseconds between garbage
|
||||
// collections. If we go this long without a garbage collection, one
|
||||
// is forced to run.
|
||||
//
|
||||
// This is a variable for testing purposes. It normally doesn't change.
|
||||
var forcegcperiod int64 = 2 * 60 * 1e9
|
||||
|
||||
func sysmon() {
|
||||
// If a heap span goes unused for 5 minutes after a garbage collection,
|
||||
// we hand it back to the operating system.
|
||||
scavengelimit := int64(5 * 60 * 1e9)
|
||||
@ -2979,12 +2983,6 @@ func sysmon() {
|
||||
lastscavenge := nanotime()
|
||||
nscavenge := 0
|
||||
|
||||
// Make wake-up period small enough for the sampling to be correct.
|
||||
maxsleep := forcegcperiod / 2
|
||||
if scavengelimit < forcegcperiod {
|
||||
maxsleep = scavengelimit / 2
|
||||
}
|
||||
|
||||
lasttrace := int64(0)
|
||||
idle := 0 // how many cycles in succession we had not wokeup somebody
|
||||
delay := uint32(0)
|
||||
@ -3003,6 +3001,12 @@ func sysmon() {
|
||||
if atomicload(&sched.gcwaiting) != 0 || atomicload(&sched.npidle) == uint32(gomaxprocs) {
|
||||
atomicstore(&sched.sysmonwait, 1)
|
||||
unlock(&sched.lock)
|
||||
// Make wake-up period small enough
|
||||
// for the sampling to be correct.
|
||||
maxsleep := forcegcperiod / 2
|
||||
if scavengelimit < forcegcperiod {
|
||||
maxsleep = scavengelimit / 2
|
||||
}
|
||||
notetsleep(&sched.sysmonnote, maxsleep)
|
||||
lock(&sched.lock)
|
||||
atomicstore(&sched.sysmonwait, 0)
|
||||
|
Loading…
Reference in New Issue
Block a user