Permalink
15 comments
on commit
sign in to comment.
Browse files
[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...
This comment has been minimized.
nadavrotFeb 10, 2016
ContributorThe two pictures below show the shape of the internal data structure used by the metadata caches.
Before:
After:

nadavrot repliedFeb 10, 2016
The two pictures below show the shape of the internal data structure used by the metadata caches.
Before:
After:

This comment has been minimized.
dduanFeb 10, 2016
CollaboratorSweeeeeet
dduan repliedFeb 10, 2016
Sweeeeeet
This comment has been minimized.
kostiakovalFeb 10, 2016
CollaboratorAmazing, would be interesting be see the speed improvements related to this change.
kostiakoval repliedFeb 10, 2016
Amazing, would be interesting be see the speed improvements related to this change.
This comment has been minimized.
jckarterFeb 10, 2016
MemberAwesome!
jckarter repliedFeb 10, 2016
Awesome!
This comment has been minimized.
jckarterFeb 10, 2016
MemberER: playgrounds should display the bucket graph for
Dictionarysjckarter repliedFeb 10, 2016
ER: playgrounds should display the bucket graph for
DictionarysThis comment has been minimized.
rikingFeb 11, 2016
@nadavrot Can you thumbnail those images? My browser struggles on the image decode when loading this page...
riking repliedFeb 11, 2016
@nadavrot Can you thumbnail those images? My browser struggles on the image decode when loading this page...
This comment has been minimized.
Cyan4973Feb 12, 2016
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
Cyan4973 repliedFeb 12, 2016
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
This comment has been minimized.
gribozavrFeb 12, 2016
CollaboratorIt 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.
gribozavr repliedFeb 12, 2016
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.
This comment has been minimized.
nadavrotFeb 12, 2016
Contributor@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.
nadavrot repliedFeb 12, 2016
@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.
This comment has been minimized.
gribozavrFeb 12, 2016
Collaborator@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.
gribozavr repliedFeb 12, 2016
@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.
This comment has been minimized.
Cyan4973Feb 12, 2016
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 ...
Cyan4973 repliedFeb 12, 2016
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 ...
This comment has been minimized.
nadavrotFeb 12, 2016
Contributor@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.
nadavrot repliedFeb 12, 2016
@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.
This comment has been minimized.
gribozavrFeb 12, 2016
CollaboratorWe could use different functions for 32 and 64-bit targets.
gribozavr repliedFeb 12, 2016
We could use different functions for 32 and 64-bit targets.
This comment has been minimized.
Cyan4973Feb 12, 2016
Sure.
In general, the gains from 32 to 64 bits makes it worthwhile.
Two caveats though :
Once again, only benchmarking will tell...
Cyan4973 repliedFeb 12, 2016
Sure.
In general, the gains from 32 to 64 bits makes it worthwhile.
Two caveats though :
Once again, only benchmarking will tell...
This comment has been minimized.
rudkxFeb 13, 2016
Memberrudkx repliedFeb 13, 2016