github.com/ltltlt/go-source-code@v0.0.0-20190830023027-95be009773aa/runtime/testdata/testprog/gc.go (about) 1 // Copyright 2015 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "fmt" 9 "os" 10 "runtime" 11 "runtime/debug" 12 "sync/atomic" 13 "time" 14 ) 15 16 func init() { 17 register("GCFairness", GCFairness) 18 register("GCFairness2", GCFairness2) 19 register("GCSys", GCSys) 20 } 21 22 func GCSys() { 23 runtime.GOMAXPROCS(1) 24 memstats := new(runtime.MemStats) 25 runtime.GC() 26 runtime.ReadMemStats(memstats) 27 sys := memstats.Sys 28 29 runtime.MemProfileRate = 0 // disable profiler 30 31 itercount := 100000 32 for i := 0; i < itercount; i++ { 33 workthegc() 34 } 35 36 // Should only be using a few MB. 37 // We allocated 100 MB or (if not short) 1 GB. 38 runtime.ReadMemStats(memstats) 39 if sys > memstats.Sys { 40 sys = 0 41 } else { 42 sys = memstats.Sys - sys 43 } 44 if sys > 16<<20 { 45 fmt.Printf("using too much memory: %d bytes\n", sys) 46 return 47 } 48 fmt.Printf("OK\n") 49 } 50 51 func workthegc() []byte { 52 return make([]byte, 1029) 53 } 54 55 func GCFairness() { 56 runtime.GOMAXPROCS(1) 57 f, err := os.Open("/dev/null") 58 if os.IsNotExist(err) { 59 // This test tests what it is intended to test only if writes are fast. 60 // If there is no /dev/null, we just don't execute the test. 61 fmt.Println("OK") 62 return 63 } 64 if err != nil { 65 fmt.Println(err) 66 os.Exit(1) 67 } 68 for i := 0; i < 2; i++ { 69 go func() { 70 for { 71 f.Write([]byte(".")) 72 } 73 }() 74 } 75 time.Sleep(10 * time.Millisecond) 76 fmt.Println("OK") 77 } 78 79 func GCFairness2() { 80 // Make sure user code can't exploit the GC's high priority 81 // scheduling to make scheduling of user code unfair. See 82 // issue #15706. 83 runtime.GOMAXPROCS(1) 84 debug.SetGCPercent(1) 85 var count [3]int64 86 var sink [3]interface{} 87 for i := range count { 88 go func(i int) { 89 for { 90 sink[i] = make([]byte, 1024) 91 atomic.AddInt64(&count[i], 1) 92 } 93 }(i) 94 } 95 // Note: If the unfairness is really bad, it may not even get 96 // past the sleep. 97 // 98 // If the scheduling rules change, this may not be enough time 99 // to let all goroutines run, but for now we cycle through 100 // them rapidly. 101 // 102 // OpenBSD's scheduler makes every usleep() take at least 103 // 20ms, so we need a long time to ensure all goroutines have 104 // run. If they haven't run after 30ms, give it another 1000ms 105 // and check again. 106 time.Sleep(30 * time.Millisecond) 107 var fail bool 108 for i := range count { 109 if atomic.LoadInt64(&count[i]) == 0 { 110 fail = true 111 } 112 } 113 if fail { 114 time.Sleep(1 * time.Second) 115 for i := range count { 116 if atomic.LoadInt64(&count[i]) == 0 { 117 fmt.Printf("goroutine %d did not run\n", i) 118 return 119 } 120 } 121 } 122 fmt.Println("OK") 123 }