Cyan4973 / xxHash

Extremely fast non-cryptographic hash algorithm
http://www.xxhash.com/
Other
9.14k stars 777 forks source link

Feedback - Throwing 10x5 million short keys at XXH64, WYHASH and FNV1A-Pippip #275

Closed Sanmayce closed 4 years ago

Sanmayce commented 5 years ago

Hi Yann, wanted to share my experience with XXH64 (taken from xxHash-0.7.0.zip) with short keys.

First off, I wasn't able make the binary, had to comment the last line in xxhash.c:

//#include "xxh3.h"

With this I was able to produce the binary with Intel v19.0, so let the showdown begins:

Quickly tried latest XXH64, it seems it cannot ramp up in such a short distance as 128, but on 'Complete Shakespeare' it reaches for 10GB/s while WYHASH and Pippip cannot touch 7GB/s. Tried also to use the newest XXH3, but couldn't compile it.

However, the big surprise is at the very bottom, GCC by not unrolling proves superior.

E:\Lookuperorama.c_r5->quickbench.bat

E:\Lookuperorama.c_r5->Lookuperorama_ICC-v19.0_Pippip_64bit.exe key128.txt x 1 1 I

RAW Hashing Speed for key 128 bytes long = 10,729,253,981 10,720,268,006 10,729,253,981 10,738,255,033 10,720,268,006 | 10,738,255,033 BYTES-PER-SECOND

E:\Lookuperorama.c_r5->Lookuperorama_ICC-v19.0_WY_64bit.exe key128.txt x 1 1 I

RAW Hashing Speed for key 128 bytes long = 7,227,555,053 7,134,894,091 7,248,018,120 7,243,916,242 7,243,916,242 | 7,248,018,120 BYTES-PER-SECOND

E:\Lookuperorama.c_r5->Lookuperorama_ICC-V19.0_XXH64_64bit.exe key128.txt x 1 1 I

RAW Hashing Speed for key 128 bytes long = 6,467,913,087 6,474,456,246 6,103,958,035 5,890,473,999 6,040,585,181 | 6,474,456,246 BYTES-PER-SECOND

E:\Lookuperorama.c_r5->Lookuperorama_ICC-v19.0_Pippip_64bit.exe KAZE_www.gutenberg.org_ebooks_100.txt x 1 1 I

RAW Hashing Speed for key 5,784,758 bytes long = 6,025,789,583 6,032,072,992 6,032,072,992 6,032,072,992 6,032,072,992 | 6,032,072,992 BYTES-PER-SECOND
RAW Hashing Speed for keys 04 bytes long = 304,460,789 KEYS-PER-SECOND
RAW Hashing Speed for keys 06 bytes long = 156,344,675 KEYS-PER-SECOND
RAW Hashing Speed for keys 08 bytes long = 103,299,125 KEYS-PER-SECOND
RAW Hashing Speed for keys 10 bytes long = 74,163,448 KEYS-PER-SECOND
RAW Hashing Speed for keys 12 bytes long = 57,847,470 KEYS-PER-SECOND
RAW Hashing Speed for keys 14 bytes long = 47,030,447 KEYS-PER-SECOND
RAW Hashing Speed for keys 16 bytes long = 39,621,527 KEYS-PER-SECOND
RAW Hashing Speed for keys 18 bytes long = 33,245,637 KEYS-PER-SECOND
RAW Hashing Speed for keys 36 bytes long = 27,678,100 KEYS-PER-SECOND
RAW Hashing Speed for keys 64 bytes long = 23,138,780 KEYS-PER-SECOND

E:\Lookuperorama.c_r5->Lookuperorama_ICC-v19.0_WY_64bit.exe KAZE_www.gutenberg.org_ebooks_100.txt x 1 1 I

RAW Hashing Speed for key 5,784,758 bytes long = 6,742,142,191 6,757,894,859 6,765,798,830 6,765,798,830 6,757,894,859 | 6,765,798,830 BYTES-PER-SECOND
RAW Hashing Speed for keys 04 bytes long = 214,250,185 KEYS-PER-SECOND
RAW Hashing Speed for keys 06 bytes long = 101,486,894 KEYS-PER-SECOND
RAW Hashing Speed for keys 08 bytes long = 67,264,546 KEYS-PER-SECOND
RAW Hashing Speed for keys 10 bytes long = 49,023,296 KEYS-PER-SECOND
RAW Hashing Speed for keys 12 bytes long = 39,086,128 KEYS-PER-SECOND
RAW Hashing Speed for keys 14 bytes long = 31,959,917 KEYS-PER-SECOND
RAW Hashing Speed for keys 16 bytes long = 27,286,523 KEYS-PER-SECOND
RAW Hashing Speed for keys 18 bytes long = 23,046,776 KEYS-PER-SECOND
RAW Hashing Speed for keys 36 bytes long = 19,154,711 KEYS-PER-SECOND
RAW Hashing Speed for keys 64 bytes long = 15,634,310 KEYS-PER-SECOND

E:\Lookuperorama.c_r5->Lookuperorama_ICC-V19.0_XXH64_64bit.exe KAZE_www.gutenberg.org_ebooks_100.txt x 1 1 I

RAW Hashing Speed for key 5,784,758 bytes long = 10,792,458,955 10,792,458,955 10,853,204,502 10,832,880,149 10,853,204,502 | 10,853,204,502 BYTES-PER-SECOND
RAW Hashing Speed for keys 04 bytes long = 165,278,714 KEYS-PER-SECOND
RAW Hashing Speed for keys 06 bytes long = 75,126,662 KEYS-PER-SECOND
RAW Hashing Speed for keys 08 bytes long = 51,192,486 KEYS-PER-SECOND
RAW Hashing Speed for keys 10 bytes long = 36,154,681 KEYS-PER-SECOND
RAW Hashing Speed for keys 12 bytes long = 28,356,602 KEYS-PER-SECOND
RAW Hashing Speed for keys 14 bytes long = 22,249,019 KEYS-PER-SECOND
RAW Hashing Speed for keys 16 bytes long = 18,966,370 KEYS-PER-SECOND
RAW Hashing Speed for keys 18 bytes long = 16,024,213 KEYS-PER-SECOND
RAW Hashing Speed for keys 36 bytes long = 12,999,377 KEYS-PER-SECOND
RAW Hashing Speed for keys 64 bytes long = 10,752,221 KEYS-PER-SECOND

And for good measure, GCC 7.3.0 64bit amazes (failed to compile XXh64):

E:\Lookuperorama.c_r5->Lookuperorama_GCC-7.3.0_WY.exe KAZE_www.gutenberg.org_ebooks_100.txt x 1 1 I

RAW Hashing Speed for key 5,784,758 bytes long = 7,285,589,420 7,303,987,373 7,285,589,420 7,313,221,238 7,303,987,373 | 7,313,221,238 BYTES-PER-SECOND
RAW Hashing Speed for keys 04 bytes long = 214,250,185 KEYS-PER-SECOND
RAW Hashing Speed for keys 06 bytes long = 107,125,055 KEYS-PER-SECOND
RAW Hashing Speed for keys 08 bytes long = 70,545,743 KEYS-PER-SECOND
RAW Hashing Speed for keys 10 bytes long = 53,071,091 KEYS-PER-SECOND
RAW Hashing Speed for keys 12 bytes long = 42,534,904 KEYS-PER-SECOND
RAW Hashing Speed for keys 14 bytes long = 35,059,060 KEYS-PER-SECOND
RAW Hashing Speed for keys 16 bytes long = 29,818,262 KEYS-PER-SECOND
RAW Hashing Speed for keys 18 bytes long = 25,151,047 KEYS-PER-SECOND
RAW Hashing Speed for keys 36 bytes long = 21,189,461 KEYS-PER-SECOND
RAW Hashing Speed for keys 64 bytes long = 17,582,659 KEYS-PER-SECOND

E:\Lookuperorama.c_r5->Lookuperorama_GCC-7.3.0_Pippip.exe KAZE_www.gutenberg.org_ebooks_100.txt x 1 1 I

RAW Hashing Speed for key 5,784,758 bytes long = 6,019,519,250 6,025,789,583 6,025,789,583 6,038,369,519 6,025,789,583 | 6,038,369,519 BYTES-PER-SECOND
RAW Hashing Speed for keys 04 bytes long = 525,886,818 KEYS-PER-SECOND
RAW Hashing Speed for keys 06 bytes long = 251,511,000 KEYS-PER-SECOND
RAW Hashing Speed for keys 08 bytes long = 170,139,735 KEYS-PER-SECOND
RAW Hashing Speed for keys 10 bytes long = 128,549,977 KEYS-PER-SECOND
RAW Hashing Speed for keys 12 bytes long = 103,299,053 KEYS-PER-SECOND
RAW Hashing Speed for keys 14 bytes long = 87,647,651 KEYS-PER-SECOND
RAW Hashing Speed for keys 16 bytes long = 75,126,532 KEYS-PER-SECOND
RAW Hashing Speed for keys 18 bytes long = 63,568,582 KEYS-PER-SECOND
RAW Hashing Speed for keys 36 bytes long = 52,588,390 KEYS-PER-SECOND
RAW Hashing Speed for keys 64 bytes long = 42,534,522 KEYS-PER-SECOND

Are you kidding me, WYHASH is running faster with GCC than ICC, but the performance of Pippip is UNBELIEVABLE, ... 2GB/s hashing rate for QWORDs :P who would have thought GCC 7.3.0 was so awesome, to outperform latest Intel v19.0, with a margin?!

The benchmarking (C sources and binaries included) package is freely downloadable at: https://drive.google.com/file/d/1lrgE13ITsD0pxJ8UCk2qnry57K3kxSRJ/view?usp=sharing Regarding XXH3, I was unable to use it, please consider giving short usage notes in the future.

Cyan4973 commented 5 years ago

Regarding XXH3, I was unable to use it,

I recommend using the version v0.7.2, which cleans a few details which were annoying at integration time.

Sanmayce commented 5 years ago

Ugh, my browser on XP doesn't allow editing:

2GB/s hashing rate for QWORDs of course 2GB/s hashing rate for DWORDs

As for QWORDS, 8x170,139,735 =1.2GB/s

Cyan4973 commented 5 years ago

Btw, how are you compiling with gcc on Windows XP ?

Sanmayce commented 5 years ago

I'm sorry for the mess, the tests were run on i5-7200U with Windows 10, in that machine I have installed GCC 7.3.0 64bit and Intel v19.0, my browser is on XP 32bit, and from previous year github somehow depreciated many features!? I will try tomorrow again with v0.7.2...

Sanmayce commented 5 years ago

Now no commenting is needed, however, no idea why XXH64 is successfully compiled with ICC while giving errors with GCC!?

E:\Lookuperorama.c_r5-+>gcc -O3 -msse4.1 -fomit-frame-pointer Lookuperorama.c -o Lookuperorama_GCC_XXH64.exe -D_N_XMM -D_N_prefetch_4096 -D_N_alone -D_N_HIGH_PRIORITY -DHashInBITS=24 -DHashChunkSizeInBITS=24 -DRAMpoolInKB=5120 -DBtreeHEURISTIC -D_WIN32_ENVIRONMENT_ -DLongestLineInclusive=64 -D_N_XXH64
Lookuperorama.c: In function 'FNV1A_Hash_Totenschiff_v1':
Lookuperorama.c:1232:23: warning: integer constant is so large that it is unsigned
     uint64_t hash64 = 14695981039346656037;//2166136261;
                       ^~~~~~~~~~~~~~~~~~~~
Lookuperorama.c: In function 'FNV1A_Pippip':
Lookuperorama.c:1311:71: warning: integer constant is so large that it is unsigned
  const uint32_t PRIME = 591798841; uint32_t hash32; uint64_t hash64 = 14695981039346656037; const char *p = str;
                                                                       ^~~~~~~~~~~~~~~~~~~~
