Title: [128650] trunk/Source
Revision
128650
Author
[email protected]
Date
2012-09-14 14:00:20 -0700 (Fri, 14 Sep 2012)

Log Message

Minimize collisions when hashing pairs
https://bugs.webkit.org/show_bug.cgi?id=96022

Reviewed by Adrienne Walker.

Source/WebCore:

Use WTF::pairIntHash() to hash pairs of integers.

* dom/Document.cpp:
(WebCore::ImmutableAttributeDataCacheKey::hash):
* dom/StyledElement.cpp:
(WebCore::computePresentationAttributeCacheHash):
* platform/graphics/Gradient.cpp:
(WebCore::Gradient::hash):
* platform/graphics/IntPointHash.h:
(WTF::IntPointHash::hash):
* platform/graphics/IntRectHash.h:
* platform/graphics/IntSizeHash.h:
* platform/graphics/blackberry/LayerTileIndex.h:
* platform/graphics/cg/GraphicsContextCG.cpp:
(WebCore::SubimageCacheHash::hash):

Source/WebKit/blackberry:

Use WTF::pairIntHash() to hash a pair of integers.

* WebKitSupport/TileIndexHash.h:

Source/WTF:

The current hash function for pairs has poor performance as it does a
nice hash function on 64 bits, but then just drops the top 32 bits. The
hash method for pairs tries to use Thomas Wang's 64 bit Mix Function,
but this requires not dropping any bits in order to retain the
characteristics mentioned by Thomas.

A better method of hashing sets of 32-bit integers is to use
multiplication in 64 bits with random integers. This method is a
provably almost-universal hash function. Testing shows that this
method decreases the time required, when compared with the current
method, by more than 20% due to better hashing characteristics.

* wtf/HashFunctions.h:
(WTF):
(WTF::pairIntHash):
Implments the hashing method for a pair of unsigned integers.

(WTF::PairHash::hash):
Use pairIntHash() on the hash results of each object in the pair.

(WTF::IntPairHash::hash):
Implement an integer-specific PairHash class that does not need to
hash each object in the pair. It uses pairIntHash on the two
integers in the pair directly.

(WTF::IntPairHash::equal):
(IntPairHash):

Modified Paths

Diff

Modified: trunk/Source/WTF/ChangeLog (128649 => 128650)


--- trunk/Source/WTF/ChangeLog	2012-09-14 20:51:13 UTC (rev 128649)
+++ trunk/Source/WTF/ChangeLog	2012-09-14 21:00:20 UTC (rev 128650)
@@ -1,3 +1,38 @@
+2012-09-14  Dana Jansens  <[email protected]>
+
+        Minimize collisions when hashing pairs
+        https://bugs.webkit.org/show_bug.cgi?id=96022
+
+        Reviewed by Adrienne Walker.
+
+        The current hash function for pairs has poor performance as it does a
+        nice hash function on 64 bits, but then just drops the top 32 bits. The
+        hash method for pairs tries to use Thomas Wang's 64 bit Mix Function,
+        but this requires not dropping any bits in order to retain the
+        characteristics mentioned by Thomas.
+
+        A better method of hashing sets of 32-bit integers is to use
+        multiplication in 64 bits with random integers. This method is a
+        provably almost-universal hash function. Testing shows that this
+        method decreases the time required, when compared with the current
+        method, by more than 20% due to better hashing characteristics.
+
+        * wtf/HashFunctions.h:
+        (WTF):
+        (WTF::pairIntHash):
+        Implments the hashing method for a pair of unsigned integers.
+
+        (WTF::PairHash::hash):
+        Use pairIntHash() on the hash results of each object in the pair.
+
+        (WTF::IntPairHash::hash):
+        Implement an integer-specific PairHash class that does not need to
+        hash each object in the pair. It uses pairIntHash on the two
+        integers in the pair directly.
+
+        (WTF::IntPairHash::equal):
+        (IntPairHash):
+
 2012-09-14  Tor Arne Vestbø  <[email protected]>
 
         [Qt] Make force_static_libs_as_shared work on Mac OS

Modified: trunk/Source/WTF/wtf/HashFunctions.h (128649 => 128650)


