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 type empty struct { 321 } 322 323 func TestEmptyKeyAndValue(t *testing.T) { 324 a := make(map[int]empty, 4) 325 b := make(map[empty]int, 4) 326 c := make(map[empty]empty, 4) 327 a[0] = empty{} 328 b[empty{}] = 0 329 b[empty{}] = 1 330 c[empty{}] = empty{} 331 332 if len(a) != 1 { 333 t.Errorf("empty value insert problem") 334 } 335 if b[empty{}] != 1 { 336 t.Errorf("empty key returned wrong value") 337 } 338 } 339 340 // Tests a map with a single bucket, with same-lengthed short keys 341 // ("quick keys") as well as long keys. 342 func TestSingleBucketMapStringKeys_DupLen(t *testing.T) { 343 testMapLookups(t, map[string]string{ 344 "x": "x1val", 345 "xx": "x2val", 346 "foo": "fooval", 347 "bar": "barval", // same key length as "foo" 348 "xxxx": "x4val", 349 strings.Repeat("x", 128): "longval1", 350 strings.Repeat("y", 128): "longval2", 351 }) 352 } 353 354 // Tests a map with a single bucket, with all keys having different lengths. 355 func TestSingleBucketMapStringKeys_NoDupLen(t *testing.T) { 356 testMapLookups(t, map[string]string{ 357 "x": "x1val", 358 "xx": "x2val", 359 "foo": "fooval", 360 "xxxx": "x4val", 361 "xxxxx": "x5val", 362 "xxxxxx": "x6val", 363 strings.Repeat("x", 128): "longval", 364 }) 365 } 366 367 func testMapLookups(t *testing.T, m map[string]string) { 368 for k, v := range m { 369 if m[k] != v { 370 t.Fatalf("m[%q] = %q; want %q", k, m[k], v) 371 } 372 } 373 } 374 375 // Tests whether the iterator returns the right elements when 376 // started in the middle of a grow, when the keys are NaNs. 377 func TestMapNanGrowIterator(t *testing.T) { 378 m := make(map[float64]int) 379 nan := math.NaN() 380 const nBuckets = 16 381 // To fill nBuckets buckets takes LOAD * nBuckets keys. 382 nKeys := int(nBuckets * *runtime.HashLoad) 383 384 // Get map to full point with nan keys. 385 for i := 0; i < nKeys; i++ { 386 m[nan] = i 387 } 388 // Trigger grow 389 m[1.0] = 1 390 delete(m, 1.0) 391 392 // Run iterator 393 found := make(map[int]struct{}) 394 for _, v := range m { 395 if v != -1 { 396 if _, repeat := found[v]; repeat { 397 t.Fatalf("repeat of value %d", v) 398 } 399 found[v] = struct{}{} 400 } 401 if len(found) == nKeys/2 { 402 // Halfway through iteration, finish grow. 403 for i := 0; i < nBuckets; i++ { 404 delete(m, 1.0) 405 } 406 } 407 } 408 if len(found) != nKeys { 409 t.Fatalf("missing value") 410 } 411 } 412 413 func TestMapIterOrder(t *testing.T) { 414 for _, n := range [...]int{3, 7, 9, 15} { 415 for i := 0; i < 1000; i++ { 416 // Make m be {0: true, 1: true, ..., n-1: true}. 417 m := make(map[int]bool) 418 for i := 0; i < n; i++ { 419 m[i] = true 420 } 421 // Check that iterating over the map produces at least two different orderings. 422 ord := func() []int { 423 var s []int 424 for key := range m { 425 s = append(s, key) 426 } 427 return s 428 } 429 first := ord() 430 ok := false 431 for try := 0; try < 100; try++ { 432 if !reflect.DeepEqual(first, ord()) { 433 ok = true 434 break 435 } 436 } 437 if !ok { 438 t.Errorf("Map with n=%d elements had consistent iteration order: %v", n, first) 439 break 440 } 441 } 442 } 443 } 444 445 // Issue 8410 446 func TestMapSparseIterOrder(t *testing.T) { 447 // Run several rounds to increase the probability 448 // of failure. One is not enough. 449 NextRound: 450 for round := 0; round < 10; round++ { 451 m := make(map[int]bool) 452 // Add 1000 items, remove 980. 453 for i := 0; i < 1000; i++ { 454 m[i] = true 455 } 456 for i := 20; i < 1000; i++ { 457 delete(m, i) 458 } 459 460 var first []int 461 for i := range m { 462 first = append(first, i) 463 } 464 465 // 800 chances to get a different iteration order. 466 // See bug 8736 for why we need so many tries. 467 for n := 0; n < 800; n++ { 468 idx := 0 469 for i := range m { 470 if i != first[idx] { 471 // iteration order changed. 472 continue NextRound 473 } 474 idx++ 475 } 476 } 477 t.Fatalf("constant iteration order on round %d: %v", round, first) 478 } 479 } 480 481 func TestMapStringBytesLookup(t *testing.T) { 482 // Use large string keys to avoid small-allocation coalescing, 483 // which can cause AllocsPerRun to report lower counts than it should. 484 m := map[string]int{ 485 "1000000000000000000000000000000000000000000000000": 1, 486 "2000000000000000000000000000000000000000000000000": 2, 487 } 488 buf := []byte("1000000000000000000000000000000000000000000000000") 489 if x := m[string(buf)]; x != 1 { 490 t.Errorf(`m[string([]byte("1"))] = %d, want 1`, x) 491 } 492 buf[0] = '2' 493 if x := m[string(buf)]; x != 2 { 494 t.Errorf(`m[string([]byte("2"))] = %d, want 2`, x) 495 } 496 497 var x int 498 n := testing.AllocsPerRun(100, func() { 499 x += m[string(buf)] 500 }) 501 if n != 0 { 502 t.Errorf("AllocsPerRun for m[string(buf)] = %v, want 0", n) 503 } 504 505 x = 0 506 n = testing.AllocsPerRun(100, func() { 507 y, ok := m[string(buf)] 508 if !ok { 509 panic("!ok") 510 } 511 x += y 512 }) 513 if n != 0 { 514 t.Errorf("AllocsPerRun for x,ok = m[string(buf)] = %v, want 0", n) 515 } 516 } 517 518 func TestMapLargeKeyNoPointer(t *testing.T) { 519 const ( 520 I = 1000 521 N = 64 522 ) 523 type T [N]int 524 m := make(map[T]int) 525 for i := 0; i < I; i++ { 526 var v T 527 for j := 0; j < N; j++ { 528 v[j] = i + j 529 } 530 m[v] = i 531 } 532 runtime.GC() 533 for i := 0; i < I; i++ { 534 var v T 535 for j := 0; j < N; j++ { 536 v[j] = i + j 537 } 538 if m[v] != i { 539 t.Fatalf("corrupted map: want %+v, got %+v", i, m[v]) 540 } 541 } 542 } 543 544 func TestMapLargeValNoPointer(t *testing.T) { 545 const ( 546 I = 1000 547 N = 64 548 ) 549 type T [N]int 550 m := make(map[int]T) 551 for i := 0; i < I; i++ { 552 var v T 553 for j := 0; j < N; j++ { 554 v[j] = i + j 555 } 556 m[i] = v 557 } 558 runtime.GC() 559 for i := 0; i < I; i++ { 560 var v T 561 for j := 0; j < N; j++ { 562 v[j] = i + j 563 } 564 v1 := m[i] 565 for j := 0; j < N; j++ { 566 if v1[j] != v[j] { 567 t.Fatalf("corrupted map: want %+v, got %+v", v, v1) 568 } 569 } 570 } 571 } 572 573 func benchmarkMapPop(b *testing.B, n int) { 574 m := map[int]int{} 575 for i := 0; i < b.N; i++ { 576 for j := 0; j < n; j++ { 577 m[j] = j 578 } 579 for j := 0; j < n; j++ { 580 // Use iterator to pop an element. 581 // We want this to be fast, see issue 8412. 582 for k := range m { 583 delete(m, k) 584 break 585 } 586 } 587 } 588 } 589 590 func BenchmarkMapPop100(b *testing.B) { benchmarkMapPop(b, 100) } 591 func BenchmarkMapPop1000(b *testing.B) { benchmarkMapPop(b, 1000) } 592 func BenchmarkMapPop10000(b *testing.B) { benchmarkMapPop(b, 10000) } 593 594 func TestNonEscapingMap(t *testing.T) { 595 n := testing.AllocsPerRun(1000, func() { 596 m := make(map[int]int) 597 m[0] = 0 598 }) 599 if n != 0 { 600 t.Fatalf("want 0 allocs, got %v", n) 601 } 602 } 603