// Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package main import ( "fmt" "os" "runtime" "runtime/debug" "sync/atomic" "time" ) func init() { register("GCFairness", GCFairness) register("GCFairness2", GCFairness2) register("GCSys", GCSys) } func GCSys() { runtime.GOMAXPROCS(1) memstats := new(runtime.MemStats) runtime.GC() runtime.ReadMemStats(memstats) sys := memstats.Sys runtime.MemProfileRate = 0 // disable profiler itercount := 100000 for i := 0; i < itercount; i++ { workthegc() } // Should only be using a few MB. // We allocated 100 MB or (if not short) 1 GB. runtime.ReadMemStats(memstats) if sys > memstats.Sys { sys = 0 } else { sys = memstats.Sys - sys } if sys > 16<<20 { fmt.Printf("using too much memory: %d bytes\n", sys) return } fmt.Printf("OK\n") } func workthegc() []byte { return make([]byte, 1029) } func GCFairness() { runtime.GOMAXPROCS(1) f, err := os.Open("/dev/null") if os.IsNotExist(err) { // This test tests what it is intended to test only if writes are fast. // If there is no /dev/null, we just don't execute the test. fmt.Println("OK") return } if err != nil { fmt.Println(err) os.Exit(1) } for i := 0; i < 2; i++ { go func() { for { f.Write([]byte(".")) } }() } time.Sleep(10 * time.Millisecond) fmt.Println("OK") } func GCFairness2() { // Make sure user code can't exploit the GC's high priority // scheduling to make scheduling of user code unfair. See // issue #15706. runtime.GOMAXPROCS(1) debug.SetGCPercent(1) var count [3]int64 var sink [3]interface{} for i := range count { go func(i int) { for { sink[i] = make([]byte, 1024) atomic.AddInt64(&count[i], 1) } }(i) } // Note: If the unfairness is really bad, it may not even get // past the sleep. // // If the scheduling rules change, this may not be enough time // to let all goroutines run, but for now we cycle through // them rapidly. // // OpenBSD's scheduler makes every usleep() take at least // 20ms, so we need a long time to ensure all goroutines have // run. If they haven't run after 30ms, give it another 1000ms // and check again. time.Sleep(30 * time.Millisecond) var fail bool for i := range count { if atomic.LoadInt64(&count[i]) == 0 { fail = true } } if fail { time.Sleep(1 * time.Second) for i := range count { if atomic.LoadInt64(&count[i]) == 0 { fmt.Printf("goroutine %d did not run\n", i) return } } } fmt.Println("OK") }