github.com/comwrg/go/src@v0.0.0-20220319063731-c238d0440370/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 "fmt" 10 "github.com/comwrg/go/src/internal/race" 11 "github.com/comwrg/go/src/internal/testenv" 12 "os" 13 "os/exec" 14 "reflect" 15 "runtime" 16 . "runtime" 17 "strings" 18 "sync/atomic" 19 "testing" 20 "time" 21 "unsafe" 22 ) 23 24 var testMemStatsCount int 25 26 func TestMemStats(t *testing.T) { 27 testMemStatsCount++ 28 29 // Make sure there's at least one forced GC. 30 GC() 31 32 // Test that MemStats has sane values. 33 st := new(MemStats) 34 ReadMemStats(st) 35 36 nz := func(x interface{}) error { 37 if x != reflect.Zero(reflect.TypeOf(x)).Interface() { 38 return nil 39 } 40 return fmt.Errorf("zero value") 41 } 42 le := func(thresh float64) func(interface{}) error { 43 return func(x interface{}) error { 44 // These sanity tests aren't necessarily valid 45 // with high -test.count values, so only run 46 // them once. 47 if testMemStatsCount > 1 { 48 return nil 49 } 50 51 if reflect.ValueOf(x).Convert(reflect.TypeOf(thresh)).Float() < thresh { 52 return nil 53 } 54 return fmt.Errorf("insanely high value (overflow?); want <= %v", thresh) 55 } 56 } 57 eq := func(x interface{}) func(interface{}) error { 58 return func(y interface{}) error { 59 if x == y { 60 return nil 61 } 62 return fmt.Errorf("want %v", x) 63 } 64 } 65 // Of the uint fields, HeapReleased, HeapIdle can be 0. 66 // PauseTotalNs can be 0 if timer resolution is poor. 67 fields := map[string][]func(interface{}) error{ 68 "Alloc": {nz, le(1e10)}, "TotalAlloc": {nz, le(1e11)}, "Sys": {nz, le(1e10)}, 69 "Lookups": {eq(uint64(0))}, "Mallocs": {nz, le(1e10)}, "Frees": {nz, le(1e10)}, 70 "HeapAlloc": {nz, le(1e10)}, "HeapSys": {nz, le(1e10)}, "HeapIdle": {le(1e10)}, 71 "HeapInuse": {nz, le(1e10)}, "HeapReleased": {le(1e10)}, "HeapObjects": {nz, le(1e10)}, 72 "StackInuse": {nz, le(1e10)}, "StackSys": {nz, le(1e10)}, 73 "MSpanInuse": {nz, le(1e10)}, "MSpanSys": {nz, le(1e10)}, 74 "MCacheInuse": {nz, le(1e10)}, "MCacheSys": {nz, le(1e10)}, 75 "BuckHashSys": {nz, le(1e10)}, "GCSys": {nz, le(1e10)}, "OtherSys": {nz, le(1e10)}, 76 "NextGC": {nz, le(1e10)}, "LastGC": {nz}, 77 "PauseTotalNs": {le(1e11)}, "PauseNs": nil, "PauseEnd": nil, 78 "NumGC": {nz, le(1e9)}, "NumForcedGC": {nz, le(1e9)}, 79 "GCCPUFraction": {le(0.99)}, "EnableGC": {eq(true)}, "DebugGC": {eq(false)}, 80 "BySize": nil, 81 } 82 83 rst := reflect.ValueOf(st).Elem() 84 for i := 0; i < rst.Type().NumField(); i++ { 85 name, val := rst.Type().Field(i).Name, rst.Field(i).Interface() 86 checks, ok := fields[name] 87 if !ok { 88 t.Errorf("unknown MemStats field %s", name) 89 continue 90 } 91 for _, check := range checks { 92 if err := check(val); err != nil { 93 t.Errorf("%s = %v: %s", name, val, err) 94 } 95 } 96 } 97 98 if st.Sys != st.HeapSys+st.StackSys+st.MSpanSys+st.MCacheSys+ 99 st.BuckHashSys+st.GCSys+st.OtherSys { 100 t.Fatalf("Bad sys value: %+v", *st) 101 } 102 103 if st.HeapIdle+st.HeapInuse != st.HeapSys { 104 t.Fatalf("HeapIdle(%d) + HeapInuse(%d) should be equal to HeapSys(%d), but isn't.", st.HeapIdle, st.HeapInuse, st.HeapSys) 105 } 106 107 if lpe := st.PauseEnd[int(st.NumGC+255)%len(st.PauseEnd)]; st.LastGC != lpe { 108 t.Fatalf("LastGC(%d) != last PauseEnd(%d)", st.LastGC, lpe) 109 } 110 111 var pauseTotal uint64 112 for _, pause := range st.PauseNs { 113 pauseTotal += pause 114 } 115 if int(st.NumGC) < len(st.PauseNs) { 116 // We have all pauses, so this should be exact. 117 if st.PauseTotalNs != pauseTotal { 118 t.Fatalf("PauseTotalNs(%d) != sum PauseNs(%d)", st.PauseTotalNs, pauseTotal) 119 } 120 for i := int(st.NumGC); i < len(st.PauseNs); i++ { 121 if st.PauseNs[i] != 0 { 122 t.Fatalf("Non-zero PauseNs[%d]: %+v", i, st) 123 } 124 if st.PauseEnd[i] != 0 { 125 t.Fatalf("Non-zero PauseEnd[%d]: %+v", i, st) 126 } 127 } 128 } else { 129 if st.PauseTotalNs < pauseTotal { 130 t.Fatalf("PauseTotalNs(%d) < sum PauseNs(%d)", st.PauseTotalNs, pauseTotal) 131 } 132 } 133 134 if st.NumForcedGC > st.NumGC { 135 t.Fatalf("NumForcedGC(%d) > NumGC(%d)", st.NumForcedGC, st.NumGC) 136 } 137 } 138 139 func TestStringConcatenationAllocs(t *testing.T) { 140 n := testing.AllocsPerRun(1e3, func() { 141 b := make([]byte, 10) 142 for i := 0; i < 10; i++ { 143 b[i] = byte(i) + '0' 144 } 145 s := "foo" + string(b) 146 if want := "foo0123456789"; s != want { 147 t.Fatalf("want %v, got %v", want, s) 148 } 149 }) 150 // Only string concatenation allocates. 151 if n != 1 { 152 t.Fatalf("want 1 allocation, got %v", n) 153 } 154 } 155 156 func TestTinyAlloc(t *testing.T) { 157 if runtime.Raceenabled { 158 t.Skip("tinyalloc suppressed when running in race mode") 159 } 160 const N = 16 161 var v [N]unsafe.Pointer 162 for i := range v { 163 v[i] = unsafe.Pointer(new(byte)) 164 } 165 166 chunks := make(map[uintptr]bool, N) 167 for _, p := range v { 168 chunks[uintptr(p)&^7] = true 169 } 170 171 if len(chunks) == N { 172 t.Fatal("no bytes allocated within the same 8-byte chunk") 173 } 174 } 175 176 var ( 177 tinyByteSink *byte 178 tinyUint32Sink *uint32 179 tinyObj12Sink *obj12 180 ) 181 182 type obj12 struct { 183 a uint64 184 b uint32 185 } 186 187 func TestTinyAllocIssue37262(t *testing.T) { 188 if runtime.Raceenabled { 189 t.Skip("tinyalloc suppressed when running in race mode") 190 } 191 // Try to cause an alignment access fault 192 // by atomically accessing the first 64-bit 193 // value of a tiny-allocated object. 194 // See issue 37262 for details. 195 196 // GC twice, once to reach a stable heap state 197 // and again to make sure we finish the sweep phase. 198 runtime.GC() 199 runtime.GC() 200 201 // Make 1-byte allocations until we get a fresh tiny slot. 202 aligned := false 203 for i := 0; i < 16; i++ { 204 tinyByteSink = new(byte) 205 if uintptr(unsafe.Pointer(tinyByteSink))&0xf == 0xf { 206 aligned = true 207 break 208 } 209 } 210 if !aligned { 211 t.Fatal("unable to get a fresh tiny slot") 212 } 213 214 // Create a 4-byte object so that the current 215 // tiny slot is partially filled. 216 tinyUint32Sink = new(uint32) 217 218 // Create a 12-byte object, which fits into the 219 // tiny slot. If it actually gets place there, 220 // then the field "a" will be improperly aligned 221 // for atomic access on 32-bit architectures. 222 // This won't be true if issue 36606 gets resolved. 223 tinyObj12Sink = new(obj12) 224 225 // Try to atomically access "x.a". 226 atomic.StoreUint64(&tinyObj12Sink.a, 10) 227 228 // Clear the sinks. 229 tinyByteSink = nil 230 tinyUint32Sink = nil 231 tinyObj12Sink = nil 232 } 233 234 func TestPageCacheLeak(t *testing.T) { 235 defer GOMAXPROCS(GOMAXPROCS(1)) 236 leaked := PageCachePagesLeaked() 237 if leaked != 0 { 238 t.Fatalf("found %d leaked pages in page caches", leaked) 239 } 240 } 241 242 func TestPhysicalMemoryUtilization(t *testing.T) { 243 got := runTestProg(t, "testprog", "GCPhys") 244 want := "OK\n" 245 if got != want { 246 t.Fatalf("expected %q, but got %q", want, got) 247 } 248 } 249 250 func TestScavengedBitsCleared(t *testing.T) { 251 var mismatches [128]BitsMismatch 252 if n, ok := CheckScavengedBitsCleared(mismatches[:]); !ok { 253 t.Errorf("uncleared scavenged bits") 254 for _, m := range mismatches[:n] { 255 t.Logf("\t@ address 0x%x", m.Base) 256 t.Logf("\t| got: %064b", m.Got) 257 t.Logf("\t| want: %064b", m.Want) 258 } 259 t.FailNow() 260 } 261 } 262 263 type acLink struct { 264 x [1 << 20]byte 265 } 266 267 var arenaCollisionSink []*acLink 268 269 func TestArenaCollision(t *testing.T) { 270 testenv.MustHaveExec(t) 271 272 // Test that mheap.sysAlloc handles collisions with other 273 // memory mappings. 274 if os.Getenv("TEST_ARENA_COLLISION") != "1" { 275 cmd := testenv.CleanCmdEnv(exec.Command(os.Args[0], "-test.run=TestArenaCollision", "-test.v")) 276 cmd.Env = append(cmd.Env, "TEST_ARENA_COLLISION=1") 277 out, err := cmd.CombinedOutput() 278 if race.Enabled { 279 // This test runs the runtime out of hint 280 // addresses, so it will start mapping the 281 // heap wherever it can. The race detector 282 // doesn't support this, so look for the 283 // expected failure. 284 if want := "too many address space collisions"; !strings.Contains(string(out), want) { 285 t.Fatalf("want %q, got:\n%s", want, string(out)) 286 } 287 } else if !strings.Contains(string(out), "PASS\n") || err != nil { 288 t.Fatalf("%s\n(exit status %v)", string(out), err) 289 } 290 return 291 } 292 disallowed := [][2]uintptr{} 293 // Drop all but the next 3 hints. 64-bit has a lot of hints, 294 // so it would take a lot of memory to go through all of them. 295 KeepNArenaHints(3) 296 // Consume these 3 hints and force the runtime to find some 297 // fallback hints. 298 for i := 0; i < 5; i++ { 299 // Reserve memory at the next hint so it can't be used 300 // for the heap. 301 start, end := MapNextArenaHint() 302 disallowed = append(disallowed, [2]uintptr{start, end}) 303 // Allocate until the runtime tries to use the hint we 304 // just mapped over. 305 hint := GetNextArenaHint() 306 for GetNextArenaHint() == hint { 307 ac := new(acLink) 308 arenaCollisionSink = append(arenaCollisionSink, ac) 309 // The allocation must not have fallen into 310 // one of the reserved regions. 311 p := uintptr(unsafe.Pointer(ac)) 312 for _, d := range disallowed { 313 if d[0] <= p && p < d[1] { 314 t.Fatalf("allocation %#x in reserved region [%#x, %#x)", p, d[0], d[1]) 315 } 316 } 317 } 318 } 319 } 320 321 var mallocSink uintptr 322 323 func BenchmarkMalloc8(b *testing.B) { 324 var x uintptr 325 for i := 0; i < b.N; i++ { 326 p := new(int64) 327 x ^= uintptr(unsafe.Pointer(p)) 328 } 329 mallocSink = x 330 } 331 332 func BenchmarkMalloc16(b *testing.B) { 333 var x uintptr 334 for i := 0; i < b.N; i++ { 335 p := new([2]int64) 336 x ^= uintptr(unsafe.Pointer(p)) 337 } 338 mallocSink = x 339 } 340 341 func BenchmarkMallocTypeInfo8(b *testing.B) { 342 var x uintptr 343 for i := 0; i < b.N; i++ { 344 p := new(struct { 345 p [8 / unsafe.Sizeof(uintptr(0))]*int 346 }) 347 x ^= uintptr(unsafe.Pointer(p)) 348 } 349 mallocSink = x 350 } 351 352 func BenchmarkMallocTypeInfo16(b *testing.B) { 353 var x uintptr 354 for i := 0; i < b.N; i++ { 355 p := new(struct { 356 p [16 / unsafe.Sizeof(uintptr(0))]*int 357 }) 358 x ^= uintptr(unsafe.Pointer(p)) 359 } 360 mallocSink = x 361 } 362 363 type LargeStruct struct { 364 x [16][]byte 365 } 366 367 func BenchmarkMallocLargeStruct(b *testing.B) { 368 var x uintptr 369 for i := 0; i < b.N; i++ { 370 p := make([]LargeStruct, 2) 371 x ^= uintptr(unsafe.Pointer(&p[0])) 372 } 373 mallocSink = x 374 } 375 376 var n = flag.Int("n", 1000, "number of goroutines") 377 378 func BenchmarkGoroutineSelect(b *testing.B) { 379 quit := make(chan struct{}) 380 read := func(ch chan struct{}) { 381 for { 382 select { 383 case _, ok := <-ch: 384 if !ok { 385 return 386 } 387 case <-quit: 388 return 389 } 390 } 391 } 392 benchHelper(b, *n, read) 393 } 394 395 func BenchmarkGoroutineBlocking(b *testing.B) { 396 read := func(ch chan struct{}) { 397 for { 398 if _, ok := <-ch; !ok { 399 return 400 } 401 } 402 } 403 benchHelper(b, *n, read) 404 } 405 406 func BenchmarkGoroutineForRange(b *testing.B) { 407 read := func(ch chan struct{}) { 408 for range ch { 409 } 410 } 411 benchHelper(b, *n, read) 412 } 413 414 func benchHelper(b *testing.B, n int, read func(chan struct{})) { 415 m := make([]chan struct{}, n) 416 for i := range m { 417 m[i] = make(chan struct{}, 1) 418 go read(m[i]) 419 } 420 b.StopTimer() 421 b.ResetTimer() 422 GC() 423 424 for i := 0; i < b.N; i++ { 425 for _, ch := range m { 426 if ch != nil { 427 ch <- struct{}{} 428 } 429 } 430 time.Sleep(10 * time.Millisecond) 431 b.StartTimer() 432 GC() 433 b.StopTimer() 434 } 435 436 for _, ch := range m { 437 close(ch) 438 } 439 time.Sleep(10 * time.Millisecond) 440 } 441 442 func BenchmarkGoroutineIdle(b *testing.B) { 443 quit := make(chan struct{}) 444 fn := func() { 445 <-quit 446 } 447 for i := 0; i < *n; i++ { 448 go fn() 449 } 450 451 GC() 452 b.ResetTimer() 453 454 for i := 0; i < b.N; i++ { 455 GC() 456 } 457 458 b.StopTimer() 459 close(quit) 460 time.Sleep(10 * time.Millisecond) 461 }