blob: 19c605b2c08505ffcd182ab40f87deed0935aa00 [file] [log] [blame]
tanjent@gmail.comf3b78972012-03-01 03:38:55 +00001#include "Platform.h"
2#include "Hashes.h"
3#include "KeysetTest.h"
4#include "SpeedTest.h"
5#include "AvalancheTest.h"
6#include "DifferentialTest.h"
7
8#include <stdio.h>
9#include <time.h>
10
11//-----------------------------------------------------------------------------
12// Configuration. TODO - move these to command-line flags
13
14bool g_testAll = false;
15
16bool g_testSanity = false;
17bool g_testSpeed = false;
18bool g_testDiff = false;
19bool g_testDiffDist = false;
20bool g_testAvalanche = false;
21bool g_testBIC = false;
22bool g_testCyclic = false;
23bool g_testTwoBytes = false;
24bool g_testSparse = false;
25bool g_testPermutation = false;
26bool g_testWindow = false;
27bool g_testText = false;
28bool g_testZeroes = false;
29bool g_testSeed = false;
30
31//-----------------------------------------------------------------------------
32// This is the list of all hashes that SMHasher can test.
33
34struct HashInfo
35{
36 pfHash hash;
37 int hashbits;
38 uint32_t verification;
39 const char * name;
40 const char * desc;
41};
42
43HashInfo g_hashes[] =
44{
45 { DoNothingHash, 32, 0x00000000, "donothing32", "Do-Nothing function (only valid for measuring call overhead)" },
46 { DoNothingHash, 64, 0x00000000, "donothing64", "Do-Nothing function (only valid for measuring call overhead)" },
47 { DoNothingHash, 128, 0x00000000, "donothing128", "Do-Nothing function (only valid for measuring call overhead)" },
48
49 { crc32, 32, 0x3719DB20, "crc32", "CRC-32" },
50
51 { md5_32, 32, 0xC10C356B, "md5_32a", "MD5, first 32 bits of result" },
52 { sha1_32a, 32, 0xF9376EA7, "sha1_32a", "SHA1, first 32 bits of result" },
53
54 { FNV, 32, 0xE3CBBE91, "FNV", "Fowler-Noll-Vo hash, 32-bit" },
55 { Bernstein, 32, 0xBDB4B640, "bernstein", "Bernstein, 32-bit" },
56 { lookup3_test, 32, 0x3D83917A, "lookup3", "Bob Jenkins' lookup3" },
57 { SuperFastHash, 32, 0x980ACD1D, "superfast", "Paul Hsieh's SuperFastHash" },
58 { MurmurOAAT_test, 32, 0x5363BD98, "MurmurOAAT", "Murmur one-at-a-time" },
59 { Crap8_test, 32, 0x743E97A1, "Crap8", "Crap8" },
60
61 { CityHash64_test, 64, 0x25A20825, "City64", "Google CityHash64WithSeed" },
62 { CityHash128_test, 128, 0x6531F54E, "City128", "Google CityHash128WithSeed" },
63
64 { SpookyHash64_test, 32, 0x3F798BBB, "Spooky32", "Bob Jenkins' SpookyHash, 32-bit result" },
65 { SpookyHash64_test, 64, 0xA7F955F1, "Spooky64", "Bob Jenkins' SpookyHash, 64-bit result" },
66 { SpookyHash128_test, 128, 0x8D263080, "Spooky128", "Bob Jenkins' SpookyHash, 128-bit result" },
67
68 // MurmurHash2
69
70 { MurmurHash2_test, 32, 0x27864C1E, "Murmur2", "MurmurHash2 for x86, 32-bit" },
71 { MurmurHash2A_test, 32, 0x7FBD4396, "Murmur2A", "MurmurHash2A for x86, 32-bit" },
72 { MurmurHash64A_test, 64, 0x1F0D3804, "Murmur2B", "MurmurHash2 for x64, 64-bit" },
73 { MurmurHash64B_test, 64, 0xDD537C05, "Murmur2C", "MurmurHash2 for x86, 64-bit" },
74
75 // MurmurHash3
76
77 { MurmurHash3_x86_32, 32, 0xB0F57EE3, "Murmur3A", "MurmurHash3 for x86, 32-bit" },
78 { MurmurHash3_x86_128, 128, 0xB3ECE62A, "Murmur3C", "MurmurHash3 for x86, 128-bit" },
79 { MurmurHash3_x64_128, 128, 0x6384BA69, "Murmur3F", "MurmurHash3 for x64, 128-bit" },
80
81};
82
83HashInfo * findHash ( const char * name )
84{
85 for(size_t i = 0; i < sizeof(g_hashes) / sizeof(HashInfo); i++)
86 {
87 if(_stricmp(name,g_hashes[i].name) == 0) return &g_hashes[i];
88 }
89
90 return NULL;
91}
92
93//-----------------------------------------------------------------------------
94// Self-test on startup - verify that all installed hashes work correctly.
95
96void SelfTest ( void )
97{
98 bool pass = true;
99
100 for(size_t i = 0; i < sizeof(g_hashes) / sizeof(HashInfo); i++)
101 {
102 HashInfo * info = & g_hashes[i];
103
104 pass &= VerificationTest(info->hash,info->hashbits,info->verification,false);
105 }
106
107 if(!pass)
108 {
109 printf("Self-test FAILED!\n");
110
111 for(size_t i = 0; i < sizeof(g_hashes) / sizeof(HashInfo); i++)
112 {
113 HashInfo * info = & g_hashes[i];
114
115 printf("%16s - ",info->name);
116 pass &= VerificationTest(info->hash,info->hashbits,info->verification,true);
117 }
118
119 exit(1);
120 }
121}
122
123//----------------------------------------------------------------------------
124
125template < typename hashtype >
126void test ( hashfunc<hashtype> hash, HashInfo * info )
127{
128 const int hashbits = sizeof(hashtype) * 8;
129
130 printf("-------------------------------------------------------------------------------\n");
131 printf("--- Testing %s (%s)\n\n",info->name,info->desc);
132
133 //-----------------------------------------------------------------------------
134 // Sanity tests
135
136 if(g_testSanity || g_testAll)
137 {
138 printf("[[[ Sanity Tests ]]]\n\n");
139
140 VerificationTest(hash,hashbits,info->verification,true);
141 SanityTest(hash,hashbits);
142 AppendedZeroesTest(hash,hashbits);
143 printf("\n");
144 }
145
146 //-----------------------------------------------------------------------------
147 // Speed tests
148
149 if(g_testSpeed || g_testAll)
150 {
151 printf("[[[ Speed Tests ]]]\n\n");
152
153 BulkSpeedTest(info->hash,info->verification);
154 printf("\n");
155
156 for(int i = 1; i < 32; i++)
157 {
158 double cycles;
159
160 TinySpeedTest(hashfunc<hashtype>(info->hash),sizeof(hashtype),i,info->verification,true,cycles);
161 }
162
163 printf("\n");
164 }
165
166 //-----------------------------------------------------------------------------
167 // Differential tests
168
169 if(g_testDiff || g_testAll)
170 {
171 printf("[[[ Differential Tests ]]]\n\n");
172
173 bool result = true;
174 bool dumpCollisions = false;
175
176 result &= DiffTest< Blob<64>, hashtype >(hash,5,1000,dumpCollisions);
177 result &= DiffTest< Blob<128>, hashtype >(hash,4,1000,dumpCollisions);
178 result &= DiffTest< Blob<256>, hashtype >(hash,3,1000,dumpCollisions);
179
180 if(!result) printf("*********FAIL*********\n");
181 printf("\n");
182 }
183
184 //-----------------------------------------------------------------------------
185 // Differential-distribution tests
186
187 if(g_testDiffDist /*|| g_testAll*/)
188 {
189 printf("[[[ Differential Distribution Tests ]]]\n\n");
190
191 bool result = true;
192
193 result &= DiffDistTest2<uint64_t,hashtype>(hash);
194
195 printf("\n");
196 }
197
198 //-----------------------------------------------------------------------------
199 // Avalanche tests
200
201 if(g_testAvalanche || g_testAll)
202 {
203 printf("[[[ Avalanche Tests ]]]\n\n");
204
205 bool result = true;
206
207 result &= AvalancheTest< Blob< 32>, hashtype > (hash,300000);
208 result &= AvalancheTest< Blob< 40>, hashtype > (hash,300000);
209 result &= AvalancheTest< Blob< 48>, hashtype > (hash,300000);
210 result &= AvalancheTest< Blob< 56>, hashtype > (hash,300000);
211
212 result &= AvalancheTest< Blob< 64>, hashtype > (hash,300000);
213 result &= AvalancheTest< Blob< 72>, hashtype > (hash,300000);
214 result &= AvalancheTest< Blob< 80>, hashtype > (hash,300000);
215 result &= AvalancheTest< Blob< 88>, hashtype > (hash,300000);
216
217 result &= AvalancheTest< Blob< 96>, hashtype > (hash,300000);
218 result &= AvalancheTest< Blob<104>, hashtype > (hash,300000);
219 result &= AvalancheTest< Blob<112>, hashtype > (hash,300000);
220 result &= AvalancheTest< Blob<120>, hashtype > (hash,300000);
221
222 result &= AvalancheTest< Blob<128>, hashtype > (hash,300000);
223 result &= AvalancheTest< Blob<136>, hashtype > (hash,300000);
224 result &= AvalancheTest< Blob<144>, hashtype > (hash,300000);
225 result &= AvalancheTest< Blob<152>, hashtype > (hash,300000);
226
227 if(!result) printf("*********FAIL*********\n");
228 printf("\n");
229 }
230
231 //-----------------------------------------------------------------------------
232 // Bit Independence Criteria. Interesting, but doesn't tell us much about
233 // collision or distribution.
234
235 if(g_testBIC)
236 {
237 printf("[[[ Bit Independence Criteria ]]]\n\n");
238
239 bool result = true;
240
241 //result &= BicTest<uint64_t,hashtype>(hash,2000000);
242 BicTest3<Blob<88>,hashtype>(hash,2000000);
243
244 if(!result) printf("*********FAIL*********\n");
245 printf("\n");
246 }
247
248 //-----------------------------------------------------------------------------
249 // Keyset 'Cyclic' - keys of the form "abcdabcdabcd..."
250
251 if(g_testCyclic || g_testAll)
252 {
253 printf("[[[ Keyset 'Cyclic' Tests ]]]\n\n");
254
255 bool result = true;
256 bool drawDiagram = false;
257
258 result &= CyclicKeyTest<hashtype>(hash,sizeof(hashtype)+0,8,10000000,drawDiagram);
259 result &= CyclicKeyTest<hashtype>(hash,sizeof(hashtype)+1,8,10000000,drawDiagram);
260 result &= CyclicKeyTest<hashtype>(hash,sizeof(hashtype)+2,8,10000000,drawDiagram);
261 result &= CyclicKeyTest<hashtype>(hash,sizeof(hashtype)+3,8,10000000,drawDiagram);
262 result &= CyclicKeyTest<hashtype>(hash,sizeof(hashtype)+4,8,10000000,drawDiagram);
263
264 if(!result) printf("*********FAIL*********\n");
265 printf("\n");
266 }
267
268 //-----------------------------------------------------------------------------
269 // Keyset 'TwoBytes' - all keys up to N bytes containing two non-zero bytes
270
271 // This generates some huge keysets, 128-bit tests will take ~1.3 gigs of RAM.
272
273 if(g_testTwoBytes || g_testAll)
274 {
275 printf("[[[ Keyset 'TwoBytes' Tests ]]]\n\n");
276
277 bool result = true;
278 bool drawDiagram = false;
279
280 for(int i = 4; i <= 20; i += 4)
281 {
282 result &= TwoBytesTest2<hashtype>(hash,i,drawDiagram);
283 }
284
285 if(!result) printf("*********FAIL*********\n");
286 printf("\n");
287 }
288
289 //-----------------------------------------------------------------------------
290 // Keyset 'Sparse' - keys with all bits 0 except a few
291
292 if(g_testSparse || g_testAll)
293 {
294 printf("[[[ Keyset 'Sparse' Tests ]]]\n\n");
295
296 bool result = true;
297 bool drawDiagram = false;
298
299 result &= SparseKeyTest< 32,hashtype>(hash,6,true,true,true,drawDiagram);
300 result &= SparseKeyTest< 40,hashtype>(hash,6,true,true,true,drawDiagram);
301 result &= SparseKeyTest< 48,hashtype>(hash,5,true,true,true,drawDiagram);
302 result &= SparseKeyTest< 56,hashtype>(hash,5,true,true,true,drawDiagram);
303 result &= SparseKeyTest< 64,hashtype>(hash,5,true,true,true,drawDiagram);
304 result &= SparseKeyTest< 96,hashtype>(hash,4,true,true,true,drawDiagram);
305 result &= SparseKeyTest< 256,hashtype>(hash,3,true,true,true,drawDiagram);
306 result &= SparseKeyTest<2048,hashtype>(hash,2,true,true,true,drawDiagram);
307
308 if(!result) printf("*********FAIL*********\n");
309 printf("\n");
310 }
311
312 //-----------------------------------------------------------------------------
313 // Keyset 'Permutation' - all possible combinations of a set of blocks
314
315 if(g_testPermutation || g_testAll)
316 {
317 {
318 // This one breaks lookup3, surprisingly
319
320 printf("[[[ Keyset 'Combination Lowbits' Tests ]]]\n\n");
321
322 bool result = true;
323 bool drawDiagram = false;
324
325 uint32_t blocks[] =
326 {
327 0x00000000,
328
329 0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000006, 0x00000007,
330 };
331
332 result &= CombinationKeyTest<hashtype>(hash,8,blocks,sizeof(blocks) / sizeof(uint32_t),true,true,drawDiagram);
333
334 if(!result) printf("*********FAIL*********\n");
335 printf("\n");
336 }
337
338 {
339 printf("[[[ Keyset 'Combination Highbits' Tests ]]]\n\n");
340
341 bool result = true;
342 bool drawDiagram = false;
343
344 uint32_t blocks[] =
345 {
346 0x00000000,
347
348 0x20000000, 0x40000000, 0x60000000, 0x80000000, 0xA0000000, 0xC0000000, 0xE0000000
349 };
350
351 result &= CombinationKeyTest<hashtype>(hash,8,blocks,sizeof(blocks) / sizeof(uint32_t),true,true,drawDiagram);
352
353 if(!result) printf("*********FAIL*********\n");
354 printf("\n");
355 }
356
357 {
358 printf("[[[ Keyset 'Combination 0x8000000' Tests ]]]\n\n");
359
360 bool result = true;
361 bool drawDiagram = false;
362
363 uint32_t blocks[] =
364 {
365 0x00000000,
366
367 0x80000000,
368 };
369
370 result &= CombinationKeyTest<hashtype>(hash,20,blocks,sizeof(blocks) / sizeof(uint32_t),true,true,drawDiagram);
371
372 if(!result) printf("*********FAIL*********\n");
373 printf("\n");
374 }
375
376 {
377 printf("[[[ Keyset 'Combination 0x0000001' Tests ]]]\n\n");
378
379 bool result = true;
380 bool drawDiagram = false;
381
382 uint32_t blocks[] =
383 {
384 0x00000000,
385
386 0x00000001,
387 };
388
389 result &= CombinationKeyTest<hashtype>(hash,20,blocks,sizeof(blocks) / sizeof(uint32_t),true,true,drawDiagram);
390
391 if(!result) printf("*********FAIL*********\n");
392 printf("\n");
393 }
394
395 {
396 printf("[[[ Keyset 'Combination Hi-Lo' Tests ]]]\n\n");
397
398 bool result = true;
399 bool drawDiagram = false;
400
401 uint32_t blocks[] =
402 {
403 0x00000000,
404
405 0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000006, 0x00000007,
406
407 0x80000000, 0x40000000, 0xC0000000, 0x20000000, 0xA0000000, 0x60000000, 0xE0000000
408 };
409
410 result &= CombinationKeyTest<hashtype>(hash,6,blocks,sizeof(blocks) / sizeof(uint32_t),true,true,drawDiagram);
411
412 if(!result) printf("*********FAIL*********\n");
413 printf("\n");
414 }
415 }
416
417 //-----------------------------------------------------------------------------
418 // Keyset 'Window'
419
420 // Skip distribution test for these - they're too easy to distribute well,
421 // and it generates a _lot_ of testing
422
423 if(g_testWindow || g_testAll)
424 {
425 printf("[[[ Keyset 'Window' Tests ]]]\n\n");
426
427 bool result = true;
428 bool testCollision = true;
429 bool testDistribution = false;
430 bool drawDiagram = false;
431
432 result &= WindowedKeyTest< Blob<hashbits*2>, hashtype > ( hash, 20, testCollision, testDistribution, drawDiagram );
433
434 if(!result) printf("*********FAIL*********\n");
435 printf("\n");
436 }
437
438 //-----------------------------------------------------------------------------
439 // Keyset 'Text'
440
441 if(g_testText || g_testAll)
442 {
443 printf("[[[ Keyset 'Text' Tests ]]]\n\n");
444
445 bool result = true;
446 bool drawDiagram = false;
447
448 const char * alnum = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
449
450 result &= TextKeyTest( hash, "Foo", alnum,4, "Bar", drawDiagram );
451 result &= TextKeyTest( hash, "FooBar", alnum,4, "", drawDiagram );
452 result &= TextKeyTest( hash, "", alnum,4, "FooBar", drawDiagram );
453
454 if(!result) printf("*********FAIL*********\n");
455 printf("\n");
456 }
457
458 //-----------------------------------------------------------------------------
459 // Keyset 'Zeroes'
460
461 if(g_testZeroes || g_testAll)
462 {
463 printf("[[[ Keyset 'Zeroes' Tests ]]]\n\n");
464
465 bool result = true;
466 bool drawDiagram = false;
467
468 result &= ZeroKeyTest<hashtype>( hash, drawDiagram );
469
470 if(!result) printf("*********FAIL*********\n");
471 printf("\n");
472 }
473
474 //-----------------------------------------------------------------------------
475 // Keyset 'Seed'
476
477 if(g_testSeed || g_testAll)
478 {
479 printf("[[[ Keyset 'Seed' Tests ]]]\n\n");
480
481 bool result = true;
482 bool drawDiagram = false;
483
484 result &= SeedTest<hashtype>( hash, 1000000, drawDiagram );
485
486 if(!result) printf("*********FAIL*********\n");
487 printf("\n");
488 }
489}
490
491//-----------------------------------------------------------------------------
492
493uint32_t g_inputVCode = 1;
494uint32_t g_outputVCode = 1;
495uint32_t g_resultVCode = 1;
496
497HashInfo * g_hashUnderTest = NULL;
498
499void VerifyHash ( const void * key, int len, uint32_t seed, void * out )
500{
501 g_inputVCode = MurmurOAAT(key,len,g_inputVCode);
502 g_inputVCode = MurmurOAAT(&seed,sizeof(uint32_t),g_inputVCode);
503
504 g_hashUnderTest->hash(key,len,seed,out);
505
506 g_outputVCode = MurmurOAAT(out,g_hashUnderTest->hashbits/8,g_outputVCode);
507}
508
509//-----------------------------------------------------------------------------
510
511void testHash ( const char * name )
512{
513 HashInfo * pInfo = findHash(name);
514
515 if(pInfo == NULL)
516 {
517 printf("Invalid hash '%s' specified\n",name);
518 return;
519 }
520 else
521 {
522 g_hashUnderTest = pInfo;
523
524 if(pInfo->hashbits == 32)
525 {
526 test<uint32_t>( VerifyHash, pInfo );
527 }
528 else if(pInfo->hashbits == 64)
529 {
530 test<uint64_t>( pInfo->hash, pInfo );
531 }
532 else if(pInfo->hashbits == 128)
533 {
534 test<uint128_t>( pInfo->hash, pInfo );
535 }
536 else if(pInfo->hashbits == 256)
537 {
538 test<uint256_t>( pInfo->hash, pInfo );
539 }
540 else
541 {
542 printf("Invalid hash bit width %d for hash '%s'",pInfo->hashbits,pInfo->name);
543 }
544 }
545}
546//-----------------------------------------------------------------------------
547
548int main ( int argc, char ** argv )
549{
550 const char * hashToTest = "murmur3a";
551
552 if(argc < 2)
553 {
554 printf("(No test hash given on command line, testing Murmur3_x86_32.)\n");
555 }
556 else
557 {
558 hashToTest = argv[1];
559 }
560
561 // Code runs on the 3rd CPU by default
562
563 SetAffinity((1 << 2));
564
565 SelfTest();
566
567 int timeBegin = clock();
568
569 g_testAll = true;
570
571 //g_testSanity = true;
572 //g_testSpeed = true;
573 //g_testAvalanche = true;
574 //g_testBIC = true;
575 //g_testCyclic = true;
576 //g_testTwoBytes = true;
577 //g_testDiff = true;
578 //g_testDiffDist = true;
579 //g_testSparse = true;
580 //g_testPermutation = true;
581 //g_testWindow = true;
582 //g_testZeroes = true;
583
584 testHash(hashToTest);
585
586 //----------
587
588 int timeEnd = clock();
589
590 printf("\n");
591 printf("Input vcode 0x%08x, Output vcode 0x%08x, Result vcode 0x%08x\n",g_inputVCode,g_outputVCode,g_resultVCode);
592 printf("Verification value is 0x%08x - Testing took %f seconds\n",g_verify,double(timeEnd-timeBegin)/double(CLOCKS_PER_SEC));
593 printf("-------------------------------------------------------------------------------\n");
594 return 0;
595}