--- trunk/Source/WTF/wtf/HashFunctions.h	2012-09-14 20:51:13 UTC (rev 128649)
+++ trunk/Source/WTF/wtf/HashFunctions.h	2012-09-14 21:00:20 UTC (rev 128650)
@@ -86,6 +86,18 @@
         return static_cast<unsigned>(key);
     }
 
+    // Compound integer hash method: http://opendatastructures.org/versions/edition-0.1d/ods-java/node33.html#SECTION00832000000000000000
+    inline unsigned pairIntHash(unsigned key1, unsigned key2)
+    {
+        unsigned shortRandom1 = 277951225; // A random 32-bit value.
+        unsigned shortRandom2 = 95187966; // A random 32-bit value.
+        uint64_t longRandom = 19248658165952622LL; // A random 64-bit value.
+
+        uint64_t product = longRandom * (shortRandom1 * key1 + shortRandom2 * key2);
+        unsigned highBits = product >> (sizeof(uint64_t) - sizeof(unsigned));
+        return highBits;
+    }
+
     template<typename T> struct IntHash {
         static unsigned hash(T key) { return intHash(static_cast<typename IntTypes<sizeof(T)>::UnsignedType>(key)); }
         static bool equal(T a, T b) { return a == b; }
@@ -139,7 +151,7 @@
     template<typename T, typename U> struct PairHash {
         static unsigned hash(const std::pair<T, U>& p)
         {
-            return intHash((static_cast<uint64_t>(DefaultHash<T>::Hash::hash(p.first)) << 32 | DefaultHash<U>::Hash::hash(p.second)));
+            return pairIntHash(DefaultHash<T>::Hash::hash(p.first), DefaultHash<U>::Hash::hash(p.second));
         }
         static bool equal(const std::pair<T, U>& a, const std::pair<T, U>& b)
         {
@@ -149,6 +161,12 @@
                                                             && DefaultHash<U>::Hash::safeToCompareToEmptyOrDeleted;
     };
 
+    template<typename T, typename U> struct IntPairHash {
+        static unsigned hash(const std::pair<T, U>& p) { return pairIntHash(p.first, p.second); }
+        static bool equal(const std::pair<T, U>& a, const std::pair<T, U>& b) { return PairHash<T, T>::equal(a, b); }
+        static const bool safeToCompareToEmptyOrDeleted = PairHash<T, U>::safeToCompareToEmptyOrDeleted;
+    };
+
     // make IntHash the default hash function for many integer types
 
     template<> struct DefaultHash<short> { typedef IntHash<unsigned> Hash; };
@@ -172,6 +190,27 @@
     template<typename P> struct DefaultHash<P*> { typedef PtrHash<P*> Hash; };
     template<typename P> struct DefaultHash<RefPtr<P> > { typedef PtrHash<RefPtr<P> > Hash; };
 
+    // make IntPairHash the default hash function for pairs of (at most) 32-bit integers.
+
+    template<> struct DefaultHash<std::pair<short, short> > { typedef IntPairHash<short, short> Hash; };
+    template<> struct DefaultHash<std::pair<short, unsigned short> > { typedef IntPairHash<short, unsigned short> Hash; };
+    template<> struct DefaultHash<std::pair<short, int> > { typedef IntPairHash<short, int> Hash; };
+    template<> struct DefaultHash<std::pair<short, unsigned> > { typedef IntPairHash<short, unsigned> Hash; };
+    template<> struct DefaultHash<std::pair<unsigned short, short> > { typedef IntPairHash<unsigned short, short> Hash; };
+    template<> struct DefaultHash<std::pair<unsigned short, unsigned short> > { typedef IntPairHash<unsigned short, unsigned short> Hash; };
+    template<> struct DefaultHash<std::pair<unsigned short, int> > { typedef IntPairHash<unsigned short, int> Hash; };
+    template<> struct DefaultHash<std::pair<unsigned short, unsigned> > { typedef IntPairHash<unsigned short, unsigned> Hash; };
+    template<> struct DefaultHash<std::pair<int, short> > { typedef IntPairHash<int, short> Hash; };
+    template<> struct DefaultHash<std::pair<int, unsigned short> > { typedef IntPairHash<int, unsigned short> Hash; };
+    template<> struct DefaultHash<std::pair<int, int> > { typedef IntPairHash<int, int> Hash; };
+    template<> struct DefaultHash<std::pair<int, unsigned> > { typedef IntPairHash<unsigned, unsigned> Hash; };
+    template<> struct DefaultHash<std::pair<unsigned, short> > { typedef IntPairHash<unsigned, short> Hash; };
+    template<> struct DefaultHash<std::pair<unsigned, unsigned short> > { typedef IntPairHash<unsigned, unsigned short> Hash; };
+    template<> struct DefaultHash<std::pair<unsigned, int> > { typedef IntPairHash<unsigned, int> Hash; };
+    template<> struct DefaultHash<std::pair<unsigned, unsigned> > { typedef IntPairHash<unsigned, unsigned> Hash; };
+
+    // make PairHash the default hash function for pairs of arbitrary values.
+
     template<typename T, typename U> struct DefaultHash<std::pair<T, U> > { typedef PairHash<T, U> Hash; };
 
 } // namespace WTF

Modified: trunk/Source/WebCore/ChangeLog (128649 => 128650)


--- trunk/Source/WebCore/ChangeLog	2012-09-14 20:51:13 UTC (rev 128649)
+++ trunk/Source/WebCore/ChangeLog	2012-09-14 21:00:20 UTC (rev 128650)
@@ -1,3 +1,26 @@
+2012-09-14  Dana Jansens  <[email protected]>
+
+        Minimize collisions when hashing pairs
+        https://bugs.webkit.org/show_bug.cgi?id=96022
+
+        Reviewed by Adrienne Walker.
+
+        Use WTF::pairIntHash() to hash pairs of integers.
+
+        * dom/Document.cpp:
+        (WebCore::ImmutableAttributeDataCacheKey::hash):
+        * dom/StyledElement.cpp:
+        (WebCore::computePresentationAttributeCacheHash):
+        * platform/graphics/Gradient.cpp:
+        (WebCore::Gradient::hash):
+        * platform/graphics/IntPointHash.h:
+        (WTF::IntPointHash::hash):
+        * platform/graphics/IntRectHash.h:
+        * platform/graphics/IntSizeHash.h:
+        * platform/graphics/blackberry/LayerTileIndex.h:
+        * platform/graphics/cg/GraphicsContextCG.cpp:
+        (WebCore::SubimageCacheHash::hash):
+
 2012-09-14  Rob Buis  <[email protected]>
 
         [BlackBerry] Use StringBuilder more in BlackBerry RSS classes

Modified: trunk/Source/WebCore/dom/Document.cpp (128649 => 128650)


--- trunk/Source/WebCore/dom/Document.cpp	2012-09-14 20:51:13 UTC (rev 128649)
+++ trunk/Source/WebCore/dom/Document.cpp	2012-09-14 21:00:20 UTC (rev 128650)
@@ -6322,7 +6322,7 @@
     unsigned hash() const
     {
         unsigned attributeHash = StringHasher::hashMemory(m_attributes, m_attributeCount * sizeof(Attribute));
-        return WTF::intHash((static_cast<uint64_t>(m_localName->existingHash()) << 32 | attributeHash));
+        return WTF::pairIntHash(m_localName->existingHash(), attributeHash);
     }
 
 private:

Modified: trunk/Source/WebCore/dom/StyledElement.cpp (128649 => 128650)


--- trunk/Source/WebCore/dom/StyledElement.cpp	2012-09-14 20:51:13 UTC (rev 128649)
+++ trunk/Source/WebCore/dom/StyledElement.cpp	2012-09-14 21:00:20 UTC (rev 128650)
@@ -266,7 +266,7 @@
         return 0;
     ASSERT(key.attributesAndValues.size());
     unsigned attributeHash = StringHasher::hashMemory(key.attributesAndValues.data(), key.attributesAndValues.size() * sizeof(key.attributesAndValues[0]));
-    return WTF::intHash((static_cast<uint64_t>(key.tagName->existingHash()) << 32 | attributeHash));
+    return WTF::pairIntHash(key.tagName->existingHash(), attributeHash);
 }
 
 void StyledElement::updateAttributeStyle()

