github.com/moontrade/nogc@v0.1.7/hash/hash_test.go (about)

     1  package hash
     2  
     3  import (
     4  	"encoding/binary"
     5  	"hash/crc32"
     6  	"hash/crc64"
     7  	"math/rand"
     8  	"testing"
     9  )
    10  
    11  func TestHashCollisions_WASM(t *testing.T) {
    12  	var (
    13  		c32   int
    14  		a32   int
    15  		c16   int
    16  		fn    int
    17  		mur   int
    18  		wy    int
    19  		wy64  int
    20  		met   int
    21  		met64 int
    22  		total int
    23  	)
    24  
    25  	type config struct {
    26  		low            int
    27  		high           int
    28  		adder          int
    29  		factor         float64
    30  		addressStart   int
    31  		multiplierLow  int
    32  		multiplierHigh int
    33  		multiplierAdd  int
    34  	}
    35  	for _, cfg := range []config{
    36  		//{2, 10, 4, 8, 65580, 64, 4096, 128},
    37  		// WASM like pointer values
    38  		{40, 1024, 88, 3, 65580, 512, 256000, 96},
    39  		{1024, 4096, 512, 3, 65580, 56, 52050, 512},
    40  	} {
    41  		for i := cfg.low; i < cfg.high; i += cfg.adder {
    42  			var (
    43  				entries = i
    44  				slots   = int(float64(i) * cfg.factor)
    45  			)
    46  			for multiplier := cfg.multiplierLow; multiplier < cfg.multiplierHigh; multiplier += cfg.multiplierAdd {
    47  				total += entries
    48  				c32 += testCollisions(entries, multiplier, slots, crc32h)
    49  				c16 += testCollisions(entries, multiplier, slots, crc16a)
    50  				a32 += testCollisions(entries, multiplier, slots, Adler32)
    51  				fn += testCollisions(entries, multiplier, slots, FNV32)
    52  				mur += testCollisions(entries, multiplier, slots, Murmur32)
    53  				wy += testCollisions(entries, multiplier, slots, WyHash32)
    54  				wy64 += testCollisions64(entries, multiplier, slots, WyHash64)
    55  				met += testCollisions(entries, multiplier, slots, Metro32)
    56  				met64 += testCollisions64(entries, multiplier, slots, Metro64)
    57  			}
    58  		}
    59  
    60  		//println("\tcrc32		", c32)
    61  		//println("\tcrc16		", c16)
    62  		//println("\tadler32		", a32)
    63  		//println("\tfnv			", fn)
    64  		//println("\tmurmur32		", mur)
    65  		//println("\twyhash32	", wy)
    66  		//println("\twyhash64	", wy64)
    67  		//println("\tmetro32		", met)
    68  		//println("\tmetro64		", met64)
    69  	}
    70  
    71  	println("")
    72  	println("total		", total)
    73  	println("\tcrc32		", c32)
    74  	println("\tcrc16		", c16)
    75  	println("\tAdler32		", a32)
    76  	println("\tfnv			", fn)
    77  	println("\tMurmur32	", mur)
    78  	println("\tWyHash32	", wy)
    79  	println("\tWyHash64	", wy64)
    80  	println("\tMetro32		", met)
    81  	println("\tMetro64		", met64)
    82  }
    83  
    84  func rangeRandom(min, max uint32) uint32 {
    85  	return uint32(rand.Int31n(int32(max-min)) + int32(min))
    86  }
    87  
    88  func testCollisions(entries, multiplier, slots int, hasher func(uint32) uint32) int {
    89  	m := make(map[uint32]struct{})
    90  	count := 0
    91  
    92  	ptr := 65680
    93  
    94  	for i := 0; i < entries; i++ {
    95  		v := hasher(uint32(ptr))
    96  		ptr += multiplier
    97  		index := v % uint32(slots)
    98  
    99  		_, ok := m[index]
   100  		if ok {
   101  			count++
   102  		} else {
   103  			m[index] = struct{}{}
   104  		}
   105  	}
   106  	return count
   107  }
   108  
   109  func testCollisionsRandom(entries, slots int, hasher func(uint32) uint32) int {
   110  	m := make(map[uint32]struct{})
   111  	count := 0
   112  
   113  	for i := 0; i < entries; i++ {
   114  		v := hasher(uint32(rand.Uint32()))
   115  		index := v % uint32(slots)
   116  
   117  		_, ok := m[index]
   118  		if ok {
   119  			count++
   120  		} else {
   121  			m[index] = struct{}{}
   122  		}
   123  	}
   124  	return count
   125  }
   126  
   127  func testCollisions64(entries, multiplier, slots int, hasher func(uint64) uint64) int {
   128  	m := make(map[uint64]struct{})
   129  	count := 0
   130  
   131  	ptr := 65536
   132  
   133  	for i := uint64(0); i < uint64(entries); i++ {
   134  		v := hasher(uint64(ptr))
   135  		ptr += multiplier
   136  		index := v % uint64(slots)
   137  
   138  		_, ok := m[index]
   139  		if ok {
   140  			count++
   141  		} else {
   142  			m[index] = struct{}{}
   143  		}
   144  	}
   145  	return count
   146  }
   147  
   148  func crc64h(v uint32) uint32 {
   149  	h := crc64.New(crc64.MakeTable(crc64.ECMA))
   150  	h.Reset()
   151  	b := [4]byte{}
   152  	binary.LittleEndian.PutUint32(b[0:], v)
   153  	h.Write(b[0:4])
   154  	return uint32(h.Sum64())
   155  }
   156  
   157  func crc32h(v uint32) uint32 {
   158  	h := crc32.NewIEEE()
   159  	h.Reset()
   160  	b := [4]byte{}
   161  	binary.LittleEndian.PutUint32(b[0:], v)
   162  	h.Write(b[0:4])
   163  	return uint32(h.Sum32())
   164  }
   165  
   166  var crc16tab = [256]uint16{
   167  	0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
   168  	0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
   169  	0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
   170  	0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
   171  	0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
   172  	0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
   173  	0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
   174  	0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
   175  	0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
   176  	0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
   177  	0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
   178  	0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
   179  	0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
   180  	0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
   181  	0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
   182  	0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
   183  	0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
   184  	0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
   185  	0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
   186  	0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
   187  	0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
   188  	0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
   189  	0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
   190  	0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
   191  	0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
   192  	0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
   193  	0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
   194  	0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
   195  	0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
   196  	0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
   197  	0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
   198  	0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0}
   199  
   200  func crc16a(v uint32) uint32 {
   201  	crc := uint16(0)
   202  	crc = ((crc << 8) & 0xff00) ^ crc16tab[((crc>>8)&0xff)^uint16(byte(v))]
   203  	crc = ((crc << 8) & 0xff00) ^ crc16tab[((crc>>8)&0xff)^uint16(byte(v<<8))]
   204  	crc = ((crc << 8) & 0xff00) ^ crc16tab[((crc>>8)&0xff)^uint16(byte(v<<16))]
   205  	crc = ((crc << 8) & 0xff00) ^ crc16tab[((crc>>8)&0xff)^uint16(byte(v<<24))]
   206  	return uint32(crc)
   207  }
   208  
   209  func BenchmarkHash(b *testing.B) {
   210  	//b.Run("crc32", func(b *testing.B) {
   211  	//	for i := 0; i < b.N; i++ {
   212  	//		crc32h(23)
   213  	//	}
   214  	//})
   215  	//b.Run("crc16", func(b *testing.B) {
   216  	//	for i := 0; i < b.N; i++ {
   217  	//		crc16a(23)
   218  	//	}
   219  	//})
   220  	//b.Run("crc16", func(b *testing.B) {
   221  	//	for i := 0; i < b.N; i++ {
   222  	//		crc16a(23)
   223  	//	}
   224  	//})
   225  	b.Run("Adler32", func(b *testing.B) {
   226  		for i := 0; i < b.N; i++ {
   227  			Adler32(Adler32(uint32(i)))
   228  		}
   229  	})
   230  	b.Run("FNV32", func(b *testing.B) {
   231  		for i := 0; i < b.N; i++ {
   232  			FNV32(FNV32(uint32(i)))
   233  		}
   234  	})
   235  	b.Run("Murmur32", func(b *testing.B) {
   236  		for i := 0; i < b.N; i++ {
   237  			Murmur32(Murmur32(uint32(i)))
   238  		}
   239  	})
   240  	b.Run("WyHash32", func(b *testing.B) {
   241  		for i := 0; i < b.N; i++ {
   242  			WyHash32(WyHash32(uint32(i)))
   243  		}
   244  	})
   245  	b.Run("WyHash64", func(b *testing.B) {
   246  		for i := 0; i < b.N; i++ {
   247  			WyHash64(WyHash64(uint64(i)))
   248  		}
   249  	})
   250  	b.Run("Metro32", func(b *testing.B) {
   251  		for i := 0; i < b.N; i++ {
   252  			Metro32(Metro32(uint32(i)))
   253  		}
   254  	})
   255  	b.Run("Metro64", func(b *testing.B) {
   256  		for i := 0; i < b.N; i++ {
   257  			Metro64(Metro64(uint64(i)))
   258  		}
   259  	})
   260  	//b.Run("WyHash", func(b *testing.B) {
   261  	//	h := fnv.New32a()
   262  	//	for i := 0; i < b.N; i++ {
   263  	//		h.Reset()
   264  	//
   265  	//		WyHash32(23)
   266  	//	}
   267  	//})
   268  }