github.com/panjjo/go@v0.0.0-20161104043856-d62b31386338/src/runtime/map_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 "fmt" 9 "math" 10 "reflect" 11 "runtime" 12 "sort" 13 "strings" 14 "sync" 15 "testing" 16 ) 17 18 // negative zero is a good test because: 19 // 1) 0 and -0 are equal, yet have distinct representations. 20 // 2) 0 is represented as all zeros, -0 isn't. 21 // I'm not sure the language spec actually requires this behavior, 22 // but it's what the current map implementation does. 23 func TestNegativeZero(t *testing.T) { 24 m := make(map[float64]bool, 0) 25 26 m[+0.0] = true 27 m[math.Copysign(0.0, -1.0)] = true // should overwrite +0 entry 28 29 if len(m) != 1 { 30 t.Error("length wrong") 31 } 32 33 for k := range m { 34 if math.Copysign(1.0, k) > 0 { 35 t.Error("wrong sign") 36 } 37 } 38 39 m = make(map[float64]bool, 0) 40 m[math.Copysign(0.0, -1.0)] = true 41 m[+0.0] = true // should overwrite -0.0 entry 42 43 if len(m) != 1 { 44 t.Error("length wrong") 45 } 46 47 for k := range m { 48 if math.Copysign(1.0, k) < 0 { 49 t.Error("wrong sign") 50 } 51 } 52 } 53 54 // nan is a good test because nan != nan, and nan has 55 // a randomized hash value. 56 func TestNan(t *testing.T) { 57 m := make(map[float64]int, 0) 58 nan := math.NaN() 59 m[nan] = 1 60 m[nan] = 2 61 m[nan] = 4 62 if len(m) != 3 { 63 t.Error("length wrong") 64 } 65 s := 0 66 for k, v := range m { 67 if k == k { 68 t.Error("nan disappeared") 69 } 70 if (v & (v - 1)) != 0 { 71 t.Error("value wrong") 72 } 73 s |= v 74 } 75 if s != 7 { 76 t.Error("values wrong") 77 } 78 } 79 80 // Maps aren't actually copied on assignment. 81 func TestAlias(t *testing.T) { 82 m := make(map[int]int, 0) 83 m[0] = 5 84 n := m 85 n[0] = 6 86 if m[0] != 6 { 87 t.Error("alias didn't work") 88 } 89 } 90 91 func TestGrowWithNaN(t *testing.T) { 92 m := make(map[float64]int, 4) 93 nan := math.NaN() 94 m[nan] = 1 95 m[nan] = 2 96 m[nan] = 4 97 cnt := 0 98 s := 0 99 growflag := true 100 for k, v := range m { 101 if growflag { 102 // force a hashtable resize 103 for i := 0; i < 100; i++ { 104 m[float64(i)] = i 105 } 106 growflag = false 107 } 108 if k != k { 109 cnt++ 110 s |= v 111 } 112 } 113 if cnt != 3 { 114 t.Error("NaN keys lost during grow") 115 } 116 if s != 7 { 117 t.Error("NaN values lost during grow") 118 } 119 } 120 121 type FloatInt struct { 122 x float64 123 y int 124 } 125 126 func TestGrowWithNegativeZero(t *testing.T) { 127 negzero := math.Copysign(0.0, -1.0) 128 m := make(map[FloatInt]int, 4) 129 m[FloatInt{0.0, 0}] = 1 130 m[FloatInt{0.0, 1}] = 2 131 m[FloatInt{0.0, 2}] = 4 132 m[FloatInt{0.0, 3}] = 8 133 growflag := true 134 s := 0 135 cnt := 0 136 negcnt := 0 137 // The first iteration should return the +0 key. 138 // The subsequent iterations should return the -0 key. 139 // I'm not really sure this is required by the spec, 140 // but it makes sense. 141 // TODO: are we allowed to get the first entry returned again??? 142 for k, v := range m { 143 if v == 0 { 144 continue 145 } // ignore entries added to grow table 146 cnt++ 147 if math.Copysign(1.0, k.x) < 0 { 148 if v&16 == 0 { 149 t.Error("key/value not updated together 1") 150 } 151 negcnt++ 152 s |= v & 15 153 } else { 154 if v&16 == 16 { 155 t.Error("key/value not updated together 2", k, v) 156 } 157 s |= v 158 } 159 if growflag { 160 // force a hashtable resize 161 for i := 0; i < 100; i++ { 162 m[FloatInt{3.0, i}] = 0 163 } 164 // then change all the entries 165 // to negative zero 166 m[FloatInt{negzero, 0}] = 1 | 16 167 m[FloatInt{negzero, 1}] = 2 | 16 168 m[FloatInt{negzero, 2}] = 4 | 16 169 m[FloatInt{negzero, 3}] = 8 | 16 170 growflag = false 171 } 172 } 173 if s != 15 { 174 t.Error("entry missing", s) 175 } 176 if cnt != 4 { 177 t.Error("wrong number of entries returned by iterator", cnt) 178 } 179 if negcnt != 3 { 180 t.Error("update to negzero missed by iteration", negcnt) 181 } 182 } 183 184 func TestIterGrowAndDelete(t *testing.T) { 185 m := make(map[int]int, 4) 186 for i := 0; i < 100; i++ { 187 m[i] = i 188 } 189 growflag := true 190 for k := range m { 191 if growflag { 192 // grow the table 193 for i := 100; i < 1000; i++ { 194 m[i] = i 195 } 196 // delete all odd keys 197 for i := 1; i < 1000; i += 2 { 198 delete(m, i) 199 } 200 growflag = false 201 } else { 202 if k&1 == 1 { 203 t.Error("odd value returned") 204 } 205 } 206 } 207 } 208 209 // make sure old bucket arrays don't get GCd while 210 // an iterator is still using them. 211 func TestIterGrowWithGC(t *testing.T) { 212 m := make(map[int]int, 4) 213 for i := 0; i < 16; i++ { 214 m[i] = i 215 } 216 growflag := true 217 bitmask := 0 218 for k := range m { 219 if k < 16 { 220 bitmask |= 1 << uint(k) 221 } 222 if growflag { 223 // grow the table 224 for i := 100; i < 1000; i++ { 225 m[i] = i 226 } 227 // trigger a gc 228 runtime.GC() 229 growflag = false 230 } 231 } 232 if bitmask != 1<<16-1 { 233 t.Error("missing key", bitmask) 234 } 235 } 236 237 func testConcurrentReadsAfterGrowth(t *testing.T, useReflect bool) { 238 if runtime.GOMAXPROCS(-1) == 1 { 239 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(16)) 240 } 241 numLoop := 10 242 numGrowStep := 250 243 numReader := 16 244 if testing.Short() { 245 numLoop, numGrowStep = 2, 500 246 } 247 for i := 0; i < numLoop; i++ { 248 m := make(map[int]int, 0) 249 for gs := 0; gs < numGrowStep; gs++ { 250 m[gs] = gs 251 var wg sync.WaitGroup 252 wg.Add(numReader * 2) 253 for nr := 0; nr < numReader; nr++ { 254 go func() { 255 defer wg.Done() 256 for range m { 257 } 258 }() 259 go func() { 260 defer wg.Done() 261 for key := 0; key < gs; key++ { 262 _ = m[key] 263 } 264 }() 265 if useReflect { 266 wg.Add(1) 267 go func() { 268 defer wg.Done() 269 mv := reflect.ValueOf(m) 270 keys := mv.MapKeys() 271 for _, k := range keys { 272 mv.MapIndex(k) 273 } 274 }() 275 } 276 } 277 wg.Wait() 278 } 279 } 280 } 281 282 func TestConcurrentReadsAfterGrowth(t *testing.T) { 283 testConcurrentReadsAfterGrowth(t, false) 284 } 285 286 func TestConcurrentReadsAfterGrowthReflect(t *testing.T) { 287 testConcurrentReadsAfterGrowth(t, true) 288 } 289 290 func TestBigItems(t *testing.T) { 291 var key [256]string 292 for i := 0; i < 256; i++ { 293 key[i] = "foo" 294 } 295 m := make(map[[256]string][256]string, 4) 296 for i := 0; i < 100; i++ { 297 key[37] = fmt.Sprintf("string%02d", i) 298 m[key] = key 299 } 300 var keys [100]string 301 var values [100]string 302 i := 0 303 for k, v := range m { 304 keys[i] = k[37] 305 values[i] = v[37] 306 i++ 307 } 308 sort.Strings(keys[:]) 309 sort.Strings(values[:]) 310 for i := 0; i < 100; i++ { 311 if keys[i] != fmt.Sprintf("string%02d", i) { 312 t.Errorf("#%d: missing key: %v", i, keys[i]) 313 } 314 if values[i] != fmt.Sprintf("string%02d", i) { 315 t.Errorf("#%d: missing value: %v", i, values[i]) 316 } 317 } 318 } 319 320 func TestMapHugeZero(t *testing.T) { 321 type T [4000]byte 322 m := map[int]T{} 323 x := m[0] 324 if x != (T{}) { 325 t.Errorf("map value not zero") 326 } 327 y, ok := m[0] 328 if ok { 329 t.Errorf("map value should be missing") 330 } 331 if y != (T{}) { 332 t.Errorf("map value not zero") 333 } 334 } 335 336 type empty struct { 337 } 338 339 func TestEmptyKeyAndValue(t *testing.T) { 340 a := make(map[int]empty, 4) 341 b := make(map[empty]int, 4) 342 c := make(map[empty]empty, 4) 343 a[0] = empty{} 344 b[empty{}] = 0 345 b[empty{}] = 1 346 c[empty{}] = empty{} 347 348 if len(a) != 1 { 349 t.Errorf("empty value insert problem") 350 } 351 if b[empty{}] != 1 { 352 t.Errorf("empty key returned wrong value") 353 } 354 } 355 356 // Tests a map with a single bucket, with same-lengthed short keys 357 // ("quick keys") as well as long keys. 358 func TestSingleBucketMapStringKeys_DupLen(t *testing.T) { 359 testMapLookups(t, map[string]string{ 360 "x": "x1val", 361 "xx": "x2val", 362 "foo": "fooval", 363 "bar": "barval", // same key length as "foo" 364 "xxxx": "x4val", 365 strings.Repeat("x", 128): "longval1", 366 strings.Repeat("y", 128): "longval2", 367 }) 368 } 369 370 // Tests a map with a single bucket, with all keys having different lengths. 371 func TestSingleBucketMapStringKeys_NoDupLen(t *testing.T) { 372 testMapLookups(t, map[string]string{ 373 "x": "x1val", 374 "xx": "x2val", 375 "foo": "fooval", 376 "xxxx": "x4val", 377 "xxxxx": "x5val", 378 "xxxxxx": "x6val", 379 strings.Repeat("x", 128): "longval", 380 }) 381 } 382 383 func testMapLookups(t *testing.T, m map[string]string) { 384 for k, v := range m { 385 if m[k] != v { 386 t.Fatalf("m[%q] = %q; want %q", k, m[k], v) 387 } 388 } 389 } 390 391 // Tests whether the iterator returns the right elements when 392 // started in the middle of a grow, when the keys are NaNs. 393 func TestMapNanGrowIterator(t *testing.T) { 394 m := make(map[float64]int) 395 nan := math.NaN() 396 const nBuckets = 16 397 // To fill nBuckets buckets takes LOAD * nBuckets keys. 398 nKeys := int(nBuckets * *runtime.HashLoad) 399 400 // Get map to full point with nan keys. 401 for i := 0; i < nKeys; i++ { 402 m[nan] = i 403 } 404 // Trigger grow 405 m[1.0] = 1 406 delete(m, 1.0) 407 408 // Run iterator 409 found := make(map[int]struct{}) 410 for _, v := range m { 411 if v != -1 { 412 if _, repeat := found[v]; repeat { 413 t.Fatalf("repeat of value %d", v) 414 } 415 found[v] = struct{}{} 416 } 417 if len(found) == nKeys/2 { 418 // Halfway through iteration, finish grow. 419 for i := 0; i < nBuckets; i++ { 420 delete(m, 1.0) 421 } 422 } 423 } 424 if len(found) != nKeys { 425 t.Fatalf("missing value") 426 } 427 } 428 429 func TestMapIterOrder(t *testing.T) { 430 for _, n := range [...]int{3, 7, 9, 15} { 431 for i := 0; i < 1000; i++ { 432 // Make m be {0: true, 1: true, ..., n-1: true}. 433 m := make(map[int]bool) 434 for i := 0; i < n; i++ { 435 m[i] = true 436 } 437 // Check that iterating over the map produces at least two different orderings. 438 ord := func() []int { 439 var s []int 440 for key := range m { 441 s = append(s, key) 442 } 443 return s 444 } 445 first := ord() 446 ok := false 447 for try := 0; try < 100; try++ { 448 if !reflect.DeepEqual(first, ord()) { 449 ok = true 450 break 451 } 452 } 453 if !ok { 454 t.Errorf("Map with n=%d elements had consistent iteration order: %v", n, first) 455 break 456 } 457 } 458 } 459 } 460 461 // Issue 8410 462 func TestMapSparseIterOrder(t *testing.T) { 463 // Run several rounds to increase the probability 464 // of failure. One is not enough. 465 NextRound: 466 for round := 0; round < 10; round++ { 467 m := make(map[int]bool) 468 // Add 1000 items, remove 980. 469 for i := 0; i < 1000; i++ { 470 m[i] = true 471 } 472 for i := 20; i < 1000; i++ { 473 delete(m, i) 474 } 475 476 var first []int 477 for i := range m { 478 first = append(first, i) 479 } 480 481 // 800 chances to get a different iteration order. 482 // See bug 8736 for why we need so many tries. 483 for n := 0; n < 800; n++ { 484 idx := 0 485 for i := range m { 486 if i != first[idx] { 487 // iteration order changed. 488 continue NextRound 489 } 490 idx++ 491 } 492 } 493 t.Fatalf("constant iteration order on round %d: %v", round, first) 494 } 495 } 496 497 func TestMapStringBytesLookup(t *testing.T) { 498 // Use large string keys to avoid small-allocation coalescing, 499 // which can cause AllocsPerRun to report lower counts than it should. 500 m := map[string]int{ 501 "1000000000000000000000000000000000000000000000000": 1, 502 "2000000000000000000000000000000000000000000000000": 2, 503 } 504 buf := []byte("1000000000000000000000000000000000000000000000000") 505 if x := m[string(buf)]; x != 1 { 506 t.Errorf(`m[string([]byte("1"))] = %d, want 1`, x) 507 } 508 buf[0] = '2' 509 if x := m[string(buf)]; x != 2 { 510 t.Errorf(`m[string([]byte("2"))] = %d, want 2`, x) 511 } 512 513 var x int 514 n := testing.AllocsPerRun(100, func() { 515 x += m[string(buf)] 516 }) 517 if n != 0 { 518 t.Errorf("AllocsPerRun for m[string(buf)] = %v, want 0", n) 519 } 520 521 x = 0 522 n = testing.AllocsPerRun(100, func() { 523 y, ok := m[string(buf)] 524 if !ok { 525 panic("!ok") 526 } 527 x += y 528 }) 529 if n != 0 { 530 t.Errorf("AllocsPerRun for x,ok = m[string(buf)] = %v, want 0", n) 531 } 532 } 533 534 func TestMapLargeKeyNoPointer(t *testing.T) { 535 const ( 536 I = 1000 537 N = 64 538 ) 539 type T [N]int 540 m := make(map[T]int) 541 for i := 0; i < I; i++ { 542 var v T 543 for j := 0; j < N; j++ { 544 v[j] = i + j 545 } 546 m[v] = i 547 } 548 runtime.GC() 549 for i := 0; i < I; i++ { 550 var v T 551 for j := 0; j < N; j++ { 552 v[j] = i + j 553 } 554 if m[v] != i { 555 t.Fatalf("corrupted map: want %+v, got %+v", i, m[v]) 556 } 557 } 558 } 559 560 func TestMapLargeValNoPointer(t *testing.T) { 561 const ( 562 I = 1000 563 N = 64 564 ) 565 type T [N]int 566 m := make(map[int]T) 567 for i := 0; i < I; i++ { 568 var v T 569 for j := 0; j < N; j++ { 570 v[j] = i + j 571 } 572 m[i] = v 573 } 574 runtime.GC() 575 for i := 0; i < I; i++ { 576 var v T 577 for j := 0; j < N; j++ { 578 v[j] = i + j 579 } 580 v1 := m[i] 581 for j := 0; j < N; j++ { 582 if v1[j] != v[j] { 583 t.Fatalf("corrupted map: want %+v, got %+v", v, v1) 584 } 585 } 586 } 587 } 588 589 func benchmarkMapPop(b *testing.B, n int) { 590 m := map[int]int{} 591 for i := 0; i < b.N; i++ { 592 for j := 0; j < n; j++ { 593 m[j] = j 594 } 595 for j := 0; j < n; j++ { 596 // Use iterator to pop an element. 597 // We want this to be fast, see issue 8412. 598 for k := range m { 599 delete(m, k) 600 break 601 } 602 } 603 } 604 } 605 606 func BenchmarkMapPop100(b *testing.B) { benchmarkMapPop(b, 100) } 607 func BenchmarkMapPop1000(b *testing.B) { benchmarkMapPop(b, 1000) } 608 func BenchmarkMapPop10000(b *testing.B) { benchmarkMapPop(b, 10000) } 609 610 func TestNonEscapingMap(t *testing.T) { 611 n := testing.AllocsPerRun(1000, func() { 612 m := make(map[int]int) 613 m[0] = 0 614 }) 615 if n != 0 { 616 t.Fatalf("want 0 allocs, got %v", n) 617 } 618 }