Modified: trunk/Source/WebCore/platform/graphics/Gradient.cpp (128649 => 128650)


--- trunk/Source/WebCore/platform/graphics/Gradient.cpp	2012-09-14 20:51:13 UTC (rev 128649)
+++ trunk/Source/WebCore/platform/graphics/Gradient.cpp	2012-09-14 21:00:20 UTC (rev 128650)
@@ -33,7 +33,7 @@
 #include <wtf/StringHasher.h>
 #include <wtf/UnusedParam.h>
 
-using WTF::intHash;
+using WTF::pairIntHash;
 
 namespace WebCore {
 
@@ -283,7 +283,7 @@
     unsigned parametersHash = StringHasher::hashMemory(&parameters, sizeof(parameters));
     unsigned stopHash = StringHasher::hashMemory(m_stops.data(), m_stops.size() * sizeof(ColorStop));
 
-    m_cachedHash = intHash((static_cast<uint64_t>(parametersHash) << 32) | stopHash);
+    m_cachedHash = pairIntHash(parametersHash, stopHash);
 
     return m_cachedHash;
 }

Modified: trunk/Source/WebCore/platform/graphics/IntPointHash.h (128649 => 128650)


--- trunk/Source/WebCore/platform/graphics/IntPointHash.h	2012-09-14 20:51:13 UTC (rev 128649)
+++ trunk/Source/WebCore/platform/graphics/IntPointHash.h	2012-09-14 21:00:20 UTC (rev 128650)
@@ -28,7 +28,7 @@
     
 // The empty value is (0, INT_MIN), the deleted value is (INT_MIN, 0)
 struct IntPointHash {
-    static unsigned hash(const WebCore::IntPoint& p) { return WTF::intHash(static_cast<uint64_t>(p.x()) << 32 | p.y()); }
+    static unsigned hash(const WebCore::IntPoint& p) { return pairIntHash(p.x(), p.y()); }
     static bool equal(const WebCore::IntPoint& a, const WebCore::IntPoint& b) { return a == b; }
     static const bool safeToCompareToEmptyOrDeleted = true;
 };

