github.com/moontrade/unsafe@v0.9.1/memory/hash/hash_test.go (about)

     1  package hash
     2  
     3  import (
     4  	"encoding/binary"
     5  	"fmt"
     6  	"hash/crc32"
     7  	"hash/crc64"
     8  	"math/rand"
     9  	"testing"
    10  	"time"
    11  )
    12  
    13  func print_hash(s string) {
    14  	fmt.Printf("%s: %d\n", s, String(s))
    15  }
    16  
    17  func TestMul64(t *testing.T) {
    18  	print_hash("h")
    19  	print_hash("he")
    20  	print_hash("hel")
    21  	print_hash("hell")
    22  	print_hash("hello")
    23  	print_hash("hellonow")
    24  	print_hash("hellonowhellonow")
    25  	print_hash("hellonowhellonowhellonowhellonow")
    26  	print_hash("hellonowhellonowhellonowhellonowhellonowhellonowhellonowhellonow")
    27  
    28  	//println(U64(10))
    29  	//println(U64(11))
    30  	//println(wymum(5000000000, 11))
    31  	//SetSeed(uint64(time.Now().UnixNano()))
    32  	//fmt.Println(Next())
    33  	//for i := 0; i < 10; i++ {
    34  	//	fmt.Println(NextFloat())
    35  	//}
    36  	//fmt.Println(NextGaussian())
    37  	//fmt.Println(wymum(10, 11), wymum2(10, 11))
    38  	//fmt.Println(wymum(192923, 9877732), wymum2(192923, 9877732))
    39  	//fmt.Println(1 ^ uint64(0xe7037ed1a0b428db))
    40  	//fmt.Println(99 ^ uint64(0xe7037ed1a0b428db))
    41  	//fmt.Println(HashString("hel"))
    42  	//fmt.Println(HashString("hell"))
    43  	//fmt.Println(HashString("hello"))
    44  	//fmt.Println(HashString("hello there today ok"))
    45  	//fmt.Println(String("hello there today ok hello there today ok hello there today ok o hello there today ok hello there today ok hello there today ok o"))
    46  	//fmt.Println(HashString("hello"))
    47  	//fmt.Println(HashString("hello123"))
    48  	//fmt.Println(uint64(10) >> 2)
    49  }
    50  
    51  func TestHashCollisions(t *testing.T) {
    52  	var (
    53  		//c32   int
    54  		//a32   int
    55  		//c16   int
    56  		fn           int
    57  		wyf3         int
    58  		wyf3string3  int
    59  		wyf3string4  int
    60  		wyf3string5  int
    61  		wyf3string8  int
    62  		wyf3string20 int
    63  		wyf3string32 int
    64  		wyf3string64 int
    65  		total        int
    66  	)
    67  
    68  	type config struct {
    69  		low            int
    70  		high           int
    71  		adder          int
    72  		factor         float64
    73  		addressStart   int
    74  		multiplierLow  int
    75  		multiplierHigh int
    76  		multiplierAdd  int
    77  	}
    78  	for _, cfg := range []config{
    79  		//{2, 10, 4, 8, 65580, 64, 4096, 128},
    80  		// WASM like pointer values
    81  		{40, 1024, 88, 3, 65580, 512, 256000, 96},
    82  		{1024, 4096, 512, 3, 65580, 56, 52050, 512},
    83  	} {
    84  		for i := cfg.low; i < cfg.high; i += cfg.adder {
    85  			var (
    86  				entries = i
    87  				slots   = int(float64(i) * cfg.factor)
    88  			)
    89  			for multiplier := cfg.multiplierLow; multiplier < cfg.multiplierHigh; multiplier += cfg.multiplierAdd {
    90  				total += entries
    91  				//c32 += testCollisions(entries, multiplier, slots, crc32h)
    92  				//c16 += testCollisions(entries, multiplier, slots, crc16a)
    93  				fn += testCollisions(entries, multiplier, slots, FNV32)
    94  				wyf3 += testCollisions64(entries, multiplier, slots, U64)
    95  
    96  				wyf3string3 += testCollisionsString(entries, 3, slots, String)
    97  				wyf3string4 += testCollisionsString(entries, 4, slots, String)
    98  				wyf3string5 += testCollisionsString(entries, 5, slots, String)
    99  				wyf3string8 += testCollisionsString(entries, 8, slots, String)
   100  				wyf3string20 += testCollisionsString(entries, 20, slots, String)
   101  				wyf3string32 += testCollisionsString(entries, 32, slots, String)
   102  				wyf3string64 += testCollisionsString(entries, 64, slots, String)
   103  			}
   104  		}
   105  	}
   106  
   107  	println("")
   108  	println("total		", total)
   109  	//println("\tcrc32		", c32)
   110  	//println("\tcrc16		", c16)
   111  	println("\tfnv			", fn)
   112  	println("\tWYF3		", wyf3)
   113  	println("\tWYF3Str 3		", wyf3string3)
   114  	println("\tWYF3Str 4		", wyf3string4)
   115  	println("\tWYF3Str 5		", wyf3string5)
   116  	println("\tWYF3Str 8		", wyf3string8)
   117  	println("\tWYF3Str 20		", wyf3string20)
   118  	println("\tWYF3Str 32		", wyf3string32)
   119  	println("\tWYF3Str 64		", wyf3string64)
   120  }
   121  
   122  func rangeRandom(min, max uint32) uint32 {
   123  	return uint32(rand.Int31n(int32(max-min)) + int32(min))
   124  }
   125  
   126  func testCollisions(entries, multiplier, slots int, hasher func(uint32) uint32) int {
   127  	m := make(map[uint32]struct{})
   128  	count := 0
   129  
   130  	ptr := 65680
   131  
   132  	for i := 0; i < entries; i++ {
   133  		v := hasher(uint32(ptr))
   134  		ptr += multiplier
   135  		index := v % uint32(slots)
   136  
   137  		_, ok := m[index]
   138  		if ok {
   139  			count++
   140  		} else {
   141  			m[index] = struct{}{}
   142  		}
   143  	}
   144  	return count
   145  }
   146  
   147  var seededRand = rand.New(
   148  	rand.NewSource(time.Now().UnixNano()))
   149  
   150  func StringWithCharset(length int, charset string) string {
   151  	b := make([]byte, length)
   152  	for i := range b {
   153  		b[i] = charset[seededRand.Intn(len(charset))]
   154  	}
   155  	return string(b)
   156  }
   157  
   158  const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
   159  
   160  func testCollisionsString(entries, size, slots int, hasher func(b string) uint64) int {
   161  	m := make(map[uint64]struct{})
   162  	count := 0
   163  
   164  	for i := 0; i < entries; i++ {
   165  		s := StringWithCharset(size, charset)
   166  		v := hasher(s)
   167  		index := v % uint64(slots)
   168  
   169  		_, ok := m[index]
   170  		if ok {
   171  			count++
   172  		} else {
   173  			m[index] = struct{}{}
   174  		}
   175  	}
   176  	return count
   177  }
   178  
   179  func testCollisions64(entries, multiplier, slots int, hasher func(uint64) uint64) int {
   180  	m := make(map[uint64]struct{})
   181  	count := 0
   182  
   183  	ptr := 65536
   184  
   185  	for i := uint64(0); i < uint64(entries); i++ {
   186  		v := hasher(uint64(ptr))
   187  		ptr += multiplier
   188  		index := v % uint64(slots)
   189  
   190  		_, ok := m[index]
   191  		if ok {
   192  			count++
   193  		} else {
   194  			m[index] = struct{}{}
   195  		}
   196  	}
   197  	return count
   198  }
   199  
   200  func crc64h(v uint32) uint32 {
   201  	h := crc64.New(crc64.MakeTable(crc64.ECMA))
   202  	h.Reset()
   203  	b := [4]byte{}
   204  	binary.LittleEndian.PutUint32(b[0:], v)
   205  	h.Write(b[0:4])
   206  	return uint32(h.Sum64())
   207  }
   208  
   209  func crc32h(v uint32) uint32 {
   210  	h := crc32.NewIEEE()
   211  	h.Reset()
   212  	b := [4]byte{}
   213  	binary.LittleEndian.PutUint32(b[0:], v)
   214  	h.Write(b[0:4])
   215  	return h.Sum32()
   216  }
   217  
   218  var crc16tab = [256]uint16{
   219  	0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
   220  	0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
   221  	0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
   222  	0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
   223  	0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
   224  	0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
   225  	0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
   226  	0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
   227  	0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
   228  	0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
   229  	0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
   230  	0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
   231  	0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
   232  	0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
   233  	0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
   234  	0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
   235  	0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
   236  	0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
   237  	0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
   238  	0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
   239  	0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
   240  	0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
   241  	0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
   242  	0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
   243  	0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
   244  	0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
   245  	0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
   246  	0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
   247  	0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
   248  	0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
   249  	0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
   250  	0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0}
   251  
   252  func crc16a(v uint32) uint32 {
   253  	crc := uint16(0)
   254  	crc = ((crc << 8) & 0xff00) ^ crc16tab[((crc>>8)&0xff)^uint16(byte(v))]
   255  	crc = ((crc << 8) & 0xff00) ^ crc16tab[((crc>>8)&0xff)^uint16(byte(v<<8))]
   256  	crc = ((crc << 8) & 0xff00) ^ crc16tab[((crc>>8)&0xff)^uint16(byte(v<<16))]
   257  	crc = ((crc << 8) & 0xff00) ^ crc16tab[((crc>>8)&0xff)^uint16(byte(v<<24))]
   258  	return uint32(crc)
   259  }
   260  
   261  func BenchmarkHash(b *testing.B) {
   262  	const multiply = uint64(1)
   263  	seed := rand.Uint64()
   264  
   265  	//FNV64(FNV64((11 + 1) * seed))
   266  	String(StringWithCharset(128, charset))
   267  	String(StringWithCharset(3, charset))
   268  	String(StringWithCharset(4, charset))
   269  	String(StringWithCharset(16, charset))
   270  	String(StringWithCharset(32, charset))
   271  	String(StringWithCharset(51, charset))
   272  	String(StringWithCharset(64, charset))
   273  	String(StringWithCharset(96, charset))
   274  	String(StringWithCharset(128, charset))
   275  	String(StringWithCharset(256, charset))
   276  	U64(U64((11 + 1) * seed))
   277  
   278  	//b.Run("crc32", func(b *testing.B) {
   279  	//	for i := 0; i < b.N; i++ {
   280  	//		crc32h(23)
   281  	//	}
   282  	//})
   283  	//b.Run("crc16", func(b *testing.B) {
   284  	//	for i := 0; i < b.N; i++ {
   285  	//		crc16a(23)
   286  	//	}
   287  	//})
   288  	//b.Run("crc16", func(b *testing.B) {
   289  	//	for i := 0; i < b.N; i++ {
   290  	//		crc16a(23)
   291  	//	}
   292  	//})
   293  	//b.Run("FNV64a", func(b *testing.B) {
   294  	//	for i := uint64(0); i < uint64(b.N)*multiply; i++ {
   295  	//		FNV32a(uint32((i + 1) * seed))
   296  	//	}
   297  	//})
   298  	b.Run("Hash U64", func(b *testing.B) {
   299  		b.ResetTimer()
   300  		for i := 0; i < b.N; i++ {
   301  			U64(uint64(i + 1))
   302  		}
   303  	})
   304  	b.Run("Hash 3", func(b *testing.B) {
   305  		str := "hel"
   306  
   307  		b.ResetTimer()
   308  		for i := 0; i < b.N; i++ {
   309  			String(str)
   310  		}
   311  	})
   312  	b.Run("Hash 5", func(b *testing.B) {
   313  		str := "hello"
   314  
   315  		b.ResetTimer()
   316  		for i := 0; i < b.N; i++ {
   317  			String(str)
   318  		}
   319  	})
   320  	b.Run("Hash 8", func(b *testing.B) {
   321  		str := "hellobye"
   322  
   323  		b.ResetTimer()
   324  		for i := 0; i < b.N; i++ {
   325  			String(str)
   326  		}
   327  	})
   328  	b.Run("Hash 16", func(b *testing.B) {
   329  		str := "hellobyehellobye"
   330  
   331  		b.ResetTimer()
   332  		for i := 0; i < b.N; i++ {
   333  			String(str)
   334  		}
   335  	})
   336  	b.Run("Hash 32", func(b *testing.B) {
   337  		str := "hellobyehellobyehellobyehellobye"
   338  
   339  		b.ResetTimer()
   340  		for i := 0; i < b.N; i++ {
   341  			String(str)
   342  		}
   343  	})
   344  	b.Run("Hash 64", func(b *testing.B) {
   345  		str := "hellobyehellobyehellobyehellobyehellobyehellobyehellobyehellobye"
   346  
   347  		b.ResetTimer()
   348  		for i := 0; i < b.N; i++ {
   349  			String(str)
   350  		}
   351  	})
   352  	b.Run("Hash 128", func(b *testing.B) {
   353  		str := "hellobyehellobyehellobyehellobyehellobyehellobyehellobyehellobyehellobyehellobyehellobyehellobyehellobyehellobyehellobyehellobye"
   354  
   355  		b.ResetTimer()
   356  		for i := 0; i < b.N; i++ {
   357  			String(str)
   358  		}
   359  	})
   360  	b.Run("Hash 129", func(b *testing.B) {
   361  		str := "hello there today ok hello there today ok hello there today ok o hello there today ok hello there today ok hello there today ok o"
   362  
   363  		b.ResetTimer()
   364  		for i := 0; i < b.N; i++ {
   365  			String(str)
   366  		}
   367  	})
   368  	b.Run("Hash 256", func(b *testing.B) {
   369  		str := "hellobyehellobyehellobyehellobyehellobyehellobyehellobyehellobyehellobyehellobyehellobyehellobyehellobyehellobyehellobyehellobyehellobyehellobyehellobyehellobyehellobyehellobyehellobyehellobyehellobyehellobyehellobyehellobyehellobyehellobyehellobyehellobye"
   370  
   371  		b.ResetTimer()
   372  		for i := 0; i < b.N; i++ {
   373  			String(str)
   374  		}
   375  	})
   376  }