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