blob: 25d3c898639be32169c1def7a2f5a640bb5abd10 [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
45//-----------------------------------------------------------------------------
46
47struct HashInfo
48{
49 pfHash hash;
50 int hashbits;
51 const char * name;
52 const char * desc;
53};
54
55HashInfo g_hashes[] =
56{
57 { randhash_32, 32, "rand32", "Random number generator, 32-bit" },
58 { randhash_64, 64, "rand64", "Random number generator, 64-bit" },
59 { randhash_128, 128, "rand128", "Random number generator, 128-bit" },
60
61 { crc32, 32, "crc32", "CRC-32" },
62 { DoNothingHash, 32, "donothing32", "Do-Nothing Function (only valid for speed test comparison)" },
63
64 { md5_32, 32, "md5_32a", "MD5, first 32 bits of result" },
65 { sha1_32a, 32, "sha1_32a", "SHA1, first 32 bits of result" },
66
67 { FNV, 32, "FNV", "Fowler-Noll-Vo hash, 32-bit" },
68 { lookup3_test, 32, "lookup3", "Bob Jenkins' lookup3" },
69 { SuperFastHash, 32, "superfast", "Paul Hsieh's SuperFastHash" },
70
71 // MurmurHash2
72
73 { MurmurHash2_test, 32, "Murmur2", "MurmurHash2 for x86, 32-bit" },
74 { MurmurHash2A_test, 32, "Murmur2A", "MurmurHash2A for x86, 32-bit" },
75 { MurmurHash64A_test, 64, "Murmur2B", "MurmurHash2 for x64, 64-bit" },
76 { MurmurHash64B_test, 64, "Murmur2C", "MurmurHash2 for x86, 64-bit" },
77
78 // MurmurHash3
79
80 { MurmurHash3_x86_32, 32, "Murmur3A", "MurmurHash3 for x86, 32-bit" },
81 { MurmurHash3_x86_64, 64, "Murmur3B", "MurmurHash3 for x86, 64-bit" },
82 { MurmurHash3_x86_128, 128, "Murmur3C", "MurmurHash3 for x86, 128-bit" },
83
84 { MurmurHash3_x64_32, 32, "Murmur3D", "MurmurHash3 for x64, 32-bit" },
85 { MurmurHash3_x64_64, 64, "Murmur3E", "MurmurHash3 for x64, 64-bit" },
86 { MurmurHash3_x64_128, 128, "Murmur3F", "MurmurHash3 for x64, 128-bit" },
87
88};
89
90HashInfo * findHash ( const char * name )
91{
92 for(int i = 0; i < sizeof(g_hashes) / sizeof(HashInfo); i++)
93 {
94 if(_stricmp(name,g_hashes[i].name) == 0) return &g_hashes[i];
95 }
96
97 return NULL;
98}
tanjent@gmail.com7e5c3632010-11-02 00:50:04 +000099
100//----------------------------------------------------------------------------
101
102template < typename hashtype >
103void test ( hashfunc<hashtype> hash, const char * hashname )
104{
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000105 const int hashbits = sizeof(hashtype) * 8;
tanjent@gmail.com7e5c3632010-11-02 00:50:04 +0000106
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000107 printf("-------------------------------------------------------------------------------\n");
108 printf("--- Testing %s\n\n",hashname);
tanjent@gmail.com7e5c3632010-11-02 00:50:04 +0000109
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000110 //-----------------------------------------------------------------------------
111 // Sanity tests
tanjent@gmail.com7e5c3632010-11-02 00:50:04 +0000112
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000113 if(g_testSanity || g_testAll)
114 {
115 printf("[[[ Sanity Tests ]]]\n\n");
tanjent@gmail.com7e5c3632010-11-02 00:50:04 +0000116
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000117 QuickBrownFox(hash,hashbits);
118 SanityTest(hash,hashbits);
119 AlignmentTest(hash,hashbits);
120 AppendedZeroesTest(hash,hashbits);
121 printf("\n");
122 }
tanjent@gmail.com7e5c3632010-11-02 00:50:04 +0000123
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000124 //-----------------------------------------------------------------------------
125 // Speed tests
tanjent@gmail.com7e5c3632010-11-02 00:50:04 +0000126
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000127 if(g_testSpeed || g_testAll)
128 {
129 printf("[[[ Speed Tests ]]]\n\n");
tanjent@gmail.com7e5c3632010-11-02 00:50:04 +0000130
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000131 BulkSpeedTest(hash);
132 printf("\n");
tanjent@gmail.com7e5c3632010-11-02 00:50:04 +0000133
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000134 TinySpeedTest<hashtype,4>(hash);
135 TinySpeedTest<hashtype,8>(hash);
136 TinySpeedTest<hashtype,16>(hash);
137 TinySpeedTest<hashtype,32>(hash);
138 TinySpeedTest<hashtype,64>(hash);
139 TinySpeedTest<hashtype,128>(hash);
140 printf("\n");
141 }
tanjent@gmail.com7e5c3632010-11-02 00:50:04 +0000142
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000143 //-----------------------------------------------------------------------------
144 // Differential tests
tanjent@gmail.com7e5c3632010-11-02 00:50:04 +0000145
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000146 if(g_testDiff || g_testAll)
147 {
148 printf("[[[ Differential Tests ]]]\n\n");
tanjent@gmail.com7e5c3632010-11-02 00:50:04 +0000149
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000150 bool result = true;
151 bool dumpCollisions = false;
tanjent@gmail.com7e5c3632010-11-02 00:50:04 +0000152
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000153 result &= DiffTest< Blob<64>, hashtype >(hash,5,1000,dumpCollisions);
154 result &= DiffTest< Blob<128>, hashtype >(hash,4,1000,dumpCollisions);
155 result &= DiffTest< Blob<256>, hashtype >(hash,3,1000,dumpCollisions);
156
157 if(!result) printf("*********FAIL*********\n");
158 printf("\n");
159 }
160
161 //-----------------------------------------------------------------------------
162 // Avalanche tests.
163
164 // 2 million reps is enough to measure bias down to ~0.25%
165
166 if(g_testAvalanche || g_testAll)
167 {
168 printf("[[[ Avalanche Tests ]]]\n\n");
169
170 const int hashbits = sizeof(hashtype) * 8;
171 bool result = true;
172
173 result &= AvalancheTest< Blob<hashbits * 2>, hashtype > (hash,2000000);
174
175 // The bit independence test is slow and not particularly useful...
176 //result &= BicTest < Blob<hashbits * 2>, hashtype > ( hash, 1000000 );
177
178 if(!result) printf("*********FAIL*********\n");
179 printf("\n");
180 }
181
182 //-----------------------------------------------------------------------------
183 // Keyset 'Cyclic'
184
185 if(g_testCyclic || g_testAll)
186 {
187 printf("[[[ Keyset 'Cyclic' Tests ]]]\n\n");
188
189 bool result = true;
190 bool drawDiagram = false;
191
192 result &= CyclicKeyTest<hashtype>(hash,sizeof(hashtype)+0,8,10000000,drawDiagram);
193 result &= CyclicKeyTest<hashtype>(hash,sizeof(hashtype)+1,8,10000000,drawDiagram);
194 result &= CyclicKeyTest<hashtype>(hash,sizeof(hashtype)+2,8,10000000,drawDiagram);
195 result &= CyclicKeyTest<hashtype>(hash,sizeof(hashtype)+3,8,10000000,drawDiagram);
196 result &= CyclicKeyTest<hashtype>(hash,sizeof(hashtype)+4,8,10000000,drawDiagram);
197
198 if(!result) printf("*********FAIL*********\n");
199 printf("\n");
200 }
201
202 //-----------------------------------------------------------------------------
203 // Keyset 'Sparse'
204
205 if(g_testSparse || g_testAll)
206 {
207 printf("[[[ Keyset 'Sparse' Tests ]]]\n\n");
208
209 bool result = true;
210 bool drawDiagram = false;
211
212 result &= SparseKeyTest< 32,hashtype>(hash,6,true,true,true,drawDiagram);
213 result &= SparseKeyTest< 40,hashtype>(hash,6,true,true,true,drawDiagram);
214 result &= SparseKeyTest< 48,hashtype>(hash,5,true,true,true,drawDiagram);
215 result &= SparseKeyTest< 56,hashtype>(hash,5,true,true,true,drawDiagram);
216 result &= SparseKeyTest< 64,hashtype>(hash,5,true,true,true,drawDiagram);
217 result &= SparseKeyTest< 96,hashtype>(hash,4,true,true,true,drawDiagram);
218 result &= SparseKeyTest< 256,hashtype>(hash,3,true,true,true,drawDiagram);
219 result &= SparseKeyTest<2048,hashtype>(hash,2,true,true,true,drawDiagram);
220
221 if(!result) printf("*********FAIL*********\n");
222 printf("\n");
223 }
224
225 //-----------------------------------------------------------------------------
226 // Keyset 'Permutation'
227
228 if(g_testPermutation || g_testAll)
229 {
230 printf("[[[ Keyset 'Permutation' Tests ]]]\n\n");
231
232 bool result = true;
233 bool drawDiagram = false;
234
235 // This very sparse set of blocks is particularly hard for SuperFastHash
236
237 uint32_t blocks[] =
238 {
239 0x00000000,
240 0x00000001,
241 0x00000002,
242
243 0x00000400,
244 0x00008000,
245
246 0x00080000,
247 0x00200000,
248
249 0x20000000,
250 0x40000000,
251 0x80000000,
252 };
253
254 result &= PermutationKeyTest<hashtype>(hash,blocks,sizeof(blocks) / sizeof(uint32_t),true,true,drawDiagram);
255
256 if(!result) printf("*********FAIL*********\n");
257 printf("\n");
258 }
259
260 //-----------------------------------------------------------------------------
261 // Keyset 'Window'
262
263 // Skip distribution test for these - they're too easy to distribute well,
264 // and it generates a _lot_ of testing
265
266 if(g_testWindow || g_testAll)
267 {
268 printf("[[[ Keyset 'Window' Tests ]]]\n\n");
269
270 bool result = true;
271 bool testCollision = true;
272 bool testDistribution = false;
273 bool drawDiagram = false;
274
275 result &= WindowedKeyTest< Blob<hashbits*2>, hashtype > ( hash, 20, testCollision, testDistribution, drawDiagram );
276
277 if(!result) printf("*********FAIL*********\n");
278 printf("\n");
279 }
280
281 //-----------------------------------------------------------------------------
282 // Keyset 'Text'
283
284 if(g_testText || g_testAll)
285 {
286 printf("[[[ Keyset 'Text' Tests ]]]\n\n");
287
288 bool result = true;
289 bool drawDiagram = false;
290
291 const char * alnum = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
292
293 result &= TextKeyTest( hash, "Foo", alnum,4, "Bar", drawDiagram );
294 result &= TextKeyTest( hash, "FooBar", alnum,4, "", drawDiagram );
295 result &= TextKeyTest( hash, "", alnum,4, "FooBar", drawDiagram );
296
297 if(!result) printf("*********FAIL*********\n");
298 printf("\n");
299 }
300
301 //-----------------------------------------------------------------------------
302 // Keyset 'Zeroes'
303
304 if(g_testZeroes || g_testAll)
305 {
306 printf("[[[ Keyset 'Zeroes' Tests ]]]\n\n");
307
308 bool result = true;
309 bool drawDiagram = false;
310
311 result &= ZeroKeyTest<hashtype>( hash, drawDiagram );
312
313 if(!result) printf("*********FAIL*********\n");
314 printf("\n");
315 }
316
317 //-----------------------------------------------------------------------------
318 // Keyset 'Seed'
319
320 if(g_testSeed || g_testAll)
321 {
322 printf("[[[ Keyset 'Seed' Tests ]]]\n\n");
323
324 bool result = true;
325 bool drawDiagram = false;
326
327 result &= SeedTest<hashtype>( hash, 1000000, drawDiagram );
328
329 if(!result) printf("*********FAIL*********\n");
330 printf("\n");
331 }
tanjent@gmail.com7e5c3632010-11-02 00:50:04 +0000332}
333
334//-----------------------------------------------------------------------------
335
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000336void testHash ( const char * name )
337{
338 HashInfo * pInfo = findHash(name);
tanjent@gmail.com7e5c3632010-11-02 00:50:04 +0000339
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000340 if(pInfo == NULL)
341 {
342 printf("Invalid hash '%s' specified\n",name);
343 return;
344 }
345 else
346 {
347 if(pInfo->hashbits == 32)
348 {
349 test<uint32_t>( pInfo->hash, pInfo->desc );
350 }
351 else if(pInfo->hashbits == 64)
352 {
353 test<uint64_t>( pInfo->hash, pInfo->desc );
354 }
355 else if(pInfo->hashbits == 128)
356 {
357 test<uint128_t>( pInfo->hash, pInfo->desc );
358 }
359 else
360 {
361 printf("Invalid hash bit width %d for hash '%s'",pInfo->hashbits,pInfo->name);
362 }
363 }
364}
365//-----------------------------------------------------------------------------
366
367#pragma warning(disable : 4100)
368#pragma warning(disable : 4702)
369
370int main ( int argc, char ** argv )
tanjent@gmail.com7e5c3632010-11-02 00:50:04 +0000371{
372 SetProcessAffinityMask(GetCurrentProcess(),2);
373
374 int a = clock();
375
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000376 g_testAll = true;
377
378 //g_testWindow = true;
379 //g_testSanity = true;
380 //g_testSpeed = true;
381 //g_testAvalanche = true;
382 //g_testDiff = true;
383 //g_testSparse = true;
384 //g_testPermutation = true;
385
386 //testHash("rand32");
387 //testHash("rand64");
388 //testHash("rand128");
389
390 //testHash("fnv");
391 //testHash("superfast");
392 //testHash("lookup3");
393
394 //testHash("murmur2");
395 //testHash("murmur2B");
396 //testHash("murmur2C");
397
398 testHash("murmur3a");
399 testHash("murmur3b");
400 testHash("murmur3c");
401
402 testHash("murmur3d");
403 testHash("murmur3e");
404 testHash("murmur3f");
405
tanjent@gmail.com7e5c3632010-11-02 00:50:04 +0000406 //----------
407
tanjent@gmail.com7e5c3632010-11-02 00:50:04 +0000408 int b = clock();
409
410 printf("time %d\n",b-a);
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000411
412 return 0;
413}