github.com/shijuvar/go@v0.0.0-20141209052335-e8f13700b70c/src/runtime/gc_test.go (about) 1 // Copyright 2011 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 runtime_test 6 7 import ( 8 "os" 9 "runtime" 10 "runtime/debug" 11 "testing" 12 "time" 13 "unsafe" 14 ) 15 16 func TestGcSys(t *testing.T) { 17 if os.Getenv("GOGC") == "off" { 18 t.Skip("skipping test; GOGC=off in environment") 19 } 20 data := struct{ Short bool }{testing.Short()} 21 got := executeTest(t, testGCSysSource, &data) 22 want := "OK\n" 23 if got != want { 24 t.Fatalf("expected %q, but got %q", want, got) 25 } 26 } 27 28 const testGCSysSource = ` 29 package main 30 31 import ( 32 "fmt" 33 "runtime" 34 ) 35 36 func main() { 37 runtime.GOMAXPROCS(1) 38 memstats := new(runtime.MemStats) 39 runtime.GC() 40 runtime.ReadMemStats(memstats) 41 sys := memstats.Sys 42 43 runtime.MemProfileRate = 0 // disable profiler 44 45 itercount := 1000000 46 {{if .Short}} 47 itercount = 100000 48 {{end}} 49 for i := 0; i < itercount; i++ { 50 workthegc() 51 } 52 53 // Should only be using a few MB. 54 // We allocated 100 MB or (if not short) 1 GB. 55 runtime.ReadMemStats(memstats) 56 if sys > memstats.Sys { 57 sys = 0 58 } else { 59 sys = memstats.Sys - sys 60 } 61 if sys > 16<<20 { 62 fmt.Printf("using too much memory: %d bytes\n", sys) 63 return 64 } 65 fmt.Printf("OK\n") 66 } 67 68 func workthegc() []byte { 69 return make([]byte, 1029) 70 } 71 ` 72 73 func TestGcDeepNesting(t *testing.T) { 74 type T [2][2][2][2][2][2][2][2][2][2]*int 75 a := new(T) 76 77 // Prevent the compiler from applying escape analysis. 78 // This makes sure new(T) is allocated on heap, not on the stack. 79 t.Logf("%p", a) 80 81 a[0][0][0][0][0][0][0][0][0][0] = new(int) 82 *a[0][0][0][0][0][0][0][0][0][0] = 13 83 runtime.GC() 84 if *a[0][0][0][0][0][0][0][0][0][0] != 13 { 85 t.Fail() 86 } 87 } 88 89 func TestGcHashmapIndirection(t *testing.T) { 90 defer debug.SetGCPercent(debug.SetGCPercent(1)) 91 runtime.GC() 92 type T struct { 93 a [256]int 94 } 95 m := make(map[T]T) 96 for i := 0; i < 2000; i++ { 97 var a T 98 a.a[0] = i 99 m[a] = T{} 100 } 101 } 102 103 func TestGcArraySlice(t *testing.T) { 104 type X struct { 105 buf [1]byte 106 nextbuf []byte 107 next *X 108 } 109 var head *X 110 for i := 0; i < 10; i++ { 111 p := &X{} 112 p.buf[0] = 42 113 p.next = head 114 if head != nil { 115 p.nextbuf = head.buf[:] 116 } 117 head = p 118 runtime.GC() 119 } 120 for p := head; p != nil; p = p.next { 121 if p.buf[0] != 42 { 122 t.Fatal("corrupted heap") 123 } 124 } 125 } 126 127 func TestGcRescan(t *testing.T) { 128 type X struct { 129 c chan error 130 nextx *X 131 } 132 type Y struct { 133 X 134 nexty *Y 135 p *int 136 } 137 var head *Y 138 for i := 0; i < 10; i++ { 139 p := &Y{} 140 p.c = make(chan error) 141 if head != nil { 142 p.nextx = &head.X 143 } 144 p.nexty = head 145 p.p = new(int) 146 *p.p = 42 147 head = p 148 runtime.GC() 149 } 150 for p := head; p != nil; p = p.nexty { 151 if *p.p != 42 { 152 t.Fatal("corrupted heap") 153 } 154 } 155 } 156 157 func TestGcLastTime(t *testing.T) { 158 ms := new(runtime.MemStats) 159 t0 := time.Now().UnixNano() 160 runtime.GC() 161 t1 := time.Now().UnixNano() 162 runtime.ReadMemStats(ms) 163 last := int64(ms.LastGC) 164 if t0 > last || last > t1 { 165 t.Fatalf("bad last GC time: got %v, want [%v, %v]", last, t0, t1) 166 } 167 pause := ms.PauseNs[(ms.NumGC+255)%256] 168 // Due to timer granularity, pause can actually be 0 on windows 169 // or on virtualized environments. 170 if pause == 0 { 171 t.Logf("last GC pause was 0") 172 } else if pause > 10e9 { 173 t.Logf("bad last GC pause: got %v, want [0, 10e9]", pause) 174 } 175 } 176 177 var hugeSink interface{} 178 179 func TestHugeGCInfo(t *testing.T) { 180 // The test ensures that compiler can chew these huge types even on weakest machines. 181 // The types are not allocated at runtime. 182 if hugeSink != nil { 183 // 400MB on 32 bots, 4TB on 64-bits. 184 const n = (400 << 20) + (unsafe.Sizeof(uintptr(0))-4)<<40 185 hugeSink = new([n]*byte) 186 hugeSink = new([n]uintptr) 187 hugeSink = new(struct { 188 x float64 189 y [n]*byte 190 z []string 191 }) 192 hugeSink = new(struct { 193 x float64 194 y [n]uintptr 195 z []string 196 }) 197 } 198 } 199 200 func BenchmarkSetTypeNoPtr1(b *testing.B) { 201 type NoPtr1 struct { 202 p uintptr 203 } 204 var p *NoPtr1 205 for i := 0; i < b.N; i++ { 206 p = &NoPtr1{} 207 } 208 _ = p 209 } 210 func BenchmarkSetTypeNoPtr2(b *testing.B) { 211 type NoPtr2 struct { 212 p, q uintptr 213 } 214 var p *NoPtr2 215 for i := 0; i < b.N; i++ { 216 p = &NoPtr2{} 217 } 218 _ = p 219 } 220 func BenchmarkSetTypePtr1(b *testing.B) { 221 type Ptr1 struct { 222 p *byte 223 } 224 var p *Ptr1 225 for i := 0; i < b.N; i++ { 226 p = &Ptr1{} 227 } 228 _ = p 229 } 230 func BenchmarkSetTypePtr2(b *testing.B) { 231 type Ptr2 struct { 232 p, q *byte 233 } 234 var p *Ptr2 235 for i := 0; i < b.N; i++ { 236 p = &Ptr2{} 237 } 238 _ = p 239 } 240 241 func BenchmarkAllocation(b *testing.B) { 242 type T struct { 243 x, y *byte 244 } 245 ngo := runtime.GOMAXPROCS(0) 246 work := make(chan bool, b.N+ngo) 247 result := make(chan *T) 248 for i := 0; i < b.N; i++ { 249 work <- true 250 } 251 for i := 0; i < ngo; i++ { 252 work <- false 253 } 254 for i := 0; i < ngo; i++ { 255 go func() { 256 var x *T 257 for <-work { 258 for i := 0; i < 1000; i++ { 259 x = &T{} 260 } 261 } 262 result <- x 263 }() 264 } 265 for i := 0; i < ngo; i++ { 266 <-result 267 } 268 } 269 270 func TestPrintGC(t *testing.T) { 271 if testing.Short() { 272 t.Skip("Skipping in short mode") 273 } 274 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2)) 275 done := make(chan bool) 276 go func() { 277 for { 278 select { 279 case <-done: 280 return 281 default: 282 runtime.GC() 283 } 284 } 285 }() 286 for i := 0; i < 1e4; i++ { 287 func() { 288 defer print("") 289 }() 290 } 291 close(done) 292 }