C:\Users\Kaze\AppData\Local\Temp\ccCow1e3.o:Lookuperorama.c:(.text+0x1233): undefined reference to `XXH64'
C:\Users\Kaze\AppData\Local\Temp\ccCow1e3.o:Lookuperorama.c:(.text+0x133f): undefined reference to `XXH64'
C:\Users\Kaze\AppData\Local\Temp\ccCow1e3.o:Lookuperorama.c:(.text+0x1622): undefined reference to `XXH64'
collect2.exe: error: ld returned 1 exit status

Later tonight will have few hours for digging, is XXH3 usage straightforward as XXH64 is?

For now, you can see the first revision being both SYNTHETIC and REAL-WORLD - it reports RAW (i.e. linear reading of adjacent keys without touching uncached RAM/SLOTS) hashing speed, plus, the heavy taxing search-n-insertion into B-trees and collisions reporting:

The full console log, on i7-3630QM @3.4GHz turbo: https://drive.google.com/file/d/1q65Guw0fmSgK24qwvQNa54LBJ3o-PNNT/view?usp=sharing

The latest package, Lookuperorama.c_r5-+.zip (14,756,770 bytes): https://drive.google.com/file/d/1ku-SP9ojeL1ZwOpzRFUABzXzs7WDhTCL/view?usp=sharing

And giving a quick roster:

For 'Complete Shakespeare' (5,784,758 bytes) and 10 hash-tables 23bit each, ICC v19.0:

Hasher        | Collisions | Synthetic/Taxed Hashing Speed for keys 64 bytes long |
-----------------------------------------------------------------------------------
FNV1A-Pippip  |  9,090,483 | 19,218,255 KEYS-PER-SECOND / 004,616,675 Keys/s      |
WYHASH        |  9,092,905 | 12,360,459 KEYS-PER-SECOND / 004,432,716 Keys/s      |
XXH64         |  9,093,643 |  9,390,738 KEYS-PER-SECOND / 004,470,397 Keys/s      |
-----------------------------------------------------------------------------------

For '1001 Nights' (15,583,440 bytes) and 10 hash-tables 24bit each, ICC v19.0:

Hasher        | Collisions | Synthetic/Taxed Hashing Speed for keys 64 bytes long |
-----------------------------------------------------------------------------------
FNV1A-Pippip  | 23,738,813 | 19,601,732 KEYS-PER-SECOND / 004,132,425 Keys/s      |
WYHASH        | 23,738,215 | 12,536,908 KEYS-PER-SECOND / 003,971,298 Keys/s      |
XXH64         | 23,737,218 |  9,513,661 KEYS-PER-SECOND / 004,013,231 Keys/s      |
-----------------------------------------------------------------------------------

Note1: Collisions are cumulative for all the 10 hash-tables. Note2: 'Taxed' means it is polluted with many random/uncached RAM accesses.

Wanna refine 'Lookuperorama' in the future, at the moment it reports UNSTABLE speed results for order 4, don't know what causes it...

Sanmayce commented 5 years ago

Now no commenting is needed, however, no idea why XXH64 is successfully compiled with ICC while giving errors with GCC!?

Dummy me, just saw I forgot to add xxhash.c for GCC:

Later tonight will fix it.

easyaspi314 commented 5 years ago

my browser is on XP 32bit, and from previous year github somehow depreciated many features!?

Um.

*screams inside*

Dummy me

Yes, dummy you.

Either:

Later tonight will fix it.

Yes, that is a good idea!

Cyan4973 commented 5 years ago

is XXH3 usage straightforward as XXH64 is?

Invoke XXH3_64bits(), it's about the same as XXH64(), with the minor difference that it doesn't need a seed argument.

easyaspi314 commented 5 years ago

For clarification, here is a summary of the single-shot API (with the types and macros removed):

// Unseeded. Faster, but only safe on random inputs 
uint64_t XXH3_64bits(const void *input, size_t len);

// Takes a 64-bit seed.
uint64_t XXH3_64bits_withSeed(const void *input, size_t len, uint64_t seed);

// Takes a buffer of at least 136 bytes, preferably 192 bytes
uint64_t XXH3_64bits_withSecret(const void *input, size_t len, const void *secret, size_t secretSize);

// The 128-bit hashes have the same parameters, but they return this struct:

typedef struct {
    uint64_t low64;
    uint64_t high64;
} XXH128_hash_t;

// Unseeded. Faster, but only safe on random inputs 
XXH128_hash_t XXH3_128bits(const void *input, size_t len);

// Takes a 64-bit seed.
XXH128_hash_t XXH3_128bits_withSeed(const void *input, size_t len, uint64_t seed);

// Takes a buffer of at least 136 bytes, preferably 192 bytes
XXH128_hash_t XXH3_128bits_withSecret(const void *input, size_t len, const void *secret, size_t secretSize);
Sanmayce commented 5 years ago

Thanks, v0.7.2 compiles successfully both with GCC and ICC.

The full console log, on i7-3630QM @3.4GHz turbo: https://drive.google.com/file/d/1q65Guw0fmSgK24qwvQNa54LBJ3o-PNNT/view?usp=sharing

The latest package, Lookuperorama.c_r5-++.zip (15,040,647 bytes): https://drive.google.com/file/d/1891WiOzBYFO1OQdl9luNuigEHu01A_aq/view?usp=sharing

And giving a quick roster (data taken from the 1st link):

For 'Complete Shakespeare' (5,784,758 bytes) and 10 hash-tables 23bit each, ICC v19.0:

Hasher        | Collisions | Synthetic/Taxed Hashing Speed for keys 64 bytes long |
-----------------------------------------------------------------------------------
FNV1A-Pippip  |  9,090,483 | 19,218,255 KEYS-PER-SECOND / 004,616,675 Keys/s      |
WYHASH        |  9,092,905 | 12,360,459 KEYS-PER-SECOND / 004,432,716 Keys/s      |
XXH64         |  9,093,643 |  9,390,738 KEYS-PER-SECOND / 004,470,397 Keys/s      |
XXH3          |  9,097,678 | 16,433,792 KEYS-PER-SECOND / 004,646,341 Keys/s      |
-----------------------------------------------------------------------------------

XXH3 outspeeds 'Pippip' in Taxed Hashing Speed, hm, should continue benchmarking with bigger files... but 16GB are needed already, still I haven't written the new revision in which only non-unique keys are gonna be inserted into B-trees - it will use much less memory...

For '1001 Nights' (15,583,440 bytes) and 10 hash-tables 24bit each, ICC v19.0:

Hasher        | Collisions | Synthetic/Taxed Hashing Speed for keys 64 bytes long |
-----------------------------------------------------------------------------------
FNV1A-Pippip  | 23,738,813 | 19,601,732 KEYS-PER-SECOND / 004,132,425 Keys/s      |
WYHASH        | 23,738,215 | 12,536,908 KEYS-PER-SECOND / 003,971,298 Keys/s      |
XXH64         | 23,737,218 |  9,513,661 KEYS-PER-SECOND / 004,013,231 Keys/s      |
XXH3          | 23,735,377 | 16,720,361 KEYS-PER-SECOND / 004,120,406 Keys/s      |
-----------------------------------------------------------------------------------

And the GCC results for XXH3 and 'Pippip':

F:\Lookuperorama.c_r5-+>Lookuperorama_GCC-7.3.0_Pippip_64bit.exe "Arabian_Nights_complete.html" x 24 7500 i

RAW Hashing Speed for key 15,583,440 bytes long = 6,600,355,781 6,691,043,366 6,645,390,191 6,431,465,125 6,228,393,285 | 6,691,043,366 BYTES-PER-SECOND
RAW Hashing Speed for keys 04 bytes long = 916,672,764 KEYS-PER-SECOND
RAW Hashing Speed for keys 06 bytes long = 324,654,895 KEYS-PER-SECOND
RAW Hashing Speed for keys 08 bytes long = 197,258,645 KEYS-PER-SECOND
RAW Hashing Speed for keys 10 bytes long = 140,391,270 KEYS-PER-SECOND
RAW Hashing Speed for keys 12 bytes long = 99,257,509 KEYS-PER-SECOND
RAW Hashing Speed for keys 14 bytes long = 82,451,994 KEYS-PER-SECOND
RAW Hashing Speed for keys 16 bytes long = 70,833,750 KEYS-PER-SECOND
RAW Hashing Speed for keys 18 bytes long = 58,364,880 KEYS-PER-SECOND
RAW Hashing Speed for keys 36 bytes long = 45,169,289 KEYS-PER-SECOND
RAW Hashing Speed for keys 64 bytes long = 36,840,134 KEYS-PER-SECOND
Leprechaun: Inserting keys/BBs of order 004 into B-trees, free RAM in B-tree pool is 00,007,500 MB; Pass #001 of 1 ... DONE; 00,000,185,110 B-trees have been rooted so far; HashtableS_Utilization = 000%; Keys/s = 012,456,784
Leprechaun: Inserting keys/BBs of order 006 into B-trees, free RAM in B-tree pool is 00,007,491 MB; Pass #001 of 1 ... DONE; 00,001,330,364 B-trees have been rooted so far; HashtableS_Utilization = 000%; Keys/s = 007,492,036
Leprechaun: Inserting keys/BBs of order 008 into B-trees, free RAM in B-tree pool is 00,007,432 MB; Pass #001 of 1 ... DONE; 00,004,317,931 B-trees have been rooted so far; HashtableS_Utilization = 002%; Keys/s = 006,645,387
Leprechaun: Inserting keys/BBs of order 010 into B-trees, free RAM in B-tree pool is 00,007,264 MB; Pass #001 of 1 ... DONE; 00,009,402,389 B-trees have been rooted so far; HashtableS_Utilization = 005%; Keys/s = 005,664,642
Leprechaun: Inserting keys/BBs of order 012 into B-trees, free RAM in B-tree pool is 00,006,952 MB; Pass #001 of 1 ... DONE; 00,016,178,252 B-trees have been rooted so far; HashtableS_Utilization = 009%; Keys/s = 005,248,713
Leprechaun: Inserting keys/BBs of order 014 into B-trees, free RAM in B-tree pool is 00,006,492 MB; Pass #001 of 1 ... DONE; 00,024,085,199 B-trees have been rooted so far; HashtableS_Utilization = 014%; Keys/s = 004,886,618
Leprechaun: Inserting keys/BBs of order 016 into B-trees, free RAM in B-tree pool is 00,005,903 MB; Pass #001 of 1 ... DONE; 00,032,694,767 B-trees have been rooted so far; HashtableS_Utilization = 019%; Keys/s = 004,636,544
Leprechaun: Inserting keys/BBs of order 018 into B-trees, free RAM in B-tree pool is 00,005,208 MB; Pass #001 of 1 ... DONE; 00,041,744,572 B-trees have been rooted so far; HashtableS_Utilization = 024%; Keys/s = 004,594,169
Leprechaun: Inserting keys/BBs of order 036 into B-trees, free RAM in B-tree pool is 00,004,424 MB; Pass #001 of 1 ... DONE; 00,051,646,708 B-trees have been rooted so far; HashtableS_Utilization = 030%; Keys/s = 003,972,318
Leprechaun: Inserting keys/BBs of order 064 into B-trees, free RAM in B-tree pool is 00,003,120 MB; Pass #001 of 1 ... DONE; 00,061,668,508 B-trees have been rooted so far; HashtableS_Utilization = 036%; Keys/s = 003,613,117

F:\Lookuperorama.c_r5-+>Lookuperorama_GCC-7.3.0_XXH3_64bit.exe "Arabian_Nights_complete.html" x 24 7500 i

RAW Hashing Speed for key 15,583,440 bytes long = 12,456,786,570 13,285,115,089 12,618,170,040 10,493,898,989 13,285,115,089 | 13,285,115,089 BYTES-PER-SECOND
RAW Hashing Speed for keys 04 bytes long = 247,356,142 KEYS-PER-SECOND
RAW Hashing Speed for keys 06 bytes long = 123,678,055 KEYS-PER-SECOND
RAW Hashing Speed for keys 08 bytes long = 76,389,377 KEYS-PER-SECOND
RAW Hashing Speed for keys 10 bytes long = 58,584,327 KEYS-PER-SECOND
RAW Hashing Speed for keys 12 bytes long = 49,787,313 KEYS-PER-SECOND
RAW Hashing Speed for keys 14 bytes long = 41,445,284 KEYS-PER-SECOND
RAW Hashing Speed for keys 16 bytes long = 35,578,595 KEYS-PER-SECOND
RAW Hashing Speed for keys 18 bytes long = 30,200,432 KEYS-PER-SECOND
RAW Hashing Speed for keys 36 bytes long = 24,311,084 KEYS-PER-SECOND
RAW Hashing Speed for keys 64 bytes long = 20,750,169 KEYS-PER-SECOND
Leprechaun: Inserting keys/BBs of order 004 into B-trees, free RAM in B-tree pool is 00,007,500 MB; Pass #001 of 1 ... DONE; 00,000,185,057 B-trees have been rooted so far; HashtableS_Utilization = 000%; Keys/s = 012,005,729
Leprechaun: Inserting keys/BBs of order 006 into B-trees, free RAM in B-tree pool is 00,007,491 MB; Pass #001 of 1 ... DONE; 00,001,330,053 B-trees have been rooted so far; HashtableS_Utilization = 000%; Keys/s = 007,275,179
Leprechaun: Inserting keys/BBs of order 008 into B-trees, free RAM in B-tree pool is 00,007,432 MB; Pass #001 of 1 ... DONE; 00,004,317,346 B-trees have been rooted so far; HashtableS_Utilization = 002%; Keys/s = 006,514,813
Leprechaun: Inserting keys/BBs of order 010 into B-trees, free RAM in B-tree pool is 00,007,264 MB; Pass #001 of 1 ... DONE; 00,009,402,328 B-trees have been rooted so far; HashtableS_Utilization = 005%; Keys/s = 005,569,489
Leprechaun: Inserting keys/BBs of order 012 into B-trees, free RAM in B-tree pool is 00,006,952 MB; Pass #001 of 1 ... DONE; 00,016,180,232 B-trees have been rooted so far; HashtableS_Utilization = 009%; Keys/s = 005,009,138
Leprechaun: Inserting keys/BBs of order 014 into B-trees, free RAM in B-tree pool is 00,006,492 MB; Pass #001 of 1 ... DONE; 00,024,088,581 B-trees have been rooted so far; HashtableS_Utilization = 014%; Keys/s = 004,769,950
Leprechaun: Inserting keys/BBs of order 016 into B-trees, free RAM in B-tree pool is 00,005,903 MB; Pass #001 of 1 ... DONE; 00,032,699,243 B-trees have been rooted so far; HashtableS_Utilization = 019%; Keys/s = 005,165,205
Leprechaun: Inserting keys/BBs of order 018 into B-trees, free RAM in B-tree pool is 00,005,208 MB; Pass #001 of 1 ... DONE; 00,041,747,461 B-trees have been rooted so far; HashtableS_Utilization = 024%; Keys/s = 004,511,703
Leprechaun: Inserting keys/BBs of order 036 into B-trees, free RAM in B-tree pool is 00,004,424 MB; Pass #001 of 1 ... DONE; 00,051,652,391 B-trees have been rooted so far; HashtableS_Utilization = 030%; Keys/s = 003,941,174
Leprechaun: Inserting keys/BBs of order 064 into B-trees, free RAM in B-tree pool is 00,003,120 MB; Pass #001 of 1 ... DONE; 00,061,671,944 B-trees have been rooted so far; HashtableS_Utilization = 036%; Keys/s = 003,561,100

Still have no idea why GCC is so much faster in SYNTHETIC linear raw hashing ... anyone?

No time to make more informative tables, very tired eyes.

@easyaspi314 Love Windows XP, love Christopher Walken with its "You're Talkin To My Guy All Wrong, it's the wrong tone, you do it again, and I'll stab ya in the face with a soldering iron." https://www.youtube.com/watch?v=i2lA7KeO1dg

Seriously, security is not my forte, at all... off-topicness aside, do you have any ideas how to benchmark in a more non-dummy way than mine?

Cyan4973 commented 5 years ago

The reported speed difference, between for example 4, 6 and 8 bytes keys, look way too large in my opinion. Not sure what is going on, but it does not feel correct.

Sanmayce commented 5 years ago

Fully agree, but the codepath is the same for all hashers, it puzzles me, really wanna find the cause.

In next days will look up the .s file generated by GCC...

Sanmayce commented 5 years ago

A shameful bug (a displaced clock()) caused all the lost time, please excuse me.

This is the actual fragment reporting stats below:

// [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ BENCHMARKING , STAGE #2
for (jj=0; jj< MatchLensNUM; jj++) {
    BenchSpeedMAX = 0; Slot = 0;
    wrdlen=MatchLens[jj];
        clocksA = clock();
        while (clocksA == clock());
        clocksA = clock();
    for (BuildingBlocksSTRIDE=0; BuildingBlocksSTRIDE < size_inLINESIXFOUR-MatchLens[jj]+1; BuildingBlocksSTRIDE++) {
#ifdef _N_WY
    Slot += (uint32_t)(wyhash((SourceBlock+BuildingBlocksSTRIDE), wrdlen, 0));
#endif
#ifdef _N_Pippip
    Slot += FNV1A_Pippip((SourceBlock+BuildingBlocksSTRIDE), wrdlen);
#endif
#ifdef _N_XXH64
    Slot += (uint32_t)(XXH64((SourceBlock+BuildingBlocksSTRIDE), wrdlen, 0));
#endif
#ifdef _N_XXH3
    Slot += (uint32_t)(XXH3_64bits((SourceBlock+BuildingBlocksSTRIDE), wrdlen));
#endif
    }
        printf("Dummy usage, %d.\n", Slot); // Dummy, to avoid compiler seeing it is not used       
        clocksB = clock();
        BenchSpeed = (((double)CLOCKS_PER_SEC*(size_inLINESIXFOUR-MatchLens[jj]+1)/(double)(clocksB - clocksA + 1))) * 1;
        if (BenchSpeedMAX < BenchSpeed) BenchSpeedMAX = BenchSpeed;
        printf( "RAW Hashing Speed for keys %s bytes long = %s KEYS-PER-SECOND; all in %d clocks\n", _ui64toaKAZEzerocomma(wrdlen, llTOaDigits2, 10)+(26-2), _ui64toaKAZEcomma(BenchSpeedMAX, llTOaDigits3, 10), clocksB - clocksA + 1);

}
// ]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] BENCHMARKING, STAGE #2

Now the fix is uploaded at:

Lookuperorama.c_r5+.zip (15,046,841 bytes) https://drive.google.com/file/d/1BAX6AC8u77kAZozHwTXUnRjhpUWhlkx7/view?usp=sharing

A quick run shows:

On i7-3630QM:

F:\Lookuperorama.c_r5+>Lookuperorama_GCC-7.3.0_Pippip_64bit.exe "Arabian_Nights_complete.html" x 24 7500 i

RAW Hashing Speed for key 15,583,440 bytes long = 6,268,479,485 6,193,736,089 6,558,686,868 6,271,002,012 6,645,390,191 | 6,645,390,191 BYTES-PER-SECOND
Dummy usage, 1093508219.
RAW Hashing Speed for keys 04 bytes long = 916,672,764 KEYS-PER-SECOND; all in 17 clocks
Dummy usage, -623388629.
RAW Hashing Speed for keys 06 bytes long = 916,672,647 KEYS-PER-SECOND; all in 17 clocks
Dummy usage, -1940803710.
RAW Hashing Speed for keys 08 bytes long = 973,964,562 KEYS-PER-SECOND; all in 16 clocks
Dummy usage, -1976170828.
RAW Hashing Speed for keys 10 bytes long = 486,982,218 KEYS-PER-SECOND; all in 32 clocks
Dummy usage, -1229134182.
RAW Hashing Speed for keys 12 bytes long = 486,982,156 KEYS-PER-SECOND; all in 32 clocks
Dummy usage, 2019260656.
RAW Hashing Speed for keys 14 bytes long = 486,982,093 KEYS-PER-SECOND; all in 32 clocks
Dummy usage, 775166885.
RAW Hashing Speed for keys 16 bytes long = 486,982,031 KEYS-PER-SECOND; all in 32 clocks
Dummy usage, 436757720.
RAW Hashing Speed for keys 18 bytes long = 324,654,645 KEYS-PER-SECOND; all in 48 clocks
Dummy usage, 364787154.
RAW Hashing Speed for keys 36 bytes long = 243,490,703 KEYS-PER-SECOND; all in 64 clocks
Dummy usage, -1857844813.
RAW Hashing Speed for keys 64 bytes long = 197,257,936 KEYS-PER-SECOND; all in 79 clocks
...

F:\Lookuperorama.c_r5+>Lookuperorama_GCC-7.3.0_XXH3_64bit.exe "Arabian_Nights_complete.html" x 24 7500 i

RAW Hashing Speed for key 15,583,440 bytes long = 12,773,311,475 13,645,744,308 13,645,744,308 13,645,744,308 11,458,411,764 | 13,645,744,308 BYTES-PER-SECOND
Dummy usage, 194524106.
RAW Hashing Speed for keys 04 bytes long = 164,036,178 KEYS-PER-SECOND; all in 95 clocks
Dummy usage, 1869422273.
RAW Hashing Speed for keys 06 bytes long = 164,036,157 KEYS-PER-SECOND; all in 95 clocks
Dummy usage, -595401294.
RAW Hashing Speed for keys 08 bytes long = 165,781,202 KEYS-PER-SECOND; all in 94 clocks
Dummy usage, -244025881.
RAW Hashing Speed for keys 10 bytes long = 197,258,620 KEYS-PER-SECOND; all in 79 clocks
Dummy usage, 630624269.
RAW Hashing Speed for keys 12 bytes long = 197,258,594 KEYS-PER-SECOND; all in 79 clocks
Dummy usage, 1682824392.
RAW Hashing Speed for keys 14 bytes long = 194,792,837 KEYS-PER-SECOND; all in 80 clocks
Dummy usage, -440334440.
RAW Hashing Speed for keys 16 bytes long = 324,654,687 KEYS-PER-SECOND; all in 48 clocks
Dummy usage, -1793479385.
RAW Hashing Speed for keys 18 bytes long = 197,258,518 KEYS-PER-SECOND; all in 79 clocks
Dummy usage, -1109318185.
RAW Hashing Speed for keys 36 bytes long = 140,391,036 KEYS-PER-SECOND; all in 111 clocks
Dummy usage, -456483296.
RAW Hashing Speed for keys 64 bytes long = 140,390,783 KEYS-PER-SECOND; all in 111 clocks
...

F:\Lookuperorama.c_r5+>Lookuperorama_GCC-7.3.0_XXH64_64bit.exe "Arabian_Nights_complete.html" x 24 7500 i

RAW Hashing Speed for key 15,583,440 bytes long = 8,899,737,292 11,586,200,743 11,725,688,487 11,725,688,487 11,725,688,487 | 11,725,688,487 BYTES-PER-SECOND
Dummy usage, 713312125.
RAW Hashing Speed for keys 04 bytes long = 243,491,203 KEYS-PER-SECOND; all in 64 clocks
Dummy usage, 1996479145.
RAW Hashing Speed for keys 06 bytes long = 194,792,937 KEYS-PER-SECOND; all in 80 clocks
Dummy usage, -853007940.
RAW Hashing Speed for keys 08 bytes long = 197,258,645 KEYS-PER-SECOND; all in 79 clocks
Dummy usage, -1163048755.
RAW Hashing Speed for keys 10 bytes long = 164,036,115 KEYS-PER-SECOND; all in 95 clocks
Dummy usage, -1827505444.
RAW Hashing Speed for keys 12 bytes long = 164,036,094 KEYS-PER-SECOND; all in 95 clocks
Dummy usage, 772663914.
RAW Hashing Speed for keys 14 bytes long = 141,667,518 KEYS-PER-SECOND; all in 110 clocks
Dummy usage, -1046118434.
RAW Hashing Speed for keys 16 bytes long = 164,036,052 KEYS-PER-SECOND; all in 95 clocks
Dummy usage, -1486821745.
RAW Hashing Speed for keys 18 bytes long = 123,677,960 KEYS-PER-SECOND; all in 126 clocks
Dummy usage, 1056896294.
RAW Hashing Speed for keys 36 bytes long = 76,389,240 KEYS-PER-SECOND; all in 204 clocks
Dummy usage, 49108245.
RAW Hashing Speed for keys 64 bytes long = 66,312,242 KEYS-PER-SECOND; all in 235 clocks
...

F:\Lookuperorama.c_r5+>Lookuperorama_GCC-7.3.0_WY_64bit.exe "Arabian_Nights_complete.html" x 24 7500 i

RAW Hashing Speed for key 15,583,440 bytes long = 6,691,043,366 7,669,015,748 7,850,599,496 7,850,599,496 7,850,599,496 | 7,850,599,496 BYTES-PER-SECOND
Dummy usage, 803620614.
RAW Hashing Speed for keys 04 bytes long = 164,036,178 KEYS-PER-SECOND; all in 95 clocks
Dummy usage, -371125780.
RAW Hashing Speed for keys 06 bytes long = 164,036,157 KEYS-PER-SECOND; all in 95 clocks
Dummy usage, -623528025.
RAW Hashing Speed for keys 08 bytes long = 165,781,202 KEYS-PER-SECOND; all in 94 clocks
Dummy usage, -1655635255.
RAW Hashing Speed for keys 10 bytes long = 197,258,620 KEYS-PER-SECOND; all in 79 clocks
Dummy usage, -758114859.
RAW Hashing Speed for keys 12 bytes long = 164,036,094 KEYS-PER-SECOND; all in 95 clocks
Dummy usage, -2146149880.
RAW Hashing Speed for keys 14 bytes long = 164,036,073 KEYS-PER-SECOND; all in 95 clocks
Dummy usage, 1777476378.
RAW Hashing Speed for keys 16 bytes long = 197,258,544 KEYS-PER-SECOND; all in 79 clocks
Dummy usage, 196963834.
RAW Hashing Speed for keys 18 bytes long = 164,036,031 KEYS-PER-SECOND; all in 95 clocks
Dummy usage, 1520241591.
RAW Hashing Speed for keys 36 bytes long = 141,667,318 KEYS-PER-SECOND; all in 110 clocks
Dummy usage, -2117660594.
RAW Hashing Speed for keys 64 bytes long = 99,257,178 KEYS-PER-SECOND; all in 157 clocks
...

On i5-7200u:

E:\Lookuperorama.c_r5+>Lookuperorama_GCC-7.3.0_Pippip_64bit.exe Arabian_Nights_complete.html x 1 1 I

RAW Hashing Speed for key 15,583,440 bytes long = 6,002,865,947 6,009,811,029 6,007,494,217 6,007,494,217 6,007,494,217 | 6,009,811,029 BYTES-PER-SECOND
Dummy usage, 1093508219.
RAW Hashing Speed for keys 04 bytes long = 519,447,900 KEYS-PER-SECOND; all in 30 clocks
Dummy usage, -623388629.
RAW Hashing Speed for keys 06 bytes long = 502,691,451 KEYS-PER-SECOND; all in 31 clocks
Dummy usage, -1940803710.
RAW Hashing Speed for keys 08 bytes long = 502,691,387 KEYS-PER-SECOND; all in 31 clocks
Dummy usage, -1976170828.
RAW Hashing Speed for keys 10 bytes long = 537,359,689 KEYS-PER-SECOND; all in 29 clocks
Dummy usage, -1229134182.
RAW Hashing Speed for keys 12 bytes long = 519,447,633 KEYS-PER-SECOND; all in 30 clocks
Dummy usage, 2019260656.
RAW Hashing Speed for keys 14 bytes long = 537,359,551 KEYS-PER-SECOND; all in 29 clocks
Dummy usage, 775166885.
RAW Hashing Speed for keys 16 bytes long = 537,359,482 KEYS-PER-SECOND; all in 29 clocks
Dummy usage, 436757720.
RAW Hashing Speed for keys 18 bytes long = 410,090,078 KEYS-PER-SECOND; all in 38 clocks
Dummy usage, 364787154.
RAW Hashing Speed for keys 36 bytes long = 305,556,960 KEYS-PER-SECOND; all in 51 clocks
Dummy usage, -1857844813.
RAW Hashing Speed for keys 64 bytes long = 247,355,190 KEYS-PER-SECOND; all in 63 clocks
...

E:\Lookuperorama.c_r5+>Lookuperorama_GCC-7.3.0_xxh3_64bit.exe Arabian_Nights_complete.html x 1 1 I

RAW Hashing Speed for key 15,583,440 bytes long = 13,669,684,210 13,778,461,538 13,645,744,308 13,669,684,210 13,717,816,901 | 13,778,461,538 BYTES-PER-SECOND
Dummy usage, 194524106.
RAW Hashing Speed for keys 04 bytes long = 251,345,758 KEYS-PER-SECOND; all in 62 clocks
Dummy usage, 1869422273.
RAW Hashing Speed for keys 06 bytes long = 251,345,725 KEYS-PER-SECOND; all in 62 clocks
Dummy usage, -595401294.
RAW Hashing Speed for keys 08 bytes long = 251,345,693 KEYS-PER-SECOND; all in 62 clocks
Dummy usage, -244025881.
RAW Hashing Speed for keys 10 bytes long = 278,275,553 KEYS-PER-SECOND; all in 56 clocks
Dummy usage, 630624269.
RAW Hashing Speed for keys 12 bytes long = 283,335,072 KEYS-PER-SECOND; all in 55 clocks
Dummy usage, 1682824392.
RAW Hashing Speed for keys 14 bytes long = 283,335,036 KEYS-PER-SECOND; all in 55 clocks
Dummy usage, -440334440.
RAW Hashing Speed for keys 16 bytes long = 283,335,000 KEYS-PER-SECOND; all in 55 clocks
Dummy usage, -1793479385.
RAW Hashing Speed for keys 18 bytes long = 213,471,547 KEYS-PER-SECOND; all in 73 clocks
Dummy usage, -1109318185.
RAW Hashing Speed for keys 36 bytes long = 157,408,131 KEYS-PER-SECOND; all in 99 clocks
Dummy usage, -456483296.
RAW Hashing Speed for keys 64 bytes long = 157,407,848 KEYS-PER-SECOND; all in 99 clocks
...

E:\Lookuperorama.c_r5+>Lookuperorama_GCC-7.3.0_xxh64_64bit.exe Arabian_Nights_complete.html x 1 1 I

RAW Hashing Speed for key 15,583,440 bytes long = 10,299,695,968 10,989,732,016 10,981,987,315 10,989,732,016 10,989,732,016 | 10,989,732,016 BYTES-PER-SECOND
Dummy usage, 713312125.
RAW Hashing Speed for keys 04 bytes long = 239,745,184 KEYS-PER-SECOND; all in 65 clocks
Dummy usage, 1996479145.
RAW Hashing Speed for keys 06 bytes long = 192,388,086 KEYS-PER-SECOND; all in 81 clocks
Dummy usage, -853007940.
RAW Hashing Speed for keys 08 bytes long = 216,436,569 KEYS-PER-SECOND; all in 72 clocks
Dummy usage, -1163048755.
RAW Hashing Speed for keys 10 bytes long = 173,149,233 KEYS-PER-SECOND; all in 90 clocks
Dummy usage, -1827505444.
RAW Hashing Speed for keys 12 bytes long = 190,041,817 KEYS-PER-SECOND; all in 82 clocks
Dummy usage, 772663914.
RAW Hashing Speed for keys 14 bytes long = 147,013,462 KEYS-PER-SECOND; all in 106 clocks
Dummy usage, -1046118434.
RAW Hashing Speed for keys 16 bytes long = 175,094,662 KEYS-PER-SECOND; all in 89 clocks
Dummy usage, -1486821745.
RAW Hashing Speed for keys 18 bytes long = 139,137,705 KEYS-PER-SECOND; all in 112 clocks
Dummy usage, 1056896294.
RAW Hashing Speed for keys 36 bytes long = 84,234,621 KEYS-PER-SECOND; all in 185 clocks
Dummy usage, 49108245.
RAW Hashing Speed for keys 64 bytes long = 75,282,014 KEYS-PER-SECOND; all in 207 clocks
...

E:\Lookuperorama.c_r5+>Lookuperorama_GCC-7.3.0_wy_64bit.exe Arabian_Nights_complete.html x 1 1 I

RAW Hashing Speed for key 15,583,440 bytes long = 7,336,836,158 7,347,213,578 7,340,292,039 7,347,213,578 7,340,292,039 | 7,347,213,578 BYTES-PER-SECOND
Dummy usage, 803620614.
RAW Hashing Speed for keys 04 bytes long = 216,436,625 KEYS-PER-SECOND; all in 72 clocks
Dummy usage, -371125780.
RAW Hashing Speed for keys 06 bytes long = 216,436,597 KEYS-PER-SECOND; all in 72 clocks
Dummy usage, -623528025.
RAW Hashing Speed for keys 08 bytes long = 216,436,569 KEYS-PER-SECOND; all in 72 clocks
Dummy usage, -1655635255.
RAW Hashing Speed for keys 10 bytes long = 213,471,657 KEYS-PER-SECOND; all in 73 clocks
Dummy usage, -758114859.
RAW Hashing Speed for keys 12 bytes long = 216,436,513 KEYS-PER-SECOND; all in 72 clocks
Dummy usage, -2146149880.
RAW Hashing Speed for keys 14 bytes long = 202,382,168 KEYS-PER-SECOND; all in 77 clocks
Dummy usage, 1777476378.
RAW Hashing Speed for keys 16 bytes long = 202,382,142 KEYS-PER-SECOND; all in 77 clocks
Dummy usage, 196963834.
RAW Hashing Speed for keys 18 bytes long = 160,653,845 KEYS-PER-SECOND; all in 97 clocks
Dummy usage, 1520241591.
RAW Hashing Speed for keys 36 bytes long = 136,696,535 KEYS-PER-SECOND; all in 114 clocks
Dummy usage, -2117660594.
RAW Hashing Speed for keys 64 bytes long = 106,735,458 KEYS-PER-SECOND; all in 146 clocks
...

Yann, any thoughts?

Once more, excuse me for the wrong benchmarking from last two days - distraction is nasty, calm commitment is needed.

Cyan4973 commented 5 years ago

These results look much more consistent @Sanmayce .

The debate can move on to absolute values, which are dependent on the measured system and the scenario produced. That's by nature more debatable.

I would recommend to run tests/bench/benchHash on your systems, as a point of comparison. This is a pretty strong benchmark suite, hosted within xxHash repository. You don't have to modify it, just compile (make) and run (./benchHash). This should be helpful to compare absolute numbers produced by the 2 benchmark suites.

Best case they are similar. Another possible outcome is a difference by a constant factor. Whatever the differences, it's interesting to know.

Sanmayce commented 5 years ago

Thanks, still have no enough time, but will try to play with your benchHash next week.

The debate can move on to absolute values

This prompts for trying a file much larger than any cache size, current Ryzens feature 64MB, it tells me enwik9 fits the bill. I would like to see "a hash scanner" skimming over 1GB data and hashing on the fly all needed orders one after another for each position, like: pos 0: 4,6,8,10,12,14 pos 1: 4,6,8,10,12,14 pos 2: 4,6,8,10,12,14 ... This will give the accumulative performance of one hash designed for small keys, I reckon.

I believe you have done awesome job overall, taking into account 'Pippip' probably fails all the tests in SMHASHER. But as you know, my simple view is that checksumming is an overkill for hash-tables. On the other hand I used for a month SHA3-224, I say that because there are other useful usages along with ALL-SPEED, ALL-COLLISION-FREE hashers- namely, hashers "compressing "LOSSLESSLY" keys" to fixed length chunks 28 bytes long - a nifty technique to reduce the memory footprint.

To me, every benchmark brings something new interesting to know... hopefully in the future some more hashers/benchmarks will enrich the picture, or as the song goes - best is yet to come, salute you with it: https://www.youtube.com/watch?v=A-edpq5IvSs

Sanmayce commented 5 years ago

Successfully added 'Pippip' to your benchsuite by adding:

// Kaze was here
#include <stdint.h> // uint8_t needed
#define _PADr_KAZE(x, n) ( ((x) << (n))>>(n) )
uint32_t FNV1A_Pippip(const char *str, uint32_t wrdlen) {
    const uint32_t PRIME = 591798841; uint32_t hash32; uint64_t hash64 = 14695981039346656037; const char *p = str;
    int i, Cycles, NDhead;
if (wrdlen > 8) {
    Cycles = ((wrdlen - 1)>>4) + 1; NDhead = wrdlen - (Cycles<<3);
    for(i=0; i<Cycles; i++) {
        hash64 = ( hash64 ^ (*(uint64_t *)(p)) ) * PRIME;        
        hash64 = ( hash64 ^ (*(uint64_t *)(p+NDhead)) ) * PRIME;        
        p += 8;
    }
} else
    hash64 = ( hash64 ^ _PADr_KAZE(*(uint64_t *)(p+0), (8-wrdlen)<<3) ) * PRIME;        
    hash32 = (uint32_t)(hash64 ^ (hash64>>32)); return hash32 ^ (hash32 >> 16);
} // Last update: 2019-Oct-18, 15 C lines strong, Kaze.

size_t FNV1A_Pippip_wrapper(const void* src, size_t srcSize, void* dst, size_t dstCapacity, void* customPayload)
{
    (void)dst; (void)dstCapacity; (void)customPayload;
    return (size_t) FNV1A_Pippip(src, srcSize);
}

...

#ifndef HARDWARE_SUPPORT
#  define NB_HASHES 5
#else
#  define NB_HASHES 5
#endif

Bench_Entry const hashCandidates[NB_HASHES] = {
    { "FNV1A_Pippip"  , FNV1A_Pippip_wrapper },
    { "xxh3"  , xxh3_wrapper },
    { "XXH32" , XXH32_wrapper },
    { "XXH64" , XXH64_wrapper },
    { "XXH128", XXH128_wrapper },
#ifdef HARDWARE_SUPPORT
    /* list here codecs which require specific hardware support, such SSE4.1, PCLMUL, AVX2, etc. */
#endif
};

Did what I could, enriched r.5+ with the additional "a hash scanner" benchmark, included the hardware CRC32 and SHA3-224, also easily added 'Pippip' to 'hashes.h' - the resultant graphs are below (on i5-7200U):

On the first graph 'Pippip' suffers a heartattack while competing against XXH3, :P

Yann1_benchmarking large inputs from 512 bytes (log9) to 128 MB (log27).PNG: https://drive.google.com/file/d/1rAaEt6z_nv5r0z_YGcFjJ2MAyBwPOT0-/view?usp=sharing

Yann2_Throughput small inputs of fixed size.PNG: https://drive.google.com/file/d/1yMPdMTpHZaSbpxxnTnsKYqNlXHw4UnSX/view?usp=sharing

Yann3_benchmarking random size inputs [1-N].PNG: https://drive.google.com/file/d/1w6q2qFM5hAkDzXe0r51rsg0cSRtfKtdk/view?usp=sharing

On 4th and 5th, 'Pippip' stumbles in big time after some threshold, @Cyan4973 what are the actual values?

Yann4_Latency for small inputs of fixed size.PNG: https://drive.google.com/file/d/1jgZRyKoosyGbIDCIgeb-wr9WyCeq6g75/view?usp=sharing

Yann5Latency for small inputs of random size [1-N].PNG: https://drive.google.com/file/d/1-K3Yz0dwtnOs9ZbSTZ9VAjy8o85-rGX/view?usp=sharing

Textual console outputs (for i5-7200U and i7-3630QM) are included in the package, modified xxHash-0.7.2 as well: Lookuperorama.c_r6.zip (7,831,027 bytes): https://drive.google.com/file/d/1SubNyDjAXPwJ_Z48z-vrWTzdHo_woNbc/view?usp=sharing

For '1001 Nights' (15,583,440 bytes) and 10 hash-tables 24bit each, ICC v19.0, i7-3630QM, Windows 10:

Hasher             | Collisions | Synthetic/Taxed Hashing Speed for ALL keys     |
----------------------------------------------------------------------------------
SSE4.2 iSCSI CRC32 | 23,737,621 | 208,334,772 KEYS-PER-SECOND / 5,565,507 Keys/s |
SHA3-224           | 23,737,389 |     104,465 KEYS-PER-SECOND /   102,052 Keys/s |
----------------------------------------------------------------------------------

For '1001 Nights' (15,583,440 bytes) and 10 hash-tables 24bit each, GCC 7.3.0, i7-3630QM, Windows 10:

Hasher             | Collisions | Synthetic/Taxed Hashing Speed for ALL keys     |
----------------------------------------------------------------------------------
FNV1A-Pippip       | 23,738,813 | 269,144,006 KEYS-PER-SECOND / 5,026,910 Keys/s |
WYHASH             | 23,738,215 | 134,688,314 KEYS-PER-SECOND / 5,026,910 Keys/s |
XXH64              | 23,737,218 | 115,861,992 KEYS-PER-SECOND / 4,869,819 Keys/s |
XXH3               | 23,735,377 | 174,702,219 KEYS-PER-SECOND / 5,026,910 Keys/s |
----------------------------------------------------------------------------------

Note1: Collisions are cumulative for all the 10 hash-tables. Note2: 'Taxed' means it is polluted with many random/uncached RAM accesses.

This is how looks like the console dump for 'Pippip':

F:\Lookuperorama.c_r6>Lookuperorama_GCC-7.3.0_Pippip_64bit.exe "Arabian_Nights_complete.html" x 24 7500 i

Current priority class is REALTIME_PRIORITY_CLASS.
Allocating Source-Buffer 14 MB ...
Allocating Source-Buffer 14 MB (REVERSED) ...
Allocating Target-Buffer 46 MB ...
Allocating Verification-Buffer 14 MB ...
Leprechaun: Memory pool for B-tress is 7,500 MB.
Leprechaun: In this revision 128MB 10-way hash is used which results in 10 x 16,777,216 internal B-Trees of order 3.
Leprechaun: In this revision, 1 pass is to be executed.
Leprechaun: Allocating HASH memory 1,342,177,345 bytes ... OK
Leprechaun: Allocating memory for B-tress 7501 MB ... OK
Leprechaun: Size of input file: 15,583,440

RAW Hashing Speed for key 15,583,440 bytes long = 6,600,355,781 6,691,043,366 6,688,171,673 6,691,043,366 6,691,043,366 | 6,691,043,366 BYTES-PER-SECOND
RAW Hashing Speed for keys 04 bytes long = 916,672,764 KEYS-PER-SECOND; all in 17 clocks
RAW Hashing Speed for keys 06 bytes long = 916,672,647 KEYS-PER-SECOND; all in 17 clocks
RAW Hashing Speed for keys 08 bytes long = 973,964,562 KEYS-PER-SECOND; all in 16 clocks
RAW Hashing Speed for keys 10 bytes long = 486,982,218 KEYS-PER-SECOND; all in 32 clocks
RAW Hashing Speed for keys 12 bytes long = 486,982,156 KEYS-PER-SECOND; all in 32 clocks
RAW Hashing Speed for keys 14 bytes long = 486,982,093 KEYS-PER-SECOND; all in 32 clocks
RAW Hashing Speed for keys 16 bytes long = 486,982,031 KEYS-PER-SECOND; all in 32 clocks
RAW Hashing Speed for keys 18 bytes long = 324,654,645 KEYS-PER-SECOND; all in 48 clocks
RAW Hashing Speed for keys 36 bytes long = 247,355,634 KEYS-PER-SECOND; all in 63 clocks
RAW Hashing Speed for keys 64 bytes long = 197,257,936 KEYS-PER-SECOND; all in 79 clocks
The hash scanner - hashing in one pass all orders - TESTING CUMULATIVE PERFORMANCE...
RAW Hashing Speed for keys 4,6,8,10,12,14,16,18,36,64 bytes long = 269,144,006 KEYS-PER-SECOND; all in 579 clocks
Leprechaun: Inserting keys/BBs of order 004 into B-trees, free RAM in B-tree pool is 00,007,500 MB; Pass #001 of 1 ... DONE; 00,000,185,110 B-trees have been rooted so far; HashtableS_Utilization = 000%; Keys/s = 012,456,784
Leprechaun: Inserting keys/BBs of order 006 into B-trees, free RAM in B-tree pool is 00,007,491 MB; Pass #001 of 1 ... DONE; 00,001,330,364 B-trees have been rooted so far; HashtableS_Utilization = 000%; Keys/s = 007,495,639
Leprechaun: Inserting keys/BBs of order 008 into B-trees, free RAM in B-tree pool is 00,007,432 MB; Pass #001 of 1 ... DONE; 00,004,317,931 B-trees have been rooted so far; HashtableS_Utilization = 002%; Keys/s = 006,734,413
Leprechaun: Inserting keys/BBs of order 010 into B-trees, free RAM in B-tree pool is 00,007,264 MB; Pass #001 of 1 ... DONE; 00,009,402,389 B-trees have been rooted so far; HashtableS_Utilization = 005%; Keys/s = 005,631,886
Leprechaun: Inserting keys/BBs of order 012 into B-trees, free RAM in B-tree pool is 00,006,952 MB; Pass #001 of 1 ... DONE; 00,016,178,252 B-trees have been rooted so far; HashtableS_Utilization = 009%; Keys/s = 005,246,945
Leprechaun: Inserting keys/BBs of order 014 into B-trees, free RAM in B-tree pool is 00,006,492 MB; Pass #001 of 1 ... DONE; 00,024,085,199 B-trees have been rooted so far; HashtableS_Utilization = 014%; Keys/s = 004,911,259
Leprechaun: Inserting keys/BBs of order 016 into B-trees, free RAM in B-tree pool is 00,005,903 MB; Pass #001 of 1 ... DONE; 00,032,694,767 B-trees have been rooted so far; HashtableS_Utilization = 019%; Keys/s = 005,246,944
Leprechaun: Inserting keys/BBs of order 018 into B-trees, free RAM in B-tree pool is 00,005,208 MB; Pass #001 of 1 ... DONE; 00,041,744,572 B-trees have been rooted so far; HashtableS_Utilization = 024%; Keys/s = 004,594,169
Leprechaun: Inserting keys/BBs of order 036 into B-trees, free RAM in B-tree pool is 00,004,424 MB; Pass #001 of 1 ... DONE; 00,051,646,708 B-trees have been rooted so far; HashtableS_Utilization = 030%; Keys/s = 004,003,958
Leprechaun: Inserting keys/BBs of order 064 into B-trees, free RAM in B-tree pool is 00,003,120 MB; Pass #001 of 1 ... DONE; 00,061,668,508 B-trees have been rooted so far; HashtableS_Utilization = 036%; Keys/s = 003,598,932

Leprechaun: (Total Hashing Speed) plus Searches-n-Inserts Per Second: 5,026,910 SNIPS

Number Of Bits (Slots=1<<Bits): 24
Number Of Hash Collisions(Distinct WORDs - Number Of Trees): 23,738,813
Number Of Trees(GREATER THE BETTER): 61,668,508
Number Of LEAFs(littler THE BETTER) not counting ROOT LEAFs: 8,688,301
Highest Tree not counting ROOT Level i.e. CORONA levels(littler THE BETTER): 2
Cyan4973 commented 5 years ago

On 4th and 5th, 'Pippip' stumbles in big time after some threshold, @Cyan4973 what are the actual values?

Not sure what you mean, it's a latency test, it's designed to avoid having a cpu pipelining multiple hash operations in parallel, so that it's more representative of hash table / bloom filter real use cases.

In your case, it just shows that at 16+ bytes, there is approximately 2x more work to do to complete hash calculation. Nothing exceptional.

Sanmayce commented 5 years ago

Thanks, far from grasping the whole picture I am, it surprises me how elusive such simple etudes are, to me at least.

Not sure what you mean, it's a latency test,

The benchmark #5 shows the falling begins at 3 times greater threshold ~48+, my dummy expectations were this fall to happen for keys >270 bytes since my simple logic tells me if the fall in benchmark #1 happens at ~270 then it should happen in benchmark #5 likewise, or I am mistaken?!

You are most welcome to see my old and kinda naive article, updated: https://www.codeproject.com/Articles/716530/Fastest-hash-function-for-table-lookups-in-C

Gladly will add/correct something you suggest.

Cyan4973 commented 5 years ago

The benchmark #5 shows the falling begins at 3 times greater threshold ~48+

It actually starts to fall after 16, which is to be expected.

The major difference of test 5 is that it requests hashing keys of random size. The size is some flat random distribution between 1 and the abscissa value, so, for example, at value 30, keys are random between 1 and 30 included.

This test is more taxing for branch-heavy hash algorithms. Your implementation has an advantage on this test, because it offloads some responsibility regarding minimum buffer size to the user (I'm not even sure if it supports very small keys of a few bytes). This cuts through the branch budget.

Because of the random distribution, the test tends to produce smoother graphs than "fixed length" tests, which will feature some more abrupt cliffs at exact positions in the graph.

It's also more realistic of "real-case" scenarios, whenever the size of keys cannot be pre-determined at compile time, because in most cases, hash is an isolated operation between more complex ones, which means the branches cannot be "hot", and the cpu cannot properly "guess" them.

Sanmayce commented 5 years ago

Thanks, I supposed so but still I have no understanding of why XXH3 outperformed 'Pippip' at such short distance as 16..48, my expectation was vectors to kick in after 64++ sizes, didn't look at your code, yet.

I'm not even sure if it supports very small keys of a few bytes

Sure, 1 byte is the minimum, even 0 is accepted.

By the way Yirii was so kind to point out my dummy choice of using an unwanted counter, hopefully it will boost a bit old results, the new variant will be called 'FNV1A-Pippip_Yurii'...

https://github.com/rurban/smhasher/issues/75#issuecomment-547085165

Sanmayce commented 5 years ago

@Cyan4973 Very interesting, having reduced 3 instructions with Yurii's help, your hashBench suite was sensitive enough to detect it!

https://software.intel.com/en-us/forums/intel-moderncode-for-parallel-architectures/topic/824947#comment-1947234

dumblob commented 5 years ago

@Sanmayce those are promising results - do you think something can be done with the really bad distribution (smhasher) without loosing too much?

Regarding quality, it feels currently halfway between the fastest (and worst) hashes (like sumhash32 in smhasher) and the highest quality ones like in XXH3 or Wyhash).


Btw. I think plots with all three contestants (FNV1A_Pippip_Yurii, XXH3, Wyhash) next to each other would be a good nice-to-have (something like plots in the comment https://software.intel.com/en-us/forums/intel-moderncode-for-parallel-architectures/topic/824947#comment-1947234 , but in addition with Wyhash).

Sanmayce commented 5 years ago

do you think something can be done with the really bad distribution (smhasher) without loosing too much?

Don't know, this issue have to address more knowledgable guys, my understanding of hashing is really superficial. To me, there are certain small tweaks that can greatly better the mix and avalanche, but I am not the guy, alchemy it is.

Regarding quality, it feels currently halfway between the fastest (and worst) hashes (like sumhash32 in smhasher) and the highest quality ones like in XXH3 or Wyhash).

You make a mistake by saying 'fastest', they are just junk, I tried 'fletcher' on my Knight-Tours benchmark and it generated collisions beyond belief, such are not practical I am looking forward seeing a corpus that makes 'Pippip' choke, if you have any file with keys which are gonna show bad distribution, please share it.

In my experience, 'Pippip' appears to be superpractical, and regarding SMHASHER, really the author should consider updating his "speed evaluation", it is bogus. Let me give you an example: According to SMHASHER, the #1 features some 17.5 cycles/hash while 'Pippip' something like 36 cycles/hash, now look the real-world RAW linear hash benchmark: https://drive.google.com/file/d/1GZsYEdW_Xyz1mBa16P8PMcx65WPKpeRZ/view?usp=sharing

By chance, the best distribution was Pippip's, go figure.

The hash scanner - hashing in one pass all orders - TESTING CUMULATIVE PERFORMANCE, without touching any SLOTS (uncached RAM):

FNV1A-Pippip-Yurii (Intel v19.0) : RAW Hashing Speed for keys 4,6,8,10,12,14,16,18,36,64 bytes long = 264,144,246 KEYS-PER-SECOND; all in 219 clocks
XXH3 (Intel v19.0)               : RAW Hashing Speed for keys 4,6,8,10,12,14,16,18,36,64 bytes long = 186,605,129 KEYS-PER-SECOND; all in 310 clocks
WYHASH (Intel v19.0)             : RAW Hashing Speed for keys 4,6,8,10,12,14,16,18,36,64 bytes long = 139,391,783 KEYS-PER-SECOND; all in 415 clocks

Please, print this page, take a beer or whatever you drink, and calmly contemplate. If you have any explanation why WYHASH is not 2x faster but 2x slower than Pippip, gladly will hear it.

As for, fur further testing, sure WYHASH is good to be included in every run, also I have an idea to hash all DWORDS possible into 29bit tables and compare collisions of iSCSI CRC32, XXH3, WYHASH and 'Pippip' - the ~4billion keys versus 0.5billion slots is worth seeing.

dumblob commented 5 years ago

You make a mistake by saying 'fastest', they are just junk, I tried 'fletcher' on my Knight-Tours benchmark and it generated collisions beyond belief, such are not practical

Just for clarification - to me it seems our definition of "practical" differs. I define "practical" as a weighted sum:

w1 independent of and stable (both the resulting hash as well as performance) across CPU architectures (100% means there are no such known restrictions) + w2 very fast - at least in all @Cyan4973 benchmarks (100% means just reading the data from memory into CPU cache) + w3 passes all smhasher and other state of the art quality/statistical tests (100% means passes all such tests) + w4 does not impose any restriction on input data (e.g. ending at least N bytes from the end of the allocated page) and if any, how much restricting it is (100% means no restrictions) + w5 * implementation complexity across programming languages and software spectrum - e.g. not all hashes are well implementable say in JavaScript (100% means lowest complexity)

With weights relationship w1:w2:w3:w4:w5 ~ 10:10:10:2:1. This yields roughly (my personal opinion):

hash function practicality unweighted practicality weighted
sumhash 100%:98%:0%:100%:100% 1000+980+0+200+100 = 2290
FNV1A-Pippip-Yurii 100%:92%:0%:50%:100% 1000+920+0+100+100 = 2120
XXH3 100%:80%:100%:100%:50% 1000+800+1000+200+50 = 3050
WYHASH 90%:65%:100%:100%:70% 900+650+1000+200+70 = 2820

Sounds hard, but according to this overview Pippip performs rather closer to sumhash than to others.

Sanmayce commented 5 years ago

This yields roughly (my personal opinion)

"Opinions Vary" https://www.youtube.com/watch?v=oeglesB0qDk

Superepic movie, love it from start to finish.

Seriously @dumblob, get serious and read the titles, at least - we are talking hashtable lookuping here.

Personally, it amuses me when someone tries to tell me e.g. Godzilla (XXH3) is more battleready than a Dragonfly (Pippip) - the lookuper of Nakamichi 'Dragoneye'.

Stick with me, and hopefully you will see how extrasynthetic your weight-ranklist is, in practice.

@Cyan4973

I'm not even sure if it supports very small keys of a few bytes

Let's find out.

Funny, we didn't come up earlier with the most intuitive and most simple of all collision-tests... I quickly inserted the fragment below for both 'Pippip' and 'XXH3' into my 1 trillion Knight-Tours benchmark, by the way will share the full console dump after passing the 1 trillion mark...

for (dumbino=1; dumbino<=4; dumbino++) { // The buffer for the KT should be 4GB in total i.e. 30bit x 4bytes-per-slot

memset(pointerflush, 0, (1LL<<HashSizeInBits)*sizeof(uint32_t));
if (dumbino==1) printf( "XXH3_64bits            : Hashing all UNIbytes,   i.e. all  8bit variants into  8bit hashtable ... ");
if (dumbino==2) printf( "XXH3_64bits            : Hashing all BIbytes,    i.e. all 16bit variants into 16bit hashtable ... ");
if (dumbino==3) printf( "XXH3_64bits            : Hashing all TRIbytes,   i.e. all 24bit variants into 24bit hashtable ... ");
if (dumbino==4) printf( "XXH3_64bits            : Hashing all TETRAbytes, i.e. all 32bit variants into 32bit hashtable ... ");
for (BenchSmallKeys=0; BenchSmallKeys < (1LL<<(dumbino<<3)); BenchSmallKeys++) {
    Slot = ( ((uint32_t)XXH3_64bits((char *)&BenchSmallKeys, dumbino)) & ((1LL<<(dumbino<<3))-1) )<<0;
    //memcpy( &PseudoLinkedPointer, pointerflush+Slot, 4 );
    //PseudoLinkedPointer++; //if (PseudoLinkedPointer==255) printf( "\nGrmbl, a slot with 255 collisions exist!\n" );
    //memcpy( pointerflush+Slot, &PseudoLinkedPointer, 4 );
    PseudoLinkedPointer = 1;
    memcpy( pointerflush+Slot, &PseudoLinkedPointer, 4-3 );
}
UsedSlots=0;
for (BenchSmallKeys=0; BenchSmallKeys < (1LL<<(dumbino<<3)); BenchSmallKeys++) {

    if (*(char*)(pointerflush+BenchSmallKeys)) UsedSlots++;
}
printf( "Used Slots = %llu; ", UsedSlots);
printf( "Utilization = (UsedSlots/AllSlots)*100%% = %5.2f%% (the-bigger-the-better)\n", (float)(UsedSlots*100)/(float)(1LL<<(dumbino<<3)));
} // dumbino

The resultant dump:

FNV1A_Pippip           : Hashing all UNIbytes,   i.e. all  8bit variants into  8bit hashtable ... Used Slots = 161; Utilization = (UsedSlots/AllSlots)*100% = 62.89% (the-bigger-the-better)
FNV1A_Pippip           : Hashing all BIbytes,    i.e. all 16bit variants into 16bit hashtable ... Used Slots = 41520; Utilization = (UsedSlots/AllSlots)*100% = 63.35% (the-bigger-the-better)
FNV1A_Pippip           : Hashing all TRIbytes,   i.e. all 24bit variants into 24bit hashtable ... Used Slots = 10599094; Utilization = (UsedSlots/AllSlots)*100% = 63.18% (the-bigger-the-better)
FNV1A_Pippip           : Hashing all TETRAbytes, i.e. all 32bit variants into 32bit hashtable ... Used Slots = 2716930650; Utilization = (UsedSlots/AllSlots)*100% = 63.26% (the-bigger-the-better)

XXH3_64bits            : Hashing all UNIbytes,   i.e. all  8bit variants into  8bit hashtable ... Used Slots = 165; Utilization = (UsedSlots/AllSlots)*100% = 64.45% (the-bigger-the-better)
XXH3_64bits            : Hashing all BIbytes,    i.e. all 16bit variants into 16bit hashtable ... Used Slots = 41483; Utilization = (UsedSlots/AllSlots)*100% = 63.30% (the-bigger-the-better)
XXH3_64bits            : Hashing all TRIbytes,   i.e. all 24bit variants into 24bit hashtable ... Used Slots = 10606427; Utilization = (UsedSlots/AllSlots)*100% = 63.22% (the-bigger-the-better)
XXH3_64bits            : Hashing all TETRAbytes, i.e. all 32bit variants into 32bit hashtable ... Used Slots = 2714932144; Utilization = (UsedSlots/AllSlots)*100% = 63.21% (the-bigger-the-better)

As you can see, the "superbad" 'Pippip' disperses DWORDs better than XXH3, who would have thought!

As for the superheavy collision benchmark 'Trismus', you can see Knight-Tours are hashed by Pippip, again, on a par with XXH3. These 52 collisions housed at 2 slots mean that a B-tree order 3 can find a key (among 22 billion keys) with maximum 4 lookups: The slot points the root, the latter has (3^0)2=2 keys, the corona level 1 has (3^1)2=6 keys, corona level 2 has (3^2)2=18 keys, corona level 3 has (3^3)2=54 keys - in total, up to 2+6+18+54=80 collisions in 4 lookups.

G:\Trismus>Knight-Tour_FNV1A_Pippip_vs_CRC32_TRISMUS_30bit.exe a8 4000000000
Knight-Tour_FNV1A_Yorikke3_vs_CRC32_TRISMUS, subrevision Efix, written by Kaze (based on Kurt White's code), downloadable at www.sanmayce.com/Fastest_Hash
Purpose: to compare FNV1A_Yorikke3 and CRC32 by giving the highest number of collisions i.e. the deepest nest/layer, the-lesser-the-better.
Note: In this subrevision a KT is transformed to lowercase at each position ONCE, KT is transformed to lowercase and then to uppercase at each position ONCE,
      and these two 2x64 sequences reversed, i.e. all the 4x64 combinations.
      Thus excluding the original KT we can hash 1+ trillion 1Kb UNIQUE chunks by having only 4 billion KTs.
Example: D:\>Knight-Tour_FNV1A_Yorikke3_vs_CRC32_TRISMUS a8 4000000000
Polynomial used:
CRC32: 0x8F6E37A0
KEYS to be hashed = 4,000,000,000x4x64
HashSizeInBits = 30
ReportAtEvery = 268,435,455
Allocating HASH memory 4096MB ... OK
FNV1A_Pippip           : Hashing all UNIbytes,   i.e. all  8bit variants into  8bit hashtable ... Used Slots = 161; Utilization = (UsedSlots/AllSlots)*100% = 62.89% (the-bigger-the-better)
FNV1A_Pippip           : Hashing all BIbytes,    i.e. all 16bit variants into 16bit hashtable ... Used Slots = 41520; Utilization = (UsedSlots/AllSlots)*100% = 63.35% (the-bigger-the-better)
FNV1A_Pippip           : Hashing all TRIbytes,   i.e. all 24bit variants into 24bit hashtable ... Used Slots = 10599094; Utilization = (UsedSlots/AllSlots)*100% = 63.18% (the-bigger-the-better)
FNV1A_Pippip           : Hashing all TETRAbytes, i.e. all 32bit variants into 32bit hashtable ... Used Slots = 2716930650; Utilization = (UsedSlots/AllSlots)*100% = 63.26% (the-bigger-the-better)
XXH3_64bits            : Hashing all UNIbytes,   i.e. all  8bit variants into  8bit hashtable ... Used Slots = 165; Utilization = (UsedSlots/AllSlots)*100% = 64.45% (the-bigger-the-better)
XXH3_64bits            : Hashing all BIbytes,    i.e. all 16bit variants into 16bit hashtable ... Used Slots = 41483; Utilization = (UsedSlots/AllSlots)*100% = 63.30% (the-bigger-the-better)
XXH3_64bits            : Hashing all TRIbytes,   i.e. all 24bit variants into 24bit hashtable ... Used Slots = 10606427; Utilization = (UsedSlots/AllSlots)*100% = 63.22% (the-bigger-the-better)
XXH3_64bits            : Hashing all TETRAbytes, i.e. all 32bit variants into 32bit hashtable ... Used Slots = 2714932144; Utilization = (UsedSlots/AllSlots)*100% = 63.21% (the-bigger-the-better)
Allocating HASH memory 4096MB ... OK
Going...
The first KT:
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
gives following 4x64 UNIQUE derivatives:
a8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8c7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7e8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8g7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7h5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5g3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3h1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1f2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2h3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3g1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1e2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2c1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1a2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2b4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4a6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6b8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8d7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7f8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8h7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7g5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5f7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7h8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8g6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6h4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4g2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2e1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1c2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2a1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1b3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3a5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5b7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7d8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8c6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6a7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7c8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8e7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7g8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8h6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6g4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4h2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2f1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1d2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2b1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1a3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3b5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5d6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6f5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5d4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4f3E5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3e5C4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5c4B2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4b2D3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2d3F4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3f4E6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4e6C5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6c5A4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5a4B6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4b6D5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6d5F6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5f6E4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6e4C3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4c3D1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3d1E3
A8C7E8G7H5G3H1F2H3G1E2C1A2B4A6B8D7F8H7G5F7H8G6H4G2E1C2A1B3A5B7D8C6A7C8E7G8H6G4H2F1D2B1A3B5D6F5D4F3E5C4B2D3F4E6C5A4B6D5F6E4C3D1e3
e3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3d1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1c3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3e4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4f6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6d5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5b6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6a4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4c5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5e6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6f4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4d3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3b2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2c4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4e5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5f3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3d4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4f5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5d6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6b5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5a3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3b1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1d2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2f1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1h2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2g4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4h6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6g8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8e7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7c8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8a7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7c6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6d8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8b7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7a5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5b3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3a1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1c2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2e1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1g2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2h4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4g6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6h8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8f7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7g5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5h7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7f8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8d7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7b8A6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8a6B4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6b4A2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4a2C1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2c1E2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1e2G1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2g1H3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1h3F2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3f2H1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2h1G3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1g3H5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3h5G7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5g7E8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7e8C7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8c7A8
E3D1C3E4F6D5B6A4C5E6F4D3B2C4E5F3D4F5D6B5A3B1D2F1H2G4H6G8E7C8A7C6D8B7A5B3A1C2E1G2H4G6H8F7G5H7F8D7B8A6B4A2C1E2G1H3F2H1G3H5G7E8C7a8
A8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8C7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7E8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8G7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7H5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5G3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3H1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1F2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2H3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3G1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1E2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2C1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1A2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2B4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4A6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6B8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8D7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7F8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8H7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7G5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5F7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7H8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8G6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6H4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4G2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2E1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1C2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2A1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1B3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3A5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5B7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7D8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8C6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6A7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7C8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8E7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7G8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8H6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6G4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4H2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2F1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1D2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2B1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1A3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3B5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5D6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6F5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5D4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4F3e5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3E5c4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5C4b2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4B2d3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2D3f4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3F4e6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4E6c5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6C5a4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5A4b6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4B6d5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6D5f6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5F6e4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6E4c3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4C3d1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3D1e3
a8c7e8g7h5g3h1f2h3g1e2c1a2b4a6b8d7f8h7g5f7h8g6h4g2e1c2a1b3a5b7d8c6a7c8e7g8h6g4h2f1d2b1a3b5d6f5d4f3e5c4b2d3f4e6c5a4b6d5f6e4c3d1E3
E3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3D1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1C3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3E4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4F6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6D5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5B6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6A4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4C5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5E6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6F4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4D3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3B2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2C4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4E5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5F3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3D4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4F5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5D6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6B5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5A3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3B1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1D2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2F1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1H2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2G4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4H6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6G8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8E7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7C8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8A7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7C6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6D8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8B7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7A5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5B3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3A1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1C2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2E1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1G2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2H4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4G6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6H8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8F7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7G5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5H7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7F8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8D7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7B8a6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8A6b4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6B4a2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4A2c1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2C1e2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1E2g1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2G1h3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1H3f2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3F2h1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2H1g3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1G3h5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3H5g7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5G7e8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7E8c7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8C7a8
e3d1c3e4f6d5b6a4c5e6f4d3b2c4e5f3d4f5d6b5a3b1d2f1h2g4h6g8e7c8a7c6d8b7a5b3a1c2e1g2h4g6h8f7g5h7f8d7b8a6b4a2c1e2g1h3f2h1g3h5g7e8c7A8
FNV1A_Pippip           : KT_DumpCounter = 0,000,268,435,457; 000,000,006 x MAXcollisionsAtSomeSlots = 000,007; HASHfreeSLOTS = 0,837,421,912
XXH3_64bits            : KT_DumpCounter = 0,000,268,435,457; 000,000,015 x MAXcollisionsAtSomeSlots = 000,007; HASHfreeSLOTS = 0,837,038,946
FNV1A_Pippip           : KT_DumpCounter = 0,000,536,870,913; 000,000,005 x MAXcollisionsAtSomeSlots = 000,009; HASHfreeSLOTS = 0,653,114,578
XXH3_64bits            : KT_DumpCounter = 0,000,536,870,913; 000,000,001 x MAXcollisionsAtSomeSlots = 000,009; HASHfreeSLOTS = 0,652,525,680
FNV1A_Pippip           : KT_DumpCounter = 0,000,805,306,369; 000,000,002 x MAXcollisionsAtSomeSlots = 000,011; HASHfreeSLOTS = 0,509,372,293
XXH3_64bits            : KT_DumpCounter = 0,000,805,306,369; 000,000,001 x MAXcollisionsAtSomeSlots = 000,011; HASHfreeSLOTS = 0,508,684,399
FNV1A_Pippip           : KT_DumpCounter = 0,001,073,741,825; 000,000,001 x MAXcollisionsAtSomeSlots = 000,012; HASHfreeSLOTS = 0,397,271,612
XXH3_64bits            : KT_DumpCounter = 0,001,073,741,825; 000,000,002 x MAXcollisionsAtSomeSlots = 000,012; HASHfreeSLOTS = 0,396,547,632
FNV1A_Pippip           : KT_DumpCounter = 0,001,342,177,281; 000,000,001 x MAXcollisionsAtSomeSlots = 000,013; HASHfreeSLOTS = 0,309,840,966
XXH3_64bits            : KT_DumpCounter = 0,001,342,177,281; 000,000,008 x MAXcollisionsAtSomeSlots = 000,012; HASHfreeSLOTS = 0,309,120,689
FNV1A_Pippip           : KT_DumpCounter = 0,001,610,612,737; 000,000,001 x MAXcollisionsAtSomeSlots = 000,015; HASHfreeSLOTS = 0,241,643,962
XXH3_64bits            : KT_DumpCounter = 0,001,610,612,737; 000,000,001 x MAXcollisionsAtSomeSlots = 000,014; HASHfreeSLOTS = 0,240,970,687
FNV1A_Pippip           : KT_DumpCounter = 0,001,879,048,193; 000,000,001 x MAXcollisionsAtSomeSlots = 000,016; HASHfreeSLOTS = 0,188,461,567
XXH3_64bits            : KT_DumpCounter = 0,001,879,048,193; 000,000,006 x MAXcollisionsAtSomeSlots = 000,014; HASHfreeSLOTS = 0,187,852,641
FNV1A_Pippip           : KT_DumpCounter = 0,002,147,483,649; 000,000,001 x MAXcollisionsAtSomeSlots = 000,016; HASHfreeSLOTS = 0,146,990,968
XXH3_64bits            : KT_DumpCounter = 0,002,147,483,649; 000,000,001 x MAXcollisionsAtSomeSlots = 000,016; HASHfreeSLOTS = 0,146,445,749
FNV1A_Pippip           : KT_DumpCounter = 0,002,415,919,105; 000,000,001 x MAXcollisionsAtSomeSlots = 000,016; HASHfreeSLOTS = 0,114,641,664
XXH3_64bits            : KT_DumpCounter = 0,002,415,919,105; 000,000,001 x MAXcollisionsAtSomeSlots = 000,017; HASHfreeSLOTS = 0,114,158,933
FNV1A_Pippip           : KT_DumpCounter = 0,002,684,354,561; 000,000,012 x MAXcollisionsAtSomeSlots = 000,016; HASHfreeSLOTS = 0,089,412,141
XXH3_64bits            : KT_DumpCounter = 0,002,684,354,561; 000,000,001 x MAXcollisionsAtSomeSlots = 000,018; HASHfreeSLOTS = 0,088,994,331
FNV1A_Pippip           : KT_DumpCounter = 0,002,952,790,017; 000,000,005 x MAXcollisionsAtSomeSlots = 000,017; HASHfreeSLOTS = 0,069,731,124
XXH3_64bits            : KT_DumpCounter = 0,002,952,790,017; 000,000,001 x MAXcollisionsAtSomeSlots = 000,019; HASHfreeSLOTS = 0,069,379,156
FNV1A_Pippip           : KT_DumpCounter = 0,003,221,225,473; 000,000,003 x MAXcollisionsAtSomeSlots = 000,018; HASHfreeSLOTS = 0,054,389,265
XXH3_64bits            : KT_DumpCounter = 0,003,221,225,473; 000,000,001 x MAXcollisionsAtSomeSlots = 000,019; HASHfreeSLOTS = 0,054,086,394
FNV1A_Pippip           : KT_DumpCounter = 0,003,489,660,929; 000,000,001 x MAXcollisionsAtSomeSlots = 000,019; HASHfreeSLOTS = 0,042,418,779
XXH3_64bits            : KT_DumpCounter = 0,003,489,660,929; 000,000,002 x MAXcollisionsAtSomeSlots = 000,019; HASHfreeSLOTS = 0,042,165,828
FNV1A_Pippip           : KT_DumpCounter = 0,003,758,096,385; 000,000,006 x MAXcollisionsAtSomeSlots = 000,019; HASHfreeSLOTS = 0,033,086,839
XXH3_64bits            : KT_DumpCounter = 0,003,758,096,385; 000,000,001 x MAXcollisionsAtSomeSlots = 000,020; HASHfreeSLOTS = 0,032,876,268
FNV1A_Pippip           : KT_DumpCounter = 0,004,026,531,841; 000,000,004 x MAXcollisionsAtSomeSlots = 000,020; HASHfreeSLOTS = 0,025,806,394
XXH3_64bits            : KT_DumpCounter = 0,004,026,531,841; 000,000,002 x MAXcollisionsAtSomeSlots = 000,020; HASHfreeSLOTS = 0,025,627,737
FNV1A_Pippip           : KT_DumpCounter = 0,004,294,967,297; 000,000,010 x MAXcollisionsAtSomeSlots = 000,020; HASHfreeSLOTS = 0,020,129,042
XXH3_64bits            : KT_DumpCounter = 0,004,294,967,297; 000,000,009 x MAXcollisionsAtSomeSlots = 000,020; HASHfreeSLOTS = 0,019,978,567
FNV1A_Pippip           : KT_DumpCounter = 0,004,563,402,753; 000,000,001 x MAXcollisionsAtSomeSlots = 000,022; HASHfreeSLOTS = 0,015,696,342
XXH3_64bits            : KT_DumpCounter = 0,004,563,402,753; 000,000,008 x MAXcollisionsAtSomeSlots = 000,021; HASHfreeSLOTS = 0,015,576,569
FNV1A_Pippip           : KT_DumpCounter = 0,004,831,838,209; 000,000,002 x MAXcollisionsAtSomeSlots = 000,022; HASHfreeSLOTS = 0,012,243,853
XXH3_64bits            : KT_DumpCounter = 0,004,831,838,209; 000,000,003 x MAXcollisionsAtSomeSlots = 000,022; HASHfreeSLOTS = 0,012,144,131
FNV1A_Pippip           : KT_DumpCounter = 0,005,100,273,665; 000,000,002 x MAXcollisionsAtSomeSlots = 000,023; HASHfreeSLOTS = 0,009,549,792
XXH3_64bits            : KT_DumpCounter = 0,005,100,273,665; 000,000,001 x MAXcollisionsAtSomeSlots = 000,023; HASHfreeSLOTS = 0,009,467,665
FNV1A_Pippip           : KT_DumpCounter = 0,005,368,709,121; 000,000,001 x MAXcollisionsAtSomeSlots = 000,024; HASHfreeSLOTS = 0,007,446,733
XXH3_64bits            : KT_DumpCounter = 0,005,368,709,121; 000,000,002 x MAXcollisionsAtSomeSlots = 000,023; HASHfreeSLOTS = 0,007,381,423
FNV1A_Pippip           : KT_DumpCounter = 0,005,637,144,577; 000,000,001 x MAXcollisionsAtSomeSlots = 000,025; HASHfreeSLOTS = 0,005,805,255
XXH3_64bits            : KT_DumpCounter = 0,005,637,144,577; 000,000,001 x MAXcollisionsAtSomeSlots = 000,024; HASHfreeSLOTS = 0,005,755,996
FNV1A_Pippip           : KT_DumpCounter = 0,005,905,580,033; 000,000,001 x MAXcollisionsAtSomeSlots = 000,025; HASHfreeSLOTS = 0,004,527,073
XXH3_64bits            : KT_DumpCounter = 0,005,905,580,033; 000,000,003 x MAXcollisionsAtSomeSlots = 000,024; HASHfreeSLOTS = 0,004,485,805
FNV1A_Pippip           : KT_DumpCounter = 0,006,174,015,489; 000,000,001 x MAXcollisionsAtSomeSlots = 000,025; HASHfreeSLOTS = 0,003,529,192
XXH3_64bits            : KT_DumpCounter = 0,006,174,015,489; 000,000,007 x MAXcollisionsAtSomeSlots = 000,024; HASHfreeSLOTS = 0,003,497,076
FNV1A_Pippip           : KT_DumpCounter = 0,006,442,450,945; 000,000,003 x MAXcollisionsAtSomeSlots = 000,025; HASHfreeSLOTS = 0,002,751,892
XXH3_64bits            : KT_DumpCounter = 0,006,442,450,945; 000,000,002 x MAXcollisionsAtSomeSlots = 000,025; HASHfreeSLOTS = 0,002,725,279
FNV1A_Pippip           : KT_DumpCounter = 0,006,710,886,401; 000,000,002 x MAXcollisionsAtSomeSlots = 000,026; HASHfreeSLOTS = 0,002,146,853
XXH3_64bits            : KT_DumpCounter = 0,006,710,886,401; 000,000,011 x MAXcollisionsAtSomeSlots = 000,025; HASHfreeSLOTS = 0,002,125,351
FNV1A_Pippip           : KT_DumpCounter = 0,006,979,321,857; 000,000,001 x MAXcollisionsAtSomeSlots = 000,027; HASHfreeSLOTS = 0,001,675,216
XXH3_64bits            : KT_DumpCounter = 0,006,979,321,857; 000,000,031 x MAXcollisionsAtSomeSlots = 000,025; HASHfreeSLOTS = 0,001,656,296
FNV1A_Pippip           : KT_DumpCounter = 0,007,247,757,313; 000,000,003 x MAXcollisionsAtSomeSlots = 000,028; HASHfreeSLOTS = 0,001,307,167
XXH3_64bits            : KT_DumpCounter = 0,007,247,757,313; 000,000,013 x MAXcollisionsAtSomeSlots = 000,026; HASHfreeSLOTS = 0,001,290,415
FNV1A_Pippip           : KT_DumpCounter = 0,007,516,192,769; 000,000,001 x MAXcollisionsAtSomeSlots = 000,029; HASHfreeSLOTS = 0,001,018,833
XXH3_64bits            : KT_DumpCounter = 0,007,516,192,769; 000,000,001 x MAXcollisionsAtSomeSlots = 000,028; HASHfreeSLOTS = 0,001,005,812
FNV1A_Pippip           : KT_DumpCounter = 0,007,784,628,225; 000,000,001 x MAXcollisionsAtSomeSlots = 000,032; HASHfreeSLOTS = 0,000,794,413
XXH3_64bits            : KT_DumpCounter = 0,007,784,628,225; 000,000,004 x MAXcollisionsAtSomeSlots = 000,028; HASHfreeSLOTS = 0,000,783,937
FNV1A_Pippip           : KT_DumpCounter = 0,008,053,063,681; 000,000,001 x MAXcollisionsAtSomeSlots = 000,032; HASHfreeSLOTS = 0,000,619,634
XXH3_64bits            : KT_DumpCounter = 0,008,053,063,681; 000,000,003 x MAXcollisionsAtSomeSlots = 000,029; HASHfreeSLOTS = 0,000,611,172
FNV1A_Pippip           : KT_DumpCounter = 0,008,321,499,137; 000,000,001 x MAXcollisionsAtSomeSlots = 000,032; HASHfreeSLOTS = 0,000,483,380
XXH3_64bits            : KT_DumpCounter = 0,008,321,499,137; 000,000,004 x MAXcollisionsAtSomeSlots = 000,029; HASHfreeSLOTS = 0,000,476,699
FNV1A_Pippip           : KT_DumpCounter = 0,008,589,934,593; 000,000,001 x MAXcollisionsAtSomeSlots = 000,032; HASHfreeSLOTS = 0,000,376,557
XXH3_64bits            : KT_DumpCounter = 0,008,589,934,593; 000,000,010 x MAXcollisionsAtSomeSlots = 000,029; HASHfreeSLOTS = 0,000,371,691
FNV1A_Pippip           : KT_DumpCounter = 0,008,858,370,049; 000,000,002 x MAXcollisionsAtSomeSlots = 000,032; HASHfreeSLOTS = 0,000,293,766
XXH3_64bits            : KT_DumpCounter = 0,008,858,370,049; 000,000,012 x MAXcollisionsAtSomeSlots = 000,029; HASHfreeSLOTS = 0,000,289,807
FNV1A_Pippip           : KT_DumpCounter = 0,009,126,805,505; 000,000,001 x MAXcollisionsAtSomeSlots = 000,033; HASHfreeSLOTS = 0,000,228,882
XXH3_64bits            : KT_DumpCounter = 0,009,126,805,505; 000,000,001 x MAXcollisionsAtSomeSlots = 000,031; HASHfreeSLOTS = 0,000,225,868
FNV1A_Pippip           : KT_DumpCounter = 0,009,395,240,961; 000,000,001 x MAXcollisionsAtSomeSlots = 000,035; HASHfreeSLOTS = 0,000,178,434
XXH3_64bits            : KT_DumpCounter = 0,009,395,240,961; 000,000,002 x MAXcollisionsAtSomeSlots = 000,032; HASHfreeSLOTS = 0,000,176,012
FNV1A_Pippip           : KT_DumpCounter = 0,009,663,676,417; 000,000,001 x MAXcollisionsAtSomeSlots = 000,036; HASHfreeSLOTS = 0,000,138,788
XXH3_64bits            : KT_DumpCounter = 0,009,663,676,417; 000,000,001 x MAXcollisionsAtSomeSlots = 000,033; HASHfreeSLOTS = 0,000,137,497
FNV1A_Pippip           : KT_DumpCounter = 0,009,932,111,873; 000,000,001 x MAXcollisionsAtSomeSlots = 000,037; HASHfreeSLOTS = 0,000,108,239
XXH3_64bits            : KT_DumpCounter = 0,009,932,111,873; 000,000,001 x MAXcollisionsAtSomeSlots = 000,034; HASHfreeSLOTS = 0,000,107,525
FNV1A_Pippip           : KT_DumpCounter = 0,010,200,547,329; 000,000,001 x MAXcollisionsAtSomeSlots = 000,038; HASHfreeSLOTS = 0,000,084,313
XXH3_64bits            : KT_DumpCounter = 0,010,200,547,329; 000,000,001 x MAXcollisionsAtSomeSlots = 000,035; HASHfreeSLOTS = 0,000,083,885
FNV1A_Pippip           : KT_DumpCounter = 0,010,468,982,785; 000,000,001 x MAXcollisionsAtSomeSlots = 000,038; HASHfreeSLOTS = 0,000,065,726
XXH3_64bits            : KT_DumpCounter = 0,010,468,982,785; 000,000,001 x MAXcollisionsAtSomeSlots = 000,035; HASHfreeSLOTS = 0,000,065,333
FNV1A_Pippip           : KT_DumpCounter = 0,010,737,418,241; 000,000,001 x MAXcollisionsAtSomeSlots = 000,038; HASHfreeSLOTS = 0,000,051,296
XXH3_64bits            : KT_DumpCounter = 0,010,737,418,241; 000,000,001 x MAXcollisionsAtSomeSlots = 000,035; HASHfreeSLOTS = 0,000,050,901
FNV1A_Pippip           : KT_DumpCounter = 0,011,005,853,697; 000,000,001 x MAXcollisionsAtSomeSlots = 000,038; HASHfreeSLOTS = 0,000,040,196
XXH3_64bits            : KT_DumpCounter = 0,011,005,853,697; 000,000,001 x MAXcollisionsAtSomeSlots = 000,035; HASHfreeSLOTS = 0,000,039,650
FNV1A_Pippip           : KT_DumpCounter = 0,011,274,289,153; 000,000,001 x MAXcollisionsAtSomeSlots = 000,038; HASHfreeSLOTS = 0,000,031,400
XXH3_64bits            : KT_DumpCounter = 0,011,274,289,153; 000,000,001 x MAXcollisionsAtSomeSlots = 000,036; HASHfreeSLOTS = 0,000,030,895
FNV1A_Pippip           : KT_DumpCounter = 0,011,542,724,609; 000,000,001 x MAXcollisionsAtSomeSlots = 000,038; HASHfreeSLOTS = 0,000,024,566
XXH3_64bits            : KT_DumpCounter = 0,011,542,724,609; 000,000,001 x MAXcollisionsAtSomeSlots = 000,037; HASHfreeSLOTS = 0,000,024,118
FNV1A_Pippip           : KT_DumpCounter = 0,011,811,160,065; 000,000,001 x MAXcollisionsAtSomeSlots = 000,040; HASHfreeSLOTS = 0,000,019,239
XXH3_64bits            : KT_DumpCounter = 0,011,811,160,065; 000,000,001 x MAXcollisionsAtSomeSlots = 000,037; HASHfreeSLOTS = 0,000,018,923
FNV1A_Pippip           : KT_DumpCounter = 0,012,079,595,521; 000,000,001 x MAXcollisionsAtSomeSlots = 000,040; HASHfreeSLOTS = 0,000,015,049
XXH3_64bits            : KT_DumpCounter = 0,012,079,595,521; 000,000,001 x MAXcollisionsAtSomeSlots = 000,037; HASHfreeSLOTS = 0,000,014,735
FNV1A_Pippip           : KT_DumpCounter = 0,012,348,030,977; 000,000,001 x MAXcollisionsAtSomeSlots = 000,040; HASHfreeSLOTS = 0,000,011,651
XXH3_64bits            : KT_DumpCounter = 0,012,348,030,977; 000,000,001 x MAXcollisionsAtSomeSlots = 000,037; HASHfreeSLOTS = 0,000,011,536
FNV1A_Pippip           : KT_DumpCounter = 0,012,616,466,433; 000,000,001 x MAXcollisionsAtSomeSlots = 000,040; HASHfreeSLOTS = 0,000,009,159
XXH3_64bits            : KT_DumpCounter = 0,012,616,466,433; 000,000,001 x MAXcollisionsAtSomeSlots = 000,038; HASHfreeSLOTS = 0,000,008,982
FNV1A_Pippip           : KT_DumpCounter = 0,012,884,901,889; 000,000,001 x MAXcollisionsAtSomeSlots = 000,040; HASHfreeSLOTS = 0,000,007,152
XXH3_64bits            : KT_DumpCounter = 0,012,884,901,889; 000,000,001 x MAXcollisionsAtSomeSlots = 000,038; HASHfreeSLOTS = 0,000,006,985
FNV1A_Pippip           : KT_DumpCounter = 0,013,153,337,345; 000,000,001 x MAXcollisionsAtSomeSlots = 000,040; HASHfreeSLOTS = 0,000,005,658
XXH3_64bits            : KT_DumpCounter = 0,013,153,337,345; 000,000,001 x MAXcollisionsAtSomeSlots = 000,038; HASHfreeSLOTS = 0,000,005,462
FNV1A_Pippip           : KT_DumpCounter = 0,013,421,772,801; 000,000,001 x MAXcollisionsAtSomeSlots = 000,040; HASHfreeSLOTS = 0,000,004,446
XXH3_64bits            : KT_DumpCounter = 0,013,421,772,801; 000,000,002 x MAXcollisionsAtSomeSlots = 000,038; HASHfreeSLOTS = 0,000,004,227
FNV1A_Pippip           : KT_DumpCounter = 0,013,690,208,257; 000,000,001 x MAXcollisionsAtSomeSlots = 000,040; HASHfreeSLOTS = 0,000,003,503
XXH3_64bits            : KT_DumpCounter = 0,013,690,208,257; 000,000,007 x MAXcollisionsAtSomeSlots = 000,038; HASHfreeSLOTS = 0,000,003,270
FNV1A_Pippip           : KT_DumpCounter = 0,013,958,643,713; 000,000,001 x MAXcollisionsAtSomeSlots = 000,040; HASHfreeSLOTS = 0,000,002,725
XXH3_64bits            : KT_DumpCounter = 0,013,958,643,713; 000,000,001 x MAXcollisionsAtSomeSlots = 000,039; HASHfreeSLOTS = 0,000,002,540
FNV1A_Pippip           : KT_DumpCounter = 0,014,227,079,169; 000,000,001 x MAXcollisionsAtSomeSlots = 000,040; HASHfreeSLOTS = 0,000,002,082
XXH3_64bits            : KT_DumpCounter = 0,014,227,079,169; 000,000,001 x MAXcollisionsAtSomeSlots = 000,040; HASHfreeSLOTS = 0,000,001,934
FNV1A_Pippip           : KT_DumpCounter = 0,014,495,514,625; 000,000,001 x MAXcollisionsAtSomeSlots = 000,041; HASHfreeSLOTS = 0,000,001,616
XXH3_64bits            : KT_DumpCounter = 0,014,495,514,625; 000,000,001 x MAXcollisionsAtSomeSlots = 000,041; HASHfreeSLOTS = 0,000,001,531
FNV1A_Pippip           : KT_DumpCounter = 0,014,763,950,081; 000,000,001 x MAXcollisionsAtSomeSlots = 000,041; HASHfreeSLOTS = 0,000,001,246
XXH3_64bits            : KT_DumpCounter = 0,014,763,950,081; 000,000,003 x MAXcollisionsAtSomeSlots = 000,041; HASHfreeSLOTS = 0,000,001,205
FNV1A_Pippip           : KT_DumpCounter = 0,015,032,385,537; 000,000,001 x MAXcollisionsAtSomeSlots = 000,042; HASHfreeSLOTS = 0,000,000,962
XXH3_64bits            : KT_DumpCounter = 0,015,032,385,537; 000,000,001 x MAXcollisionsAtSomeSlots = 000,042; HASHfreeSLOTS = 0,000,000,938
FNV1A_Pippip           : KT_DumpCounter = 0,015,300,820,993; 000,000,001 x MAXcollisionsAtSomeSlots = 000,042; HASHfreeSLOTS = 0,000,000,745
XXH3_64bits            : KT_DumpCounter = 0,015,300,820,993; 000,000,001 x MAXcollisionsAtSomeSlots = 000,042; HASHfreeSLOTS = 0,000,000,707
FNV1A_Pippip           : KT_DumpCounter = 0,015,569,256,449; 000,000,001 x MAXcollisionsAtSomeSlots = 000,042; HASHfreeSLOTS = 0,000,000,579
XXH3_64bits            : KT_DumpCounter = 0,015,569,256,449; 000,000,003 x MAXcollisionsAtSomeSlots = 000,042; HASHfreeSLOTS = 0,000,000,568
FNV1A_Pippip           : KT_DumpCounter = 0,015,837,691,905; 000,000,004 x MAXcollisionsAtSomeSlots = 000,042; HASHfreeSLOTS = 0,000,000,452
XXH3_64bits            : KT_DumpCounter = 0,015,837,691,905; 000,000,006 x MAXcollisionsAtSomeSlots = 000,042; HASHfreeSLOTS = 0,000,000,449
FNV1A_Pippip           : KT_DumpCounter = 0,016,106,127,361; 000,000,006 x MAXcollisionsAtSomeSlots = 000,042; HASHfreeSLOTS = 0,000,000,337
XXH3_64bits            : KT_DumpCounter = 0,016,106,127,361; 000,000,001 x MAXcollisionsAtSomeSlots = 000,043; HASHfreeSLOTS = 0,000,000,344
FNV1A_Pippip           : KT_DumpCounter = 0,016,374,562,817; 000,000,002 x MAXcollisionsAtSomeSlots = 000,043; HASHfreeSLOTS = 0,000,000,264
XXH3_64bits            : KT_DumpCounter = 0,016,374,562,817; 000,000,003 x MAXcollisionsAtSomeSlots = 000,043; HASHfreeSLOTS = 0,000,000,277
FNV1A_Pippip           : KT_DumpCounter = 0,016,642,998,273; 000,000,001 x MAXcollisionsAtSomeSlots = 000,044; HASHfreeSLOTS = 0,000,000,204
XXH3_64bits            : KT_DumpCounter = 0,016,642,998,273; 000,000,001 x MAXcollisionsAtSomeSlots = 000,044; HASHfreeSLOTS = 0,000,000,215
FNV1A_Pippip           : KT_DumpCounter = 0,016,911,433,729; 000,000,001 x MAXcollisionsAtSomeSlots = 000,045; HASHfreeSLOTS = 0,000,000,158
XXH3_64bits            : KT_DumpCounter = 0,016,911,433,729; 000,000,002 x MAXcollisionsAtSomeSlots = 000,044; HASHfreeSLOTS = 0,000,000,176
FNV1A_Pippip           : KT_DumpCounter = 0,017,179,869,185; 000,000,001 x MAXcollisionsAtSomeSlots = 000,045; HASHfreeSLOTS = 0,000,000,132
XXH3_64bits            : KT_DumpCounter = 0,017,179,869,185; 000,000,001 x MAXcollisionsAtSomeSlots = 000,045; HASHfreeSLOTS = 0,000,000,140
FNV1A_Pippip           : KT_DumpCounter = 0,017,448,304,641; 000,000,001 x MAXcollisionsAtSomeSlots = 000,046; HASHfreeSLOTS = 0,000,000,110
XXH3_64bits            : KT_DumpCounter = 0,017,448,304,641; 000,000,003 x MAXcollisionsAtSomeSlots = 000,045; HASHfreeSLOTS = 0,000,000,107
FNV1A_Pippip           : KT_DumpCounter = 0,017,716,740,097; 000,000,002 x MAXcollisionsAtSomeSlots = 000,046; HASHfreeSLOTS = 0,000,000,084
XXH3_64bits            : KT_DumpCounter = 0,017,716,740,097; 000,000,004 x MAXcollisionsAtSomeSlots = 000,045; HASHfreeSLOTS = 0,000,000,083
FNV1A_Pippip           : KT_DumpCounter = 0,017,985,175,553; 000,000,004 x MAXcollisionsAtSomeSlots = 000,046; HASHfreeSLOTS = 0,000,000,068
XXH3_64bits            : KT_DumpCounter = 0,017,985,175,553; 000,000,001 x MAXcollisionsAtSomeSlots = 000,046; HASHfreeSLOTS = 0,000,000,066
FNV1A_Pippip           : KT_DumpCounter = 0,018,253,611,009; 000,000,001 x MAXcollisionsAtSomeSlots = 000,048; HASHfreeSLOTS = 0,000,000,052
XXH3_64bits            : KT_DumpCounter = 0,018,253,611,009; 000,000,001 x MAXcollisionsAtSomeSlots = 000,047; HASHfreeSLOTS = 0,000,000,056
FNV1A_Pippip           : KT_DumpCounter = 0,018,522,046,465; 000,000,002 x MAXcollisionsAtSomeSlots = 000,048; HASHfreeSLOTS = 0,000,000,040
XXH3_64bits            : KT_DumpCounter = 0,018,522,046,465; 000,000,001 x MAXcollisionsAtSomeSlots = 000,049; HASHfreeSLOTS = 0,000,000,039
FNV1A_Pippip           : KT_DumpCounter = 0,018,790,481,921; 000,000,003 x MAXcollisionsAtSomeSlots = 000,048; HASHfreeSLOTS = 0,000,000,032
XXH3_64bits            : KT_DumpCounter = 0,018,790,481,921; 000,000,001 x MAXcollisionsAtSomeSlots = 000,050; HASHfreeSLOTS = 0,000,000,028
FNV1A_Pippip           : KT_DumpCounter = 0,019,058,917,377; 000,000,002 x MAXcollisionsAtSomeSlots = 000,049; HASHfreeSLOTS = 0,000,000,022
XXH3_64bits            : KT_DumpCounter = 0,019,058,917,377; 000,000,001 x MAXcollisionsAtSomeSlots = 000,050; HASHfreeSLOTS = 0,000,000,019
FNV1A_Pippip           : KT_DumpCounter = 0,019,327,352,833; 000,000,002 x MAXcollisionsAtSomeSlots = 000,049; HASHfreeSLOTS = 0,000,000,018
XXH3_64bits            : KT_DumpCounter = 0,019,327,352,833; 000,000,001 x MAXcollisionsAtSomeSlots = 000,050; HASHfreeSLOTS = 0,000,000,014
FNV1A_Pippip           : KT_DumpCounter = 0,019,595,788,289; 000,000,003 x MAXcollisionsAtSomeSlots = 000,049; HASHfreeSLOTS = 0,000,000,015
XXH3_64bits            : KT_DumpCounter = 0,019,595,788,289; 000,000,001 x MAXcollisionsAtSomeSlots = 000,050; HASHfreeSLOTS = 0,000,000,013
FNV1A_Pippip           : KT_DumpCounter = 0,019,864,223,745; 000,000,004 x MAXcollisionsAtSomeSlots = 000,049; HASHfreeSLOTS = 0,000,000,013
XXH3_64bits            : KT_DumpCounter = 0,019,864,223,745; 000,000,001 x MAXcollisionsAtSomeSlots = 000,050; HASHfreeSLOTS = 0,000,000,010
FNV1A_Pippip           : KT_DumpCounter = 0,020,132,659,201; 000,000,005 x MAXcollisionsAtSomeSlots = 000,049; HASHfreeSLOTS = 0,000,000,012
XXH3_64bits            : KT_DumpCounter = 0,020,132,659,201; 000,000,001 x MAXcollisionsAtSomeSlots = 000,051; HASHfreeSLOTS = 0,000,000,009
FNV1A_Pippip           : KT_DumpCounter = 0,020,401,094,657; 000,000,007 x MAXcollisionsAtSomeSlots = 000,049; HASHfreeSLOTS = 0,000,000,010
XXH3_64bits            : KT_DumpCounter = 0,020,401,094,657; 000,000,001 x MAXcollisionsAtSomeSlots = 000,051; HASHfreeSLOTS = 0,000,000,006
FNV1A_Pippip           : KT_DumpCounter = 0,020,669,530,113; 000,000,001 x MAXcollisionsAtSomeSlots = 000,050; HASHfreeSLOTS = 0,000,000,010
XXH3_64bits            : KT_DumpCounter = 0,020,669,530,113; 000,000,001 x MAXcollisionsAtSomeSlots = 000,052; HASHfreeSLOTS = 0,000,000,005
FNV1A_Pippip           : KT_DumpCounter = 0,020,937,965,569; 000,000,001 x MAXcollisionsAtSomeSlots = 000,051; HASHfreeSLOTS = 0,000,000,007
XXH3_64bits            : KT_DumpCounter = 0,020,937,965,569; 000,000,001 x MAXcollisionsAtSomeSlots = 000,052; HASHfreeSLOTS = 0,000,000,005
FNV1A_Pippip           : KT_DumpCounter = 0,021,206,401,025; 000,000,002 x MAXcollisionsAtSomeSlots = 000,051; HASHfreeSLOTS = 0,000,000,005
XXH3_64bits            : KT_DumpCounter = 0,021,206,401,025; 000,000,001 x MAXcollisionsAtSomeSlots = 000,052; HASHfreeSLOTS = 0,000,000,004
FNV1A_Pippip           : KT_DumpCounter = 0,021,474,836,481; 000,000,002 x MAXcollisionsAtSomeSlots = 000,052; HASHfreeSLOTS = 0,000,000,003
XXH3_64bits            : KT_DumpCounter = 0,021,474,836,481; 000,000,001 x MAXcollisionsAtSomeSlots = 000,053; HASHfreeSLOTS = 0,000,000,003
...

Who will fill the 30bit table first... to be continued.

To reproduce it, I uploaded the C source and binary to IDZ forum: https://software.intel.com/en-us/forums/intel-moderncode-for-parallel-architectures/topic/824947#comment-1947420

Yann, do you have ideas about collision benchmarking, my wish is to make a preliminary (a farcry from the in-depth digging SMHASHER) package of tests where doubters and naysayers are allowed to put all hashers to the test? To gather a preliminary stats, you know.

Cyan4973 commented 5 years ago

do you have ideas about collision benchmarking

I do have a large-scale collision analyzer, with which collision performance on 64-bit hashes can be measured accurately (provided the system offers enough memory to do so), but it's not open source yet. I will have to work a bit more on it to include it into the repository.

In the meantime, SMHasher can offer decent collision performance analysis, notably by using the sparse dataset, which is the most difficult one, and can ramp up to large nb of hashes. It's not enough to "prove" that a hash is really 64-bit, but it can already help detecting a hash which is not.

Sanmayce commented 4 years ago

@Cyan4973

I'm not even sure if it supports very small keys of a few bytes

Okay, found time to test ALL keys with lengths 5,6,7,8 bytes within three of my testfiles:

42,920,232 (Dictionary_Specification_Language_(ABBYY_Software_House))_Hanyu_Cihai_new_Sea-of-Words_(Zho-Zho).dsl
15,583,440 Arabian_Nights_complete.html
 5,784,758 KAZE_www.gutenberg.org_ebooks_100.txt

For 'Shakespeare', the first power of 2 bigger than 5,784,758:

----------------------------------------------------------------------------
Hasher, Hashtable in bits   | Hash Collisions = Distinct_KEYs - Used_Slots |
----------------------------|-----------------------------------------------
Pippip, 23bits, All 5 bytes |   4,939 = Distinct_KEYs - 280,595
XXH64,  23bits, All 5 bytes |   4,895 = Distinct_KEYs - 280,639
----------------------------------------------------------------------------
Pippip, 23bits, All 6 bytes |  25,688 = Distinct_KEYs - 642,077
XXH64,  23bits, All 6 bytes |  26,024 = Distinct_KEYs - 641,741
----------------------------------------------------------------------------
Pippip, 23bits, All 7 bytes |  85,849 = Distinct_KEYs - 1,146,732
XXH64,  23bits, All 7 bytes |  85,821 = Distinct_KEYs - 1,146,760
----------------------------------------------------------------------------
Pippip, 23bits, All 8 bytes | 204,662 = Distinct_KEYs - 1,715,415
XXH64,  23bits, All 8 bytes | 204,271 = Distinct_KEYs - 1,715,806
----------------------------------------------------------------------------

For '1001 Nights', the first power of 2 bigger than 15,583,440:

----------------------------------------------------------------------------
Hasher, Hashtable in bits   | Hash Collisions = Distinct_KEYs - Used_Slots |
----------------------------|-----------------------------------------------
Pippip, 24bits, All 5 bytes |   8,947 = Distinct_KEYs - 543,708
XXH64,  24bits, All 5 bytes |   9,123 = Distinct_KEYs - 543,532
----------------------------------------------------------------------------
Pippip, 24bits, All 6 bytes |  40,843 = Distinct_KEYs - 1,145,254
XXH64,  24bits, All 6 bytes |  41,077 = Distinct_KEYs - 1,145,020
----------------------------------------------------------------------------
Pippip, 24bits, All 7 bytes | 127,494 = Distinct_KEYs - 1,981,479
XXH64,  24bits, All 7 bytes | 127,216 = Distinct_KEYs - 1,981,757
----------------------------------------------------------------------------
Pippip, 24bits, All 8 bytes | 302,909 = Distinct_KEYs - 2,987,567
XXH64,  24bits, All 8 bytes | 302,357 = Distinct_KEYs - 2,988,119
----------------------------------------------------------------------------

For 'Sea-Of-Words', the first power of 2 bigger than 42,920,232:

----------------------------------------------------------------------------
Hasher, Hashtable in bits   | Hash Collisions = Distinct_KEYs - Used_Slots |
----------------------------|-----------------------------------------------
Pippip, 26bits, All 5 bytes |   328,636 = Distinct_KEYs - 6,424,985
XXH64,  26bits, All 5 bytes |   327,709 = Distinct_KEYs - 6,425,912
----------------------------------------------------------------------------
Pippip, 26bits, All 6 bytes |   675,528 = Distinct_KEYs - 9,069,787
XXH64,  26bits, All 6 bytes |   674,475 = Distinct_KEYs - 9,070,840
----------------------------------------------------------------------------
Pippip, 26bits, All 7 bytes | 1,036,307 = Distinct_KEYs - 11,109,915
XXH64,  26bits, All 7 bytes | 1,035,309 = Distinct_KEYs - 11,110,913
----------------------------------------------------------------------------
Pippip, 26bits, All 8 bytes | 1,414,710 = Distinct_KEYs - 12,507,408
XXH64,  26bits, All 8 bytes | 1,352,172 = Distinct_KEYs - 12,569,946
----------------------------------------------------------------------------

The only noticeable degradation of Pippip is seen in 'Unicode' encoding with 8 bytes long keys - losing all those highest bits matters, however the speed/collisions trade-off is in the desired margins.

In the hurry, mistakenly used the XXH64 instead of XXH3, I'm sorry about that, but the point was to compare one good finalizer of the XXh family against the poor Pippip's finalizer - my wish was to get those high 64 bits of 64x64 and fold them to the final hash, not doing so, still.

Also, in the hurry, lost the dump of XXH3 vs Pippip in 1 trillion Knight-Tours, yet I remember the collisions - clear victory for XXH3 all the way, at one trillion mark it was better only 5 or 7 collisions, Pippip made good.

Currently, the superweak finalizer (1..8 lengths) is superfast WHILE BEING PRACTICAL, I reckon. When have time will run enwik9.

Sanmayce commented 4 years ago

@hordi @rurban @dumblob

Two last things.

Found the dump for KT, 1000:1 ratio, that is, 1 trillion keys vs 1 billion slots:

...
FNV1A_Pippip           : KT_DumpCounter = 0,022,280,142,849; 000,000,002 x MAXcollisionsAtSomeSlots = 000,054; HASHfreeSLOTS = 0,000,000,000
XXH3_64bits            : KT_DumpCounter = 0,022,280,142,849; 000,000,002 x MAXcollisionsAtSomeSlots = 000,053; HASHfreeSLOTS = 0,000,000,002
FNV1A_Pippip           : KT_DumpCounter = 0,022,548,578,305; 000,000,001 x MAXcollisionsAtSomeSlots = 000,055; HASHfreeSLOTS = 0,000,000,000
XXH3_64bits            : KT_DumpCounter = 0,022,548,578,305; 000,000,001 x MAXcollisionsAtSomeSlots = 000,054; HASHfreeSLOTS = 0,000,000,001
FNV1A_Pippip           : KT_DumpCounter = 0,022,817,013,761; 000,000,002 x MAXcollisionsAtSomeSlots = 000,055; HASHfreeSLOTS = 0,000,000,000
XXH3_64bits            : KT_DumpCounter = 0,022,817,013,761; 000,000,001 x MAXcollisionsAtSomeSlots = 000,055; HASHfreeSLOTS = 0,000,000,001
FNV1A_Pippip           : KT_DumpCounter = 0,023,085,449,217; 000,000,003 x MAXcollisionsAtSomeSlots = 000,055; HASHfreeSLOTS = 0,000,000,000
XXH3_64bits            : KT_DumpCounter = 0,023,085,449,217; 000,000,001 x MAXcollisionsAtSomeSlots = 000,055; HASHfreeSLOTS = 0,000,000,001
FNV1A_Pippip           : KT_DumpCounter = 0,023,353,884,673; 000,000,004 x MAXcollisionsAtSomeSlots = 000,055; HASHfreeSLOTS = 0,000,000,000
XXH3_64bits            : KT_DumpCounter = 0,023,353,884,673; 000,000,001 x MAXcollisionsAtSomeSlots = 000,055; HASHfreeSLOTS = 0,000,000,001
FNV1A_Pippip           : KT_DumpCounter = 0,023,622,320,129; 000,000,001 x MAXcollisionsAtSomeSlots = 000,056; HASHfreeSLOTS = 0,000,000,000
XXH3_64bits            : KT_DumpCounter = 0,023,622,320,129; 000,000,001 x MAXcollisionsAtSomeSlots = 000,055; HASHfreeSLOTS = 0,000,000,000
...
FNV1A_Pippip           : KT_DumpCounter = 1,027,839,361,025; 000,000,001 x MAXcollisionsAtSomeSlots = 001,158; HASHfreeSLOTS = 0,000,000,000
XXH3_64bits            : KT_DumpCounter = 1,027,839,361,025; 000,000,001 x MAXcollisionsAtSomeSlots = 001,152; HASHfreeSLOTS = 0,000,000,000

And, for 'enwik9', the first power of 2 bigger than 1,000,000,000:

----------------------------------------------------------------------------
Hasher, Hashtable in bits   | Hash Collisions = Distinct_KEYs - Used_Slots |
----------------------------|-----------------------------------------------
Pippip, 30bits, All 5 bytes |    60,568 = Distinct_KEYs - 11,314,689
XXH64,  30bits, All 5 bytes |    60,061 = Distinct_KEYs - 11,315,196
----------------------------------------------------------------------------
Pippip, 30bits, All 6 bytes |   369,173 = Distinct_KEYs - 27,876,238
XXH64,  30bits, All 6 bytes |   368,351 = Distinct_KEYs - 27,877,060
----------------------------------------------------------------------------
Pippip, 30bits, All 7 bytes | 1,320,750 = Distinct_KEYs - 52,404,876
XXH64,  30bits, All 7 bytes | 1,323,587 = Distinct_KEYs - 52,402,039
----------------------------------------------------------------------------
Pippip, 30bits, All 8 bytes | 3,506,053 = Distinct_KEYs - 84,445,511
XXH64,  30bits, All 8 bytes | 3,507,552 = Distinct_KEYs - 84,444,012
----------------------------------------------------------------------------

Hm, didn't expect that for Building-Blocks order 8, and UTF-8 encoding, Pippip hashes quite well the 7 and 8 zona ... perduta.