Modified: trunk/Source/WebCore/platform/graphics/IntRectHash.h (128649 => 128650)


--- trunk/Source/WebCore/platform/graphics/IntRectHash.h	2012-09-14 20:51:13 UTC (rev 128649)
+++ trunk/Source/WebCore/platform/graphics/IntRectHash.h	2012-09-14 21:00:20 UTC (rev 128650)
@@ -37,7 +37,7 @@
 template<> struct IntHash<WebCore::IntRect> {
     static unsigned hash(const WebCore::IntRect& key)
     {
-        return intHash(static_cast<uint64_t>(DefaultHash<WebCore::IntPoint>::Hash::hash(key.location())) << 32 | DefaultHash<WebCore::IntSize>::Hash::hash(key.size()));
+        return pairIntHash(DefaultHash<WebCore::IntPoint>::Hash::hash(key.location()), DefaultHash<WebCore::IntSize>::Hash::hash(key.size()));
     }
     static bool equal(const WebCore::IntRect& a, const WebCore::IntRect& b)
     {

Modified: trunk/Source/WebCore/platform/graphics/IntSizeHash.h (128649 => 128650)


--- trunk/Source/WebCore/platform/graphics/IntSizeHash.h	2012-09-14 20:51:13 UTC (rev 128649)
+++ trunk/Source/WebCore/platform/graphics/IntSizeHash.h	2012-09-14 21:00:20 UTC (rev 128650)
@@ -27,7 +27,7 @@
 namespace WTF {
 
     template<> struct IntHash<WebCore::IntSize> {
-        static unsigned hash(const WebCore::IntSize& key) { return intHash((static_cast<uint64_t>(key.width()) << 32 | key.height())); }
+        static unsigned hash(const WebCore::IntSize& key) { return pairIntHash(key.width(), key.height()); }
         static bool equal(const WebCore::IntSize& a, const WebCore::IntSize& b) { return a == b; }
         static const bool safeToCompareToEmptyOrDeleted = true;
     };

Modified: trunk/Source/WebCore/platform/graphics/blackberry/LayerTileIndex.h (128649 => 128650)


--- trunk/Source/WebCore/platform/graphics/blackberry/LayerTileIndex.h	2012-09-14 20:51:13 UTC (rev 128649)
+++ trunk/Source/WebCore/platform/graphics/blackberry/LayerTileIndex.h	2012-09-14 21:00:20 UTC (rev 128650)
@@ -66,7 +66,7 @@
 namespace WTF {
 
 template<> struct IntHash<WebCore::TileIndex> {
-    static unsigned hash(const WebCore::TileIndex& key) { return intHash((static_cast<uint64_t>(key.i()) << 32 | key.j())); }
+    static unsigned hash(const WebCore::TileIndex& key) { return pairIntHash(key.i(), key.j()); }
     static bool equal(const WebCore::TileIndex& a, const WebCore::TileIndex& b) { return a == b; }
     static const bool safeToCompareToEmptyOrDeleted = true;
 };

Modified: trunk/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp (128649 => 128650)


--- trunk/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp	2012-09-14 20:51:13 UTC (rev 128649)
+++ trunk/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp	2012-09-14 21:00:20 UTC (rev 128650)
@@ -74,7 +74,7 @@
 using namespace std;
 
 // FIXME: The following using declaration should be in <wtf/HashFunctions.h>.
-using WTF::intHash;
+using WTF::pairIntHash;
 
 // FIXME: The following using declaration should be in <wtf/HashTraits.h>.
 using WTF::GenericHashTraits;
@@ -116,8 +116,8 @@
 struct SubimageCacheHash {
     static unsigned hash(CGImageRef image, const FloatRect& rect)
     {
-        return intHash((static_cast<uint64_t>(PtrHash<CGImageRef>::hash(image)) << 32)
-            | (static_cast<unsigned>(rect.x()) << 16) | static_cast<unsigned>(rect.y()));
+        return pairIntHash(PtrHash<CGImageRef>::hash(image),
+            (static_cast<unsigned>(rect.x()) << 16) | static_cast<unsigned>(rect.y()));
     }
     static unsigned hash(const SubimageCacheEntry& key)
     {

Modified: trunk/Source/WebKit/blackberry/ChangeLog (128649 => 128650)


--- trunk/Source/WebKit/blackberry/ChangeLog	2012-09-14 20:51:13 UTC (rev 128649)
+++ trunk/Source/WebKit/blackberry/ChangeLog	2012-09-14 21:00:20 UTC (rev 128650)
@@ -1,3 +1,14 @@
+2012-09-14  Dana Jansens  <[email protected]>
+
+        Minimize collisions when hashing pairs
+        https://bugs.webkit.org/show_bug.cgi?id=96022
+
+        Reviewed by Adrienne Walker.
+
+        Use WTF::pairIntHash() to hash a pair of integers.
+
+        * WebKitSupport/TileIndexHash.h:
+
 2012-09-14  Genevieve Mak  <[email protected]>
 
         Always send mouse events on pages that don't scroll even if there

Modified: trunk/Source/WebKit/blackberry/WebKitSupport/TileIndexHash.h (128649 => 128650)


--- trunk/Source/WebKit/blackberry/WebKitSupport/TileIndexHash.h	2012-09-14 20:51:13 UTC (rev 128649)
+++ trunk/Source/WebKit/blackberry/WebKitSupport/TileIndexHash.h	2012-09-14 21:00:20 UTC (rev 128650)
@@ -28,7 +28,7 @@
 namespace WTF {
 
 template<> struct IntHash<TileIndex> {
-    static unsigned hash(const TileIndex& key) { return intHash((static_cast<uint64_t>(key.i()) << 32 | key.j())); }
+    static unsigned hash(const TileIndex& key) { return pairIntHash(key.i(), key.j()); }
     static bool equal(const TileIndex& a, const TileIndex& b) { return a == b; }
     static const bool safeToCompareToEmptyOrDeleted = true;
 };
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to