Hmmm... I think I'm biased a bit because of something I'm writing recently where different iterations of a loop were independent.
That's a great place to be in :D.
BTW, I haven't tried to get implement an hash function in a while (I remember playing with carryless multiplication), but IIRC 6 clock cycles is not too bad.
12 cycles of latency. CONST1 and CONST3 must be odd (bottom bit is 1). Pick CONST1, CONST2, and CONST3 out of /dev/urandom.
--------
BTW: This is exactly why latency didn't matter, because the 12-cycles of latency here are basically independent between loops. The next loop iteration would cut-the-dependency on RAX, allowing the next loop iteration's "RAX" to get a new register and execute independently.
--------
AESEnc is a good baseline, but you need 2 or 3 iterations of it to work well. AESEnc also works on 128-bit vector registers, but most people want something that works on the 64-bit registers.
If your data was already in XMM registers, AESEnc / AESDec will be great. Otherwise, 64-bit multiply is really good at shuffling those bits around. Take RAX (64-bit result), EAX (32-bit result), AX (16-bit result), or AL (8-bit result) as needed.
After Multiply / BSwap / Multiply, all 64-bits will be "high quality". The XOR "shifts the zero" (I don't like the fact that Hash(0) == 0 personally), but honestly I haven't been able to figure out a statistical change in my testing. So I guess the XOR is optional.
Comments
Actually no, latency is usually a bottleneck before throughput is.
Edit: for example when accessing an hash table, the hash computation is in the critical path.
Hmmm... I think I'm biased a bit because of something I'm writing recently where different iterations of a loop were independent.
In this case, you're right. The hash calculation is on the critical path and therefore is latency bound.
That's a great place to be in :D.
BTW, I haven't tried to get implement an hash function in a while (I remember playing with carryless multiplication), but IIRC 6 clock cycles is not too bad.
Multiply RAX, CONST1 / bswap RAX / XOR RAX, CONST2 / Multiply RAX, CONST3.
12 cycles of latency. CONST1 and CONST3 must be odd (bottom bit is 1). Pick CONST1, CONST2, and CONST3 out of /dev/urandom.
--------
BTW: This is exactly why latency didn't matter, because the 12-cycles of latency here are basically independent between loops. The next loop iteration would cut-the-dependency on RAX, allowing the next loop iteration's "RAX" to get a new register and execute independently.
--------
AESEnc is a good baseline, but you need 2 or 3 iterations of it to work well. AESEnc also works on 128-bit vector registers, but most people want something that works on the 64-bit registers.
If your data was already in XMM registers, AESEnc / AESDec will be great. Otherwise, 64-bit multiply is really good at shuffling those bits around. Take RAX (64-bit result), EAX (32-bit result), AX (16-bit result), or AL (8-bit result) as needed.
If you are multiplying (or using any other t-function) for mixing, you generally want the higher bits, rather than the lower bits.
Think about what bswap does: https://c9x.me/x86/html/file_module_x86_id_21.html
After Multiply / BSwap / Multiply, all 64-bits will be "high quality". The XOR "shifts the zero" (I don't like the fact that Hash(0) == 0 personally), but honestly I haven't been able to figure out a statistical change in my testing. So I guess the XOR is optional.
er. confession: I somehow only read the last two sentences in your post!