Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Runtime] Improve the metadata hashing function.
The inputs to the hash function is pointers that have a predictable patten. The hashes that we were generating and using for the metadata caches were not very good, and as a result we generated very deep search trees. A small change that improved the utilization of the 'length' field and another bit-rotate round improved the quality of the hash function. I am going to attach to the github commit two pictures. The first picture is the binary with the old hash. The first tree is very deep and sparse. The second picture is with the new hash function and the tree is very wide and uniform. I used the benchmark 'TypeFlood' in debug mode to generate huge amounts of metadata.
- Loading branch information
4227645
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The two pictures below show the shape of the internal data structure used by the metadata caches.
Before:
After:
4227645
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sweeeeeet
4227645
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Amazing, would be interesting be see the speed improvements related to this change.
4227645
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome!
4227645
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ER: playgrounds should display the bucket graph for
Dictionary
s4227645
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nadavrot Can you thumbnail those images? My browser struggles on the image decode when loading this page...
4227645
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You might also consider changing entirely the hash function by some proven ones with excellent dispersion and speed. See for example this excellent article which makes a great job at comparing several hash algorithms for their speed and dispersion.
Better dispersion == smaller tree depth.
A PRIMER ON REPEATABLE RANDOM NUMBERS, by RUNE SKOVBO JOHANSEN
4227645
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be even better to not roll our own, and just use llvm Hashing.h or std::hash (if all of our platforms are new enough). In fact, the issue of bad balancing in the tree was caused by us writing our own hash function in the first place.
4227645
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@gribozavr Using LLVM's hash is not a very good idea. We hash our metadata pointers very frequently and LLVM's hash is way too slow. Most Swift programs have a small number of generic types at runtime, which means that we have a small number of entries in the tree, but we calculate the hash and perform the lookup very frequently. This means that a low-quality hash that runs very fast outperforms a slow hash that does a very good job. Another problem that we have is that the number if inputs to our hash function is typically very small (1 to 3 pointers) and we need to ensure that we have as much entropy in the high bits, even for the small inputs. A non-specialized hash, like LLVM's, can only do this at the cost of a high runtime (by doing lots of operations that blend the bits, such as multiplication and rotation). Another requirement that we have is the support for both 32bits and 64bits. We need the hash to be fast and effective on 32bit platforms, and LLVM is 64bits only.
4227645
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nadavrot OK, here's another hash with known good properties:
https://131002.net/siphash/
The performance is discussed in https://131002.net/siphash/siphash.pdf on page 13.
4227645
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
siphash has very poor performance in 32-bits mode unfortunately,
which doesn't meet @nadavrot requirement.
Most modern fast hashes are tailored for 64-bits CPU, since they run faster using this mode.
So it leaves only a handful which remain fast on 32-bits targets.
This benchmark was specifically run on 32-bits.
Now it also seems that another requirement is to work on short keys, which isn't uncommon.
That also could be tested with a benchmark.
The SMHasher test set for example includes a benchmark module for small keys.
edit : @nadavrot : sorry, crossed posts by a few seconds ...
4227645
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@gribozavr SipHash is a bad candidate for two reasons. First, it is slow (optimistically 15 cycles per byte), which is an order of magnitude slower than what we use today. And Second, it requires at least 16 bytes of inputs, which we don't always have.
4227645
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could use different functions for 32 and 64-bit targets.
4227645
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure.
In general, the gains from 32 to 64 bits makes it worthwhile.
Two caveats though :
Once again, only benchmarking will tell...
4227645
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 💯