github.com/fjballest/golang@v0.0.0-20151209143359-e4c5fe594ca8/src/runtime/malloc_test.go (about) 1 // Copyright 2013 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 "flag" 9 . "runtime" 10 "testing" 11 "time" 12 "unsafe" 13 ) 14 15 func TestMemStats(t *testing.T) { 16 // Test that MemStats has sane values. 17 st := new(MemStats) 18 ReadMemStats(st) 19 20 // Everything except HeapReleased and HeapIdle, because they indeed can be 0. 21 if st.Alloc == 0 || st.TotalAlloc == 0 || st.Sys == 0 || st.Lookups == 0 || 22 st.Mallocs == 0 || st.Frees == 0 || st.HeapAlloc == 0 || st.HeapSys == 0 || 23 st.HeapInuse == 0 || st.HeapObjects == 0 || st.StackInuse == 0 || 24 st.StackSys == 0 || st.MSpanInuse == 0 || st.MSpanSys == 0 || st.MCacheInuse == 0 || 25 st.MCacheSys == 0 || st.BuckHashSys == 0 || st.GCSys == 0 || st.OtherSys == 0 || 26 st.NextGC == 0 || st.NumGC == 0 { 27 t.Fatalf("Zero value: %+v", *st) 28 } 29 30 if st.Alloc > 1e10 || st.TotalAlloc > 1e11 || st.Sys > 1e10 || st.Lookups > 1e10 || 31 st.Mallocs > 1e10 || st.Frees > 1e10 || st.HeapAlloc > 1e10 || st.HeapSys > 1e10 || 32 st.HeapIdle > 1e10 || st.HeapInuse > 1e10 || st.HeapObjects > 1e10 || st.StackInuse > 1e10 || 33 st.StackSys > 1e10 || st.MSpanInuse > 1e10 || st.MSpanSys > 1e10 || st.MCacheInuse > 1e10 || 34 st.MCacheSys > 1e10 || st.BuckHashSys > 1e10 || st.GCSys > 1e10 || st.OtherSys > 1e10 || 35 st.NextGC > 1e10 || st.NumGC > 1e9 || st.PauseTotalNs > 1e11 { 36 t.Fatalf("Insanely high value (overflow?): %+v", *st) 37 } 38 39 if st.Sys != st.HeapSys+st.StackSys+st.MSpanSys+st.MCacheSys+ 40 st.BuckHashSys+st.GCSys+st.OtherSys { 41 t.Fatalf("Bad sys value: %+v", *st) 42 } 43 44 if st.HeapIdle+st.HeapInuse != st.HeapSys { 45 t.Fatalf("HeapIdle(%d) + HeapInuse(%d) should be equal to HeapSys(%d), but isn't.", st.HeapIdle, st.HeapInuse, st.HeapSys) 46 } 47 48 if lpe := st.PauseEnd[int(st.NumGC+255)%len(st.PauseEnd)]; st.LastGC != lpe { 49 t.Fatalf("LastGC(%d) != last PauseEnd(%d)", st.LastGC, lpe) 50 } 51 52 var pauseTotal uint64 53 for _, pause := range st.PauseNs { 54 pauseTotal += pause 55 } 56 if int(st.NumGC) < len(st.PauseNs) { 57 // We have all pauses, so this should be exact. 58 if st.PauseTotalNs != pauseTotal { 59 t.Fatalf("PauseTotalNs(%d) != sum PauseNs(%d)", st.PauseTotalNs, pauseTotal) 60 } 61 } else { 62 if st.PauseTotalNs < pauseTotal { 63 t.Fatalf("PauseTotalNs(%d) < sum PauseNs(%d)", st.PauseTotalNs, pauseTotal) 64 } 65 } 66 } 67 68 func TestStringConcatenationAllocs(t *testing.T) { 69 n := testing.AllocsPerRun(1e3, func() { 70 b := make([]byte, 10) 71 for i := 0; i < 10; i++ { 72 b[i] = byte(i) + '0' 73 } 74 s := "foo" + string(b) 75 if want := "foo0123456789"; s != want { 76 t.Fatalf("want %v, got %v", want, s) 77 } 78 }) 79 // Only string concatenation allocates. 80 if n != 1 { 81 t.Fatalf("want 1 allocation, got %v", n) 82 } 83 } 84 85 func TestTinyAlloc(t *testing.T) { 86 const N = 16 87 var v [N]unsafe.Pointer 88 for i := range v { 89 v[i] = unsafe.Pointer(new(byte)) 90 } 91 92 chunks := make(map[uintptr]bool, N) 93 for _, p := range v { 94 chunks[uintptr(p)&^7] = true 95 } 96 97 if len(chunks) == N { 98 t.Fatal("no bytes allocated within the same 8-byte chunk") 99 } 100 } 101 102 var mallocSink uintptr 103 104 func BenchmarkMalloc8(b *testing.B) { 105 var x uintptr 106 for i := 0; i < b.N; i++ { 107 p := new(int64) 108 x ^= uintptr(unsafe.Pointer(p)) 109 } 110 mallocSink = x 111 } 112 113 func BenchmarkMalloc16(b *testing.B) { 114 var x uintptr 115 for i := 0; i < b.N; i++ { 116 p := new([2]int64) 117 x ^= uintptr(unsafe.Pointer(p)) 118 } 119 mallocSink = x 120 } 121 122 func BenchmarkMallocTypeInfo8(b *testing.B) { 123 var x uintptr 124 for i := 0; i < b.N; i++ { 125 p := new(struct { 126 p [8 / unsafe.Sizeof(uintptr(0))]*int 127 }) 128 x ^= uintptr(unsafe.Pointer(p)) 129 } 130 mallocSink = x 131 } 132 133 func BenchmarkMallocTypeInfo16(b *testing.B) { 134 var x uintptr 135 for i := 0; i < b.N; i++ { 136 p := new(struct { 137 p [16 / unsafe.Sizeof(uintptr(0))]*int 138 }) 139 x ^= uintptr(unsafe.Pointer(p)) 140 } 141 mallocSink = x 142 } 143 144 type LargeStruct struct { 145 x [16][]byte 146 } 147 148 func BenchmarkMallocLargeStruct(b *testing.B) { 149 var x uintptr 150 for i := 0; i < b.N; i++ { 151 p := make([]LargeStruct, 2) 152 x ^= uintptr(unsafe.Pointer(&p[0])) 153 } 154 mallocSink = x 155 } 156 157 var n = flag.Int("n", 1000, "number of goroutines") 158 159 func BenchmarkGoroutineSelect(b *testing.B) { 160 quit := make(chan struct{}) 161 read := func(ch chan struct{}) { 162 for { 163 select { 164 case _, ok := <-ch: 165 if !ok { 166 return 167 } 168 case <-quit: 169 return 170 } 171 } 172 } 173 benchHelper(b, *n, read) 174 } 175 176 func BenchmarkGoroutineBlocking(b *testing.B) { 177 read := func(ch chan struct{}) { 178 for { 179 if _, ok := <-ch; !ok { 180 return 181 } 182 } 183 } 184 benchHelper(b, *n, read) 185 } 186 187 func BenchmarkGoroutineForRange(b *testing.B) { 188 read := func(ch chan struct{}) { 189 for range ch { 190 } 191 } 192 benchHelper(b, *n, read) 193 } 194 195 func benchHelper(b *testing.B, n int, read func(chan struct{})) { 196 m := make([]chan struct{}, n) 197 for i := range m { 198 m[i] = make(chan struct{}, 1) 199 go read(m[i]) 200 } 201 b.StopTimer() 202 b.ResetTimer() 203 GC() 204 205 for i := 0; i < b.N; i++ { 206 for _, ch := range m { 207 if ch != nil { 208 ch <- struct{}{} 209 } 210 } 211 time.Sleep(10 * time.Millisecond) 212 b.StartTimer() 213 GC() 214 b.StopTimer() 215 } 216 217 for _, ch := range m { 218 close(ch) 219 } 220 time.Sleep(10 * time.Millisecond) 221 } 222 223 func BenchmarkGoroutineIdle(b *testing.B) { 224 quit := make(chan struct{}) 225 fn := func() { 226 <-quit 227 } 228 for i := 0; i < *n; i++ { 229 go fn() 230 } 231 232 GC() 233 b.ResetTimer() 234 235 for i := 0; i < b.N; i++ { 236 GC() 237 } 238 239 b.StopTimer() 240 close(quit) 241 time.Sleep(10 * time.Millisecond) 242 }