github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/runtime/hash_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 "internal/race" 10 "math" 11 "math/rand" 12 . "runtime" 13 "strings" 14 "testing" 15 "unsafe" 16 ) 17 18 func TestMemHash32Equality(t *testing.T) { 19 if *UseAeshash { 20 t.Skip("skipping since AES hash implementation is used") 21 } 22 var b [4]byte 23 r := rand.New(rand.NewSource(1234)) 24 seed := uintptr(r.Uint64()) 25 for i := 0; i < 100; i++ { 26 randBytes(r, b[:]) 27 got := MemHash32(unsafe.Pointer(&b), seed) 28 want := MemHash(unsafe.Pointer(&b), seed, 4) 29 if got != want { 30 t.Errorf("MemHash32(%x, %v) = %v; want %v", b, seed, got, want) 31 } 32 } 33 } 34 35 func TestMemHash64Equality(t *testing.T) { 36 if *UseAeshash { 37 t.Skip("skipping since AES hash implementation is used") 38 } 39 var b [8]byte 40 r := rand.New(rand.NewSource(1234)) 41 seed := uintptr(r.Uint64()) 42 for i := 0; i < 100; i++ { 43 randBytes(r, b[:]) 44 got := MemHash64(unsafe.Pointer(&b), seed) 45 want := MemHash(unsafe.Pointer(&b), seed, 8) 46 if got != want { 47 t.Errorf("MemHash64(%x, %v) = %v; want %v", b, seed, got, want) 48 } 49 } 50 } 51 52 // Smhasher is a torture test for hash functions. 53 // https://code.google.com/p/smhasher/ 54 // This code is a port of some of the Smhasher tests to Go. 55 // 56 // The current AES hash function passes Smhasher. Our fallback 57 // hash functions don't, so we only enable the difficult tests when 58 // we know the AES implementation is available. 59 60 // Sanity checks. 61 // hash should not depend on values outside key. 62 // hash should not depend on alignment. 63 func TestSmhasherSanity(t *testing.T) { 64 r := rand.New(rand.NewSource(1234)) 65 const REP = 10 66 const KEYMAX = 128 67 const PAD = 16 68 const OFFMAX = 16 69 for k := 0; k < REP; k++ { 70 for n := 0; n < KEYMAX; n++ { 71 for i := 0; i < OFFMAX; i++ { 72 var b [KEYMAX + OFFMAX + 2*PAD]byte 73 var c [KEYMAX + OFFMAX + 2*PAD]byte 74 randBytes(r, b[:]) 75 randBytes(r, c[:]) 76 copy(c[PAD+i:PAD+i+n], b[PAD:PAD+n]) 77 if BytesHash(b[PAD:PAD+n], 0) != BytesHash(c[PAD+i:PAD+i+n], 0) { 78 t.Errorf("hash depends on bytes outside key") 79 } 80 } 81 } 82 } 83 } 84 85 type HashSet struct { 86 m map[uintptr]struct{} // set of hashes added 87 n int // number of hashes added 88 } 89 90 func newHashSet() *HashSet { 91 return &HashSet{make(map[uintptr]struct{}), 0} 92 } 93 func (s *HashSet) add(h uintptr) { 94 s.m[h] = struct{}{} 95 s.n++ 96 } 97 func (s *HashSet) addS(x string) { 98 s.add(StringHash(x, 0)) 99 } 100 func (s *HashSet) addB(x []byte) { 101 s.add(BytesHash(x, 0)) 102 } 103 func (s *HashSet) addS_seed(x string, seed uintptr) { 104 s.add(StringHash(x, seed)) 105 } 106 func (s *HashSet) check(t *testing.T) { 107 const SLOP = 50.0 108 collisions := s.n - len(s.m) 109 pairs := int64(s.n) * int64(s.n-1) / 2 110 expected := float64(pairs) / math.Pow(2.0, float64(hashSize)) 111 stddev := math.Sqrt(expected) 112 if float64(collisions) > expected+SLOP*(3*stddev+1) { 113 t.Errorf("unexpected number of collisions: got=%d mean=%f stddev=%f threshold=%f", collisions, expected, stddev, expected+SLOP*(3*stddev+1)) 114 } 115 } 116 117 // a string plus adding zeros must make distinct hashes 118 func TestSmhasherAppendedZeros(t *testing.T) { 119 s := "hello" + strings.Repeat("\x00", 256) 120 h := newHashSet() 121 for i := 0; i <= len(s); i++ { 122 h.addS(s[:i]) 123 } 124 h.check(t) 125 } 126 127 // All 0-3 byte strings have distinct hashes. 128 func TestSmhasherSmallKeys(t *testing.T) { 129 if race.Enabled { 130 t.Skip("Too long for race mode") 131 } 132 h := newHashSet() 133 var b [3]byte 134 for i := 0; i < 256; i++ { 135 b[0] = byte(i) 136 h.addB(b[:1]) 137 for j := 0; j < 256; j++ { 138 b[1] = byte(j) 139 h.addB(b[:2]) 140 if !testing.Short() { 141 for k := 0; k < 256; k++ { 142 b[2] = byte(k) 143 h.addB(b[:3]) 144 } 145 } 146 } 147 } 148 h.check(t) 149 } 150 151 // Different length strings of all zeros have distinct hashes. 152 func TestSmhasherZeros(t *testing.T) { 153 N := 256 * 1024 154 if testing.Short() { 155 N = 1024 156 } 157 h := newHashSet() 158 b := make([]byte, N) 159 for i := 0; i <= N; i++ { 160 h.addB(b[:i]) 161 } 162 h.check(t) 163 } 164 165 // Strings with up to two nonzero bytes all have distinct hashes. 166 func TestSmhasherTwoNonzero(t *testing.T) { 167 if GOARCH == "wasm" { 168 t.Skip("Too slow on wasm") 169 } 170 if testing.Short() { 171 t.Skip("Skipping in short mode") 172 } 173 if race.Enabled { 174 t.Skip("Too long for race mode") 175 } 176 h := newHashSet() 177 for n := 2; n <= 16; n++ { 178 twoNonZero(h, n) 179 } 180 h.check(t) 181 } 182 func twoNonZero(h *HashSet, n int) { 183 b := make([]byte, n) 184 185 // all zero 186 h.addB(b) 187 188 // one non-zero byte 189 for i := 0; i < n; i++ { 190 for x := 1; x < 256; x++ { 191 b[i] = byte(x) 192 h.addB(b) 193 b[i] = 0 194 } 195 } 196 197 // two non-zero bytes 198 for i := 0; i < n; i++ { 199 for x := 1; x < 256; x++ { 200 b[i] = byte(x) 201 for j := i + 1; j < n; j++ { 202 for y := 1; y < 256; y++ { 203 b[j] = byte(y) 204 h.addB(b) 205 b[j] = 0 206 } 207 } 208 b[i] = 0 209 } 210 } 211 } 212 213 // Test strings with repeats, like "abcdabcdabcdabcd..." 214 func TestSmhasherCyclic(t *testing.T) { 215 if testing.Short() { 216 t.Skip("Skipping in short mode") 217 } 218 if race.Enabled { 219 t.Skip("Too long for race mode") 220 } 221 r := rand.New(rand.NewSource(1234)) 222 const REPEAT = 8 223 const N = 1000000 224 for n := 4; n <= 12; n++ { 225 h := newHashSet() 226 b := make([]byte, REPEAT*n) 227 for i := 0; i < N; i++ { 228 b[0] = byte(i * 79 % 97) 229 b[1] = byte(i * 43 % 137) 230 b[2] = byte(i * 151 % 197) 231 b[3] = byte(i * 199 % 251) 232 randBytes(r, b[4:n]) 233 for j := n; j < n*REPEAT; j++ { 234 b[j] = b[j-n] 235 } 236 h.addB(b) 237 } 238 h.check(t) 239 } 240 } 241 242 // Test strings with only a few bits set 243 func TestSmhasherSparse(t *testing.T) { 244 if GOARCH == "wasm" { 245 t.Skip("Too slow on wasm") 246 } 247 if testing.Short() { 248 t.Skip("Skipping in short mode") 249 } 250 sparse(t, 32, 6) 251 sparse(t, 40, 6) 252 sparse(t, 48, 5) 253 sparse(t, 56, 5) 254 sparse(t, 64, 5) 255 sparse(t, 96, 4) 256 sparse(t, 256, 3) 257 sparse(t, 2048, 2) 258 } 259 func sparse(t *testing.T, n int, k int) { 260 b := make([]byte, n/8) 261 h := newHashSet() 262 setbits(h, b, 0, k) 263 h.check(t) 264 } 265 266 // set up to k bits at index i and greater 267 func setbits(h *HashSet, b []byte, i int, k int) { 268 h.addB(b) 269 if k == 0 { 270 return 271 } 272 for j := i; j < len(b)*8; j++ { 273 b[j/8] |= byte(1 << uint(j&7)) 274 setbits(h, b, j+1, k-1) 275 b[j/8] &= byte(^(1 << uint(j&7))) 276 } 277 } 278 279 // Test all possible combinations of n blocks from the set s. 280 // "permutation" is a bad name here, but it is what Smhasher uses. 281 func TestSmhasherPermutation(t *testing.T) { 282 if GOARCH == "wasm" { 283 t.Skip("Too slow on wasm") 284 } 285 if testing.Short() { 286 t.Skip("Skipping in short mode") 287 } 288 if race.Enabled { 289 t.Skip("Too long for race mode") 290 } 291 permutation(t, []uint32{0, 1, 2, 3, 4, 5, 6, 7}, 8) 292 permutation(t, []uint32{0, 1 << 29, 2 << 29, 3 << 29, 4 << 29, 5 << 29, 6 << 29, 7 << 29}, 8) 293 permutation(t, []uint32{0, 1}, 20) 294 permutation(t, []uint32{0, 1 << 31}, 20) 295 permutation(t, []uint32{0, 1, 2, 3, 4, 5, 6, 7, 1 << 29, 2 << 29, 3 << 29, 4 << 29, 5 << 29, 6 << 29, 7 << 29}, 6) 296 } 297 func permutation(t *testing.T, s []uint32, n int) { 298 b := make([]byte, n*4) 299 h := newHashSet() 300 genPerm(h, b, s, 0) 301 h.check(t) 302 } 303 func genPerm(h *HashSet, b []byte, s []uint32, n int) { 304 h.addB(b[:n]) 305 if n == len(b) { 306 return 307 } 308 for _, v := range s { 309 b[n] = byte(v) 310 b[n+1] = byte(v >> 8) 311 b[n+2] = byte(v >> 16) 312 b[n+3] = byte(v >> 24) 313 genPerm(h, b, s, n+4) 314 } 315 } 316 317 type Key interface { 318 clear() // set bits all to 0 319 random(r *rand.Rand) // set key to something random 320 bits() int // how many bits key has 321 flipBit(i int) // flip bit i of the key 322 hash() uintptr // hash the key 323 name() string // for error reporting 324 } 325 326 type BytesKey struct { 327 b []byte 328 } 329 330 func (k *BytesKey) clear() { 331 for i := range k.b { 332 k.b[i] = 0 333 } 334 } 335 func (k *BytesKey) random(r *rand.Rand) { 336 randBytes(r, k.b) 337 } 338 func (k *BytesKey) bits() int { 339 return len(k.b) * 8 340 } 341 func (k *BytesKey) flipBit(i int) { 342 k.b[i>>3] ^= byte(1 << uint(i&7)) 343 } 344 func (k *BytesKey) hash() uintptr { 345 return BytesHash(k.b, 0) 346 } 347 func (k *BytesKey) name() string { 348 return fmt.Sprintf("bytes%d", len(k.b)) 349 } 350 351 type Int32Key struct { 352 i uint32 353 } 354 355 func (k *Int32Key) clear() { 356 k.i = 0 357 } 358 func (k *Int32Key) random(r *rand.Rand) { 359 k.i = r.Uint32() 360 } 361 func (k *Int32Key) bits() int { 362 return 32 363 } 364 func (k *Int32Key) flipBit(i int) { 365 k.i ^= 1 << uint(i) 366 } 367 func (k *Int32Key) hash() uintptr { 368 return Int32Hash(k.i, 0) 369 } 370 func (k *Int32Key) name() string { 371 return "int32" 372 } 373 374 type Int64Key struct { 375 i uint64 376 } 377 378 func (k *Int64Key) clear() { 379 k.i = 0 380 } 381 func (k *Int64Key) random(r *rand.Rand) { 382 k.i = uint64(r.Uint32()) + uint64(r.Uint32())<<32 383 } 384 func (k *Int64Key) bits() int { 385 return 64 386 } 387 func (k *Int64Key) flipBit(i int) { 388 k.i ^= 1 << uint(i) 389 } 390 func (k *Int64Key) hash() uintptr { 391 return Int64Hash(k.i, 0) 392 } 393 func (k *Int64Key) name() string { 394 return "int64" 395 } 396 397 type EfaceKey struct { 398 i any 399 } 400 401 func (k *EfaceKey) clear() { 402 k.i = nil 403 } 404 func (k *EfaceKey) random(r *rand.Rand) { 405 k.i = uint64(r.Int63()) 406 } 407 func (k *EfaceKey) bits() int { 408 // use 64 bits. This tests inlined interfaces 409 // on 64-bit targets and indirect interfaces on 410 // 32-bit targets. 411 return 64 412 } 413 func (k *EfaceKey) flipBit(i int) { 414 k.i = k.i.(uint64) ^ uint64(1)<<uint(i) 415 } 416 func (k *EfaceKey) hash() uintptr { 417 return EfaceHash(k.i, 0) 418 } 419 func (k *EfaceKey) name() string { 420 return "Eface" 421 } 422 423 type IfaceKey struct { 424 i interface { 425 F() 426 } 427 } 428 type fInter uint64 429 430 func (x fInter) F() { 431 } 432 433 func (k *IfaceKey) clear() { 434 k.i = nil 435 } 436 func (k *IfaceKey) random(r *rand.Rand) { 437 k.i = fInter(r.Int63()) 438 } 439 func (k *IfaceKey) bits() int { 440 // use 64 bits. This tests inlined interfaces 441 // on 64-bit targets and indirect interfaces on 442 // 32-bit targets. 443 return 64 444 } 445 func (k *IfaceKey) flipBit(i int) { 446 k.i = k.i.(fInter) ^ fInter(1)<<uint(i) 447 } 448 func (k *IfaceKey) hash() uintptr { 449 return IfaceHash(k.i, 0) 450 } 451 func (k *IfaceKey) name() string { 452 return "Iface" 453 } 454 455 // Flipping a single bit of a key should flip each output bit with 50% probability. 456 func TestSmhasherAvalanche(t *testing.T) { 457 if GOARCH == "wasm" { 458 t.Skip("Too slow on wasm") 459 } 460 if testing.Short() { 461 t.Skip("Skipping in short mode") 462 } 463 if race.Enabled { 464 t.Skip("Too long for race mode") 465 } 466 avalancheTest1(t, &BytesKey{make([]byte, 2)}) 467 avalancheTest1(t, &BytesKey{make([]byte, 4)}) 468 avalancheTest1(t, &BytesKey{make([]byte, 8)}) 469 avalancheTest1(t, &BytesKey{make([]byte, 16)}) 470 avalancheTest1(t, &BytesKey{make([]byte, 32)}) 471 avalancheTest1(t, &BytesKey{make([]byte, 200)}) 472 avalancheTest1(t, &Int32Key{}) 473 avalancheTest1(t, &Int64Key{}) 474 avalancheTest1(t, &EfaceKey{}) 475 avalancheTest1(t, &IfaceKey{}) 476 } 477 func avalancheTest1(t *testing.T, k Key) { 478 const REP = 100000 479 r := rand.New(rand.NewSource(1234)) 480 n := k.bits() 481 482 // grid[i][j] is a count of whether flipping 483 // input bit i affects output bit j. 484 grid := make([][hashSize]int, n) 485 486 for z := 0; z < REP; z++ { 487 // pick a random key, hash it 488 k.random(r) 489 h := k.hash() 490 491 // flip each bit, hash & compare the results 492 for i := 0; i < n; i++ { 493 k.flipBit(i) 494 d := h ^ k.hash() 495 k.flipBit(i) 496 497 // record the effects of that bit flip 498 g := &grid[i] 499 for j := 0; j < hashSize; j++ { 500 g[j] += int(d & 1) 501 d >>= 1 502 } 503 } 504 } 505 506 // Each entry in the grid should be about REP/2. 507 // More precisely, we did N = k.bits() * hashSize experiments where 508 // each is the sum of REP coin flips. We want to find bounds on the 509 // sum of coin flips such that a truly random experiment would have 510 // all sums inside those bounds with 99% probability. 511 N := n * hashSize 512 var c float64 513 // find c such that Prob(mean-c*stddev < x < mean+c*stddev)^N > .9999 514 for c = 0.0; math.Pow(math.Erf(c/math.Sqrt(2)), float64(N)) < .9999; c += .1 { 515 } 516 c *= 4.0 // allowed slack - we don't need to be perfectly random 517 mean := .5 * REP 518 stddev := .5 * math.Sqrt(REP) 519 low := int(mean - c*stddev) 520 high := int(mean + c*stddev) 521 for i := 0; i < n; i++ { 522 for j := 0; j < hashSize; j++ { 523 x := grid[i][j] 524 if x < low || x > high { 525 t.Errorf("bad bias for %s bit %d -> bit %d: %d/%d\n", k.name(), i, j, x, REP) 526 } 527 } 528 } 529 } 530 531 // All bit rotations of a set of distinct keys 532 func TestSmhasherWindowed(t *testing.T) { 533 if race.Enabled { 534 t.Skip("Too long for race mode") 535 } 536 t.Logf("32 bit keys") 537 windowed(t, &Int32Key{}) 538 t.Logf("64 bit keys") 539 windowed(t, &Int64Key{}) 540 t.Logf("string keys") 541 windowed(t, &BytesKey{make([]byte, 128)}) 542 } 543 func windowed(t *testing.T, k Key) { 544 if GOARCH == "wasm" { 545 t.Skip("Too slow on wasm") 546 } 547 if PtrSize == 4 { 548 // This test tends to be flaky on 32-bit systems. 549 // There's not enough bits in the hash output, so we 550 // expect a nontrivial number of collisions, and it is 551 // often quite a bit higher than expected. See issue 43130. 552 t.Skip("Flaky on 32-bit systems") 553 } 554 if testing.Short() { 555 t.Skip("Skipping in short mode") 556 } 557 const BITS = 16 558 559 for r := 0; r < k.bits(); r++ { 560 h := newHashSet() 561 for i := 0; i < 1<<BITS; i++ { 562 k.clear() 563 for j := 0; j < BITS; j++ { 564 if i>>uint(j)&1 != 0 { 565 k.flipBit((j + r) % k.bits()) 566 } 567 } 568 h.add(k.hash()) 569 } 570 h.check(t) 571 } 572 } 573 574 // All keys of the form prefix + [A-Za-z0-9]*N + suffix. 575 func TestSmhasherText(t *testing.T) { 576 if testing.Short() { 577 t.Skip("Skipping in short mode") 578 } 579 text(t, "Foo", "Bar") 580 text(t, "FooBar", "") 581 text(t, "", "FooBar") 582 } 583 func text(t *testing.T, prefix, suffix string) { 584 const N = 4 585 const S = "ABCDEFGHIJKLMNOPQRSTabcdefghijklmnopqrst0123456789" 586 const L = len(S) 587 b := make([]byte, len(prefix)+N+len(suffix)) 588 copy(b, prefix) 589 copy(b[len(prefix)+N:], suffix) 590 h := newHashSet() 591 c := b[len(prefix):] 592 for i := 0; i < L; i++ { 593 c[0] = S[i] 594 for j := 0; j < L; j++ { 595 c[1] = S[j] 596 for k := 0; k < L; k++ { 597 c[2] = S[k] 598 for x := 0; x < L; x++ { 599 c[3] = S[x] 600 h.addB(b) 601 } 602 } 603 } 604 } 605 h.check(t) 606 } 607 608 // Make sure different seed values generate different hashes. 609 func TestSmhasherSeed(t *testing.T) { 610 h := newHashSet() 611 const N = 100000 612 s := "hello" 613 for i := 0; i < N; i++ { 614 h.addS_seed(s, uintptr(i)) 615 } 616 h.check(t) 617 } 618 619 // size of the hash output (32 or 64 bits) 620 const hashSize = 32 + int(^uintptr(0)>>63<<5) 621 622 func randBytes(r *rand.Rand, b []byte) { 623 for i := range b { 624 b[i] = byte(r.Uint32()) 625 } 626 } 627 628 func benchmarkHash(b *testing.B, n int) { 629 s := strings.Repeat("A", n) 630 631 for i := 0; i < b.N; i++ { 632 StringHash(s, 0) 633 } 634 b.SetBytes(int64(n)) 635 } 636 637 func BenchmarkHash5(b *testing.B) { benchmarkHash(b, 5) } 638 func BenchmarkHash16(b *testing.B) { benchmarkHash(b, 16) } 639 func BenchmarkHash64(b *testing.B) { benchmarkHash(b, 64) } 640 func BenchmarkHash1024(b *testing.B) { benchmarkHash(b, 1024) } 641 func BenchmarkHash65536(b *testing.B) { benchmarkHash(b, 65536) } 642 643 func TestArrayHash(t *testing.T) { 644 // Make sure that "" in arrays hash correctly. The hash 645 // should at least scramble the input seed so that, e.g., 646 // {"","foo"} and {"foo",""} have different hashes. 647 648 // If the hash is bad, then all (8 choose 4) = 70 keys 649 // have the same hash. If so, we allocate 70/8 = 8 650 // overflow buckets. If the hash is good we don't 651 // normally allocate any overflow buckets, and the 652 // probability of even one or two overflows goes down rapidly. 653 // (There is always 1 allocation of the bucket array. The map 654 // header is allocated on the stack.) 655 f := func() { 656 // Make the key type at most 128 bytes. Otherwise, 657 // we get an allocation per key. 658 type key [8]string 659 m := make(map[key]bool, 70) 660 661 // fill m with keys that have 4 "foo"s and 4 ""s. 662 for i := 0; i < 256; i++ { 663 var k key 664 cnt := 0 665 for j := uint(0); j < 8; j++ { 666 if i>>j&1 != 0 { 667 k[j] = "foo" 668 cnt++ 669 } 670 } 671 if cnt == 4 { 672 m[k] = true 673 } 674 } 675 if len(m) != 70 { 676 t.Errorf("bad test: (8 choose 4) should be 70, not %d", len(m)) 677 } 678 } 679 if n := testing.AllocsPerRun(10, f); n > 6 { 680 t.Errorf("too many allocs %f - hash not balanced", n) 681 } 682 } 683 func TestStructHash(t *testing.T) { 684 // See the comment in TestArrayHash. 685 f := func() { 686 type key struct { 687 a, b, c, d, e, f, g, h string 688 } 689 m := make(map[key]bool, 70) 690 691 // fill m with keys that have 4 "foo"s and 4 ""s. 692 for i := 0; i < 256; i++ { 693 var k key 694 cnt := 0 695 if i&1 != 0 { 696 k.a = "foo" 697 cnt++ 698 } 699 if i&2 != 0 { 700 k.b = "foo" 701 cnt++ 702 } 703 if i&4 != 0 { 704 k.c = "foo" 705 cnt++ 706 } 707 if i&8 != 0 { 708 k.d = "foo" 709 cnt++ 710 } 711 if i&16 != 0 { 712 k.e = "foo" 713 cnt++ 714 } 715 if i&32 != 0 { 716 k.f = "foo" 717 cnt++ 718 } 719 if i&64 != 0 { 720 k.g = "foo" 721 cnt++ 722 } 723 if i&128 != 0 { 724 k.h = "foo" 725 cnt++ 726 } 727 if cnt == 4 { 728 m[k] = true 729 } 730 } 731 if len(m) != 70 { 732 t.Errorf("bad test: (8 choose 4) should be 70, not %d", len(m)) 733 } 734 } 735 if n := testing.AllocsPerRun(10, f); n > 6 { 736 t.Errorf("too many allocs %f - hash not balanced", n) 737 } 738 } 739 740 var sink uint64 741 742 func BenchmarkAlignedLoad(b *testing.B) { 743 var buf [16]byte 744 p := unsafe.Pointer(&buf[0]) 745 var s uint64 746 for i := 0; i < b.N; i++ { 747 s += ReadUnaligned64(p) 748 } 749 sink = s 750 } 751 752 func BenchmarkUnalignedLoad(b *testing.B) { 753 var buf [16]byte 754 p := unsafe.Pointer(&buf[1]) 755 var s uint64 756 for i := 0; i < b.N; i++ { 757 s += ReadUnaligned64(p) 758 } 759 sink = s 760 } 761 762 func TestCollisions(t *testing.T) { 763 if testing.Short() { 764 t.Skip("Skipping in short mode") 765 } 766 for i := 0; i < 16; i++ { 767 for j := 0; j < 16; j++ { 768 if j == i { 769 continue 770 } 771 var a [16]byte 772 m := make(map[uint16]struct{}, 1<<16) 773 for n := 0; n < 1<<16; n++ { 774 a[i] = byte(n) 775 a[j] = byte(n >> 8) 776 m[uint16(BytesHash(a[:], 0))] = struct{}{} 777 } 778 // N balls in N bins, for N=65536 779 avg := 41427 780 stdDev := 123 781 if len(m) < avg-40*stdDev || len(m) > avg+40*stdDev { 782 t.Errorf("bad number of collisions i=%d j=%d outputs=%d out of 65536\n", i, j, len(m)) 783 } 784 } 785 } 786 }