blob: f5fcf04ef3ba5120ce17859670ef10eea7093ca8 [file] [log] [blame]
tanjent@gmail.com7e5c3632010-11-02 00:50:04 +00001#include <stdio.h>
2
tanjent@gmail.com7e5c3632010-11-02 00:50:04 +00003#include "hashes.h"
tanjent@gmail.comad4b3632010-11-05 01:20:58 +00004#include "KeysetTest.h"
5#include "SpeedTest.h"
6#include "AvalancheTest.h"
7#include "DifferentialTest.h"
tanjent@gmail.com7e5c3632010-11-02 00:50:04 +00008
tanjent@gmail.comad4b3632010-11-05 01:20:58 +00009#include <time.h>
10#include <intrin.h>
tanjent@gmail.com7e5c3632010-11-02 00:50:04 +000011#include <windows.h>
12
tanjent@gmail.comad4b3632010-11-05 01:20:58 +000013#pragma warning(disable : 4127) // "conditional expression is constant" in the if()s for avalanchetest
14
15bool g_testAll = false;
16
17/*
18bool g_testSanity = true;
19bool g_testSpeed = true;
20bool g_testDiff = true;
21bool g_testAvalanche = true;
22bool g_testCyclic = true;
23bool g_testSparse = true;
24bool g_testPermutation = true;
25bool g_testWindow = true;
26bool g_testText = true;
27bool g_testZeroes = true;
28bool g_testSeed = true;
29*/
30
31//*
32bool g_testSanity = false;
33bool g_testSpeed = false;
34bool g_testDiff = false;
35bool g_testAvalanche = false;
36bool g_testCyclic = false;
37bool g_testSparse = false;
38bool g_testPermutation = false;
39bool g_testWindow = false;
40bool g_testText = false;
41bool g_testZeroes = false;
42bool g_testSeed = false;
43//*/
44
tanjent@gmail.com31a9e8e2010-11-09 20:29:19 +000045
46int64_t g_hashcount = 0;
47int64_t g_bytecount = 0;
48
49void counterhash ( const void * , const int len, const uint32_t , void * out )
50{
51 g_hashcount++;
52 g_bytecount += len;
53
54 *(uint32_t*)out = rand_u32();
55}
56
57
tanjent@gmail.comad4b3632010-11-05 01:20:58 +000058//-----------------------------------------------------------------------------
59
60struct HashInfo
61{
62 pfHash hash;
63 int hashbits;
64 const char * name;
65 const char * desc;
66};
67
68HashInfo g_hashes[] =
69{
tanjent@gmail.com31a9e8e2010-11-09 20:29:19 +000070 { counterhash, 32, "count", "Counts how many times the hash function is called" },
tanjent@gmail.comad4b3632010-11-05 01:20:58 +000071 { randhash_32, 32, "rand32", "Random number generator, 32-bit" },
72 { randhash_64, 64, "rand64", "Random number generator, 64-bit" },
73 { randhash_128, 128, "rand128", "Random number generator, 128-bit" },
74
75 { crc32, 32, "crc32", "CRC-32" },
76 { DoNothingHash, 32, "donothing32", "Do-Nothing Function (only valid for speed test comparison)" },
77
78 { md5_32, 32, "md5_32a", "MD5, first 32 bits of result" },
79 { sha1_32a, 32, "sha1_32a", "SHA1, first 32 bits of result" },
80
81 { FNV, 32, "FNV", "Fowler-Noll-Vo hash, 32-bit" },
82 { lookup3_test, 32, "lookup3", "Bob Jenkins' lookup3" },
83 { SuperFastHash, 32, "superfast", "Paul Hsieh's SuperFastHash" },
84
85 // MurmurHash2
86
87 { MurmurHash2_test, 32, "Murmur2", "MurmurHash2 for x86, 32-bit" },
88 { MurmurHash2A_test, 32, "Murmur2A", "MurmurHash2A for x86, 32-bit" },
89 { MurmurHash64A_test, 64, "Murmur2B", "MurmurHash2 for x64, 64-bit" },
90 { MurmurHash64B_test, 64, "Murmur2C", "MurmurHash2 for x86, 64-bit" },
91
92 // MurmurHash3
93
94 { MurmurHash3_x86_32, 32, "Murmur3A", "MurmurHash3 for x86, 32-bit" },
95 { MurmurHash3_x86_64, 64, "Murmur3B", "MurmurHash3 for x86, 64-bit" },
96 { MurmurHash3_x86_128, 128, "Murmur3C", "MurmurHash3 for x86, 128-bit" },
97
98 { MurmurHash3_x64_32, 32, "Murmur3D", "MurmurHash3 for x64, 32-bit" },
99 { MurmurHash3_x64_64, 64, "Murmur3E", "MurmurHash3 for x64, 64-bit" },
100 { MurmurHash3_x64_128, 128, "Murmur3F", "MurmurHash3 for x64, 128-bit" },
101
102};
103
104HashInfo * findHash ( const char * name )
105{
106 for(int i = 0; i < sizeof(g_hashes) / sizeof(HashInfo); i++)
107 {
108 if(_stricmp(name,g_hashes[i].name) == 0) return &g_hashes[i];
109 }
110
111 return NULL;
112}
tanjent@gmail.com7e5c3632010-11-02 00:50:04 +0000113
114//----------------------------------------------------------------------------
115
116template < typename hashtype >
117void test ( hashfunc<hashtype> hash, const char * hashname )
118{
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000119 const int hashbits = sizeof(hashtype) * 8;
tanjent@gmail.com7e5c3632010-11-02 00:50:04 +0000120
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000121 printf("-------------------------------------------------------------------------------\n");
122 printf("--- Testing %s\n\n",hashname);
tanjent@gmail.com7e5c3632010-11-02 00:50:04 +0000123
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000124 //-----------------------------------------------------------------------------
125 // Sanity tests
tanjent@gmail.com7e5c3632010-11-02 00:50:04 +0000126
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000127 if(g_testSanity || g_testAll)
128 {
129 printf("[[[ Sanity Tests ]]]\n\n");
tanjent@gmail.com7e5c3632010-11-02 00:50:04 +0000130
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000131 QuickBrownFox(hash,hashbits);
132 SanityTest(hash,hashbits);
133 AlignmentTest(hash,hashbits);
134 AppendedZeroesTest(hash,hashbits);
135 printf("\n");
136 }
tanjent@gmail.com7e5c3632010-11-02 00:50:04 +0000137
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000138 //-----------------------------------------------------------------------------
139 // Speed tests
tanjent@gmail.com7e5c3632010-11-02 00:50:04 +0000140
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000141 if(g_testSpeed || g_testAll)
142 {
143 printf("[[[ Speed Tests ]]]\n\n");
tanjent@gmail.com7e5c3632010-11-02 00:50:04 +0000144
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000145 BulkSpeedTest(hash);
146 printf("\n");
tanjent@gmail.com7e5c3632010-11-02 00:50:04 +0000147
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000148 TinySpeedTest<hashtype,4>(hash);
149 TinySpeedTest<hashtype,8>(hash);
150 TinySpeedTest<hashtype,16>(hash);
151 TinySpeedTest<hashtype,32>(hash);
152 TinySpeedTest<hashtype,64>(hash);
153 TinySpeedTest<hashtype,128>(hash);
154 printf("\n");
155 }
tanjent@gmail.com7e5c3632010-11-02 00:50:04 +0000156
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000157 //-----------------------------------------------------------------------------
158 // Differential tests
tanjent@gmail.com7e5c3632010-11-02 00:50:04 +0000159
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000160 if(g_testDiff || g_testAll)
161 {
162 printf("[[[ Differential Tests ]]]\n\n");
tanjent@gmail.com7e5c3632010-11-02 00:50:04 +0000163
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000164 bool result = true;
165 bool dumpCollisions = false;
tanjent@gmail.com7e5c3632010-11-02 00:50:04 +0000166
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000167 result &= DiffTest< Blob<64>, hashtype >(hash,5,1000,dumpCollisions);
168 result &= DiffTest< Blob<128>, hashtype >(hash,4,1000,dumpCollisions);
169 result &= DiffTest< Blob<256>, hashtype >(hash,3,1000,dumpCollisions);
170
171 if(!result) printf("*********FAIL*********\n");
172 printf("\n");
173 }
174
175 //-----------------------------------------------------------------------------
176 // Avalanche tests.
177
178 // 2 million reps is enough to measure bias down to ~0.25%
179
180 if(g_testAvalanche || g_testAll)
181 {
182 printf("[[[ Avalanche Tests ]]]\n\n");
183
184 const int hashbits = sizeof(hashtype) * 8;
185 bool result = true;
186
187 result &= AvalancheTest< Blob<hashbits * 2>, hashtype > (hash,2000000);
188
189 // The bit independence test is slow and not particularly useful...
190 //result &= BicTest < Blob<hashbits * 2>, hashtype > ( hash, 1000000 );
191
192 if(!result) printf("*********FAIL*********\n");
193 printf("\n");
194 }
195
196 //-----------------------------------------------------------------------------
197 // Keyset 'Cyclic'
198
199 if(g_testCyclic || g_testAll)
200 {
201 printf("[[[ Keyset 'Cyclic' Tests ]]]\n\n");
202
203 bool result = true;
204 bool drawDiagram = false;
205
206 result &= CyclicKeyTest<hashtype>(hash,sizeof(hashtype)+0,8,10000000,drawDiagram);
207 result &= CyclicKeyTest<hashtype>(hash,sizeof(hashtype)+1,8,10000000,drawDiagram);
208 result &= CyclicKeyTest<hashtype>(hash,sizeof(hashtype)+2,8,10000000,drawDiagram);
209 result &= CyclicKeyTest<hashtype>(hash,sizeof(hashtype)+3,8,10000000,drawDiagram);
210 result &= CyclicKeyTest<hashtype>(hash,sizeof(hashtype)+4,8,10000000,drawDiagram);
211
212 if(!result) printf("*********FAIL*********\n");
213 printf("\n");
214 }
215
216 //-----------------------------------------------------------------------------
217 // Keyset 'Sparse'
218
219 if(g_testSparse || g_testAll)
220 {
221 printf("[[[ Keyset 'Sparse' Tests ]]]\n\n");
222
223 bool result = true;
224 bool drawDiagram = false;
225
226 result &= SparseKeyTest< 32,hashtype>(hash,6,true,true,true,drawDiagram);
227 result &= SparseKeyTest< 40,hashtype>(hash,6,true,true,true,drawDiagram);
228 result &= SparseKeyTest< 48,hashtype>(hash,5,true,true,true,drawDiagram);
229 result &= SparseKeyTest< 56,hashtype>(hash,5,true,true,true,drawDiagram);
230 result &= SparseKeyTest< 64,hashtype>(hash,5,true,true,true,drawDiagram);
231 result &= SparseKeyTest< 96,hashtype>(hash,4,true,true,true,drawDiagram);
232 result &= SparseKeyTest< 256,hashtype>(hash,3,true,true,true,drawDiagram);
233 result &= SparseKeyTest<2048,hashtype>(hash,2,true,true,true,drawDiagram);
234
235 if(!result) printf("*********FAIL*********\n");
236 printf("\n");
237 }
238
239 //-----------------------------------------------------------------------------
240 // Keyset 'Permutation'
241
242 if(g_testPermutation || g_testAll)
243 {
244 printf("[[[ Keyset 'Permutation' Tests ]]]\n\n");
245
246 bool result = true;
247 bool drawDiagram = false;
248
249 // This very sparse set of blocks is particularly hard for SuperFastHash
250
251 uint32_t blocks[] =
252 {
253 0x00000000,
254 0x00000001,
255 0x00000002,
256
257 0x00000400,
258 0x00008000,
259
260 0x00080000,
261 0x00200000,
262
263 0x20000000,
264 0x40000000,
265 0x80000000,
266 };
267
268 result &= PermutationKeyTest<hashtype>(hash,blocks,sizeof(blocks) / sizeof(uint32_t),true,true,drawDiagram);
269
270 if(!result) printf("*********FAIL*********\n");
271 printf("\n");
272 }
273
274 //-----------------------------------------------------------------------------
275 // Keyset 'Window'
276
277 // Skip distribution test for these - they're too easy to distribute well,
278 // and it generates a _lot_ of testing
279
280 if(g_testWindow || g_testAll)
281 {
282 printf("[[[ Keyset 'Window' Tests ]]]\n\n");
283
284 bool result = true;
285 bool testCollision = true;
286 bool testDistribution = false;
287 bool drawDiagram = false;
288
289 result &= WindowedKeyTest< Blob<hashbits*2>, hashtype > ( hash, 20, testCollision, testDistribution, drawDiagram );
290
291 if(!result) printf("*********FAIL*********\n");
292 printf("\n");
293 }
294
295 //-----------------------------------------------------------------------------
296 // Keyset 'Text'
297
298 if(g_testText || g_testAll)
299 {
300 printf("[[[ Keyset 'Text' Tests ]]]\n\n");
301
302 bool result = true;
303 bool drawDiagram = false;
304
305 const char * alnum = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
306
307 result &= TextKeyTest( hash, "Foo", alnum,4, "Bar", drawDiagram );
308 result &= TextKeyTest( hash, "FooBar", alnum,4, "", drawDiagram );
309 result &= TextKeyTest( hash, "", alnum,4, "FooBar", drawDiagram );
310
311 if(!result) printf("*********FAIL*********\n");
312 printf("\n");
313 }
314
315 //-----------------------------------------------------------------------------
316 // Keyset 'Zeroes'
317
318 if(g_testZeroes || g_testAll)
319 {
320 printf("[[[ Keyset 'Zeroes' Tests ]]]\n\n");
321
322 bool result = true;
323 bool drawDiagram = false;
324
325 result &= ZeroKeyTest<hashtype>( hash, drawDiagram );
326
327 if(!result) printf("*********FAIL*********\n");
328 printf("\n");
329 }
330
331 //-----------------------------------------------------------------------------
332 // Keyset 'Seed'
333
334 if(g_testSeed || g_testAll)
335 {
336 printf("[[[ Keyset 'Seed' Tests ]]]\n\n");
337
338 bool result = true;
339 bool drawDiagram = false;
340
341 result &= SeedTest<hashtype>( hash, 1000000, drawDiagram );
342
343 if(!result) printf("*********FAIL*********\n");
344 printf("\n");
345 }
tanjent@gmail.com7e5c3632010-11-02 00:50:04 +0000346}
347
348//-----------------------------------------------------------------------------
349
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000350void testHash ( const char * name )
351{
352 HashInfo * pInfo = findHash(name);
tanjent@gmail.com7e5c3632010-11-02 00:50:04 +0000353
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000354 if(pInfo == NULL)
355 {
356 printf("Invalid hash '%s' specified\n",name);
357 return;
358 }
359 else
360 {
361 if(pInfo->hashbits == 32)
362 {
363 test<uint32_t>( pInfo->hash, pInfo->desc );
364 }
365 else if(pInfo->hashbits == 64)
366 {
367 test<uint64_t>( pInfo->hash, pInfo->desc );
368 }
369 else if(pInfo->hashbits == 128)
370 {
371 test<uint128_t>( pInfo->hash, pInfo->desc );
372 }
373 else
374 {
375 printf("Invalid hash bit width %d for hash '%s'",pInfo->hashbits,pInfo->name);
376 }
377 }
378}
379//-----------------------------------------------------------------------------
380
381#pragma warning(disable : 4100)
382#pragma warning(disable : 4702)
383
384int main ( int argc, char ** argv )
tanjent@gmail.com7e5c3632010-11-02 00:50:04 +0000385{
386 SetProcessAffinityMask(GetCurrentProcess(),2);
387
388 int a = clock();
389
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000390 g_testAll = true;
391
392 //g_testWindow = true;
393 //g_testSanity = true;
394 //g_testSpeed = true;
395 //g_testAvalanche = true;
396 //g_testDiff = true;
397 //g_testSparse = true;
398 //g_testPermutation = true;
399
400 //testHash("rand32");
401 //testHash("rand64");
402 //testHash("rand128");
403
tanjent@gmail.com31a9e8e2010-11-09 20:29:19 +0000404 //testHash("donothing");
405
406 //testHash("count");
407
408 //printf("Called the hash function %I64d times, %I64d bytes hashed\n",g_hashcount,g_bytecount);
409
410 //testHash("crc32");
411
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000412 //testHash("fnv");
413 //testHash("superfast");
414 //testHash("lookup3");
415
416 //testHash("murmur2");
417 //testHash("murmur2B");
418 //testHash("murmur2C");
419
420 testHash("murmur3a");
421 testHash("murmur3b");
422 testHash("murmur3c");
423
424 testHash("murmur3d");
425 testHash("murmur3e");
426 testHash("murmur3f");
427
tanjent@gmail.com7e5c3632010-11-02 00:50:04 +0000428 //----------
429
tanjent@gmail.com7e5c3632010-11-02 00:50:04 +0000430 int b = clock();
431
432 printf("time %d\n",b-a);
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000433
434 return 0;
435}