Webkit内核源代码中包含一套全新实现的基础模板库 ---- WTF。 WTF提供了基本的容器类 如:Vector, Deque, HaspMap, AVLTree 等,还提供了如智能指针,定时器,线程,消息队列,内存池等实现。这些基础代码使WebKit可以不依赖任何第三方C++类库如 STL, Boost 等,从而提供最大限度的可移植性。 WTF中的HashMap是WebKit中使用最多也是操作最为频繁的容器,它的性能直接影响WebKit的整体性能,所以hash函数的实现显得尤为重要。
WTF中的Hash函数主要是两类,一类是整数Hash算法,包括 8bit,16bit,32bit,64bit。指针类型按位数转换成相应的整数进行运算,浮点类型也按所占字节数数转换成相应的整数进行Hash运算,如32位系统中 float 类型按 32bit整数运算, double类型按64bit整数计算Hash值。另一类就是使用最多的字符串Hash算法,包括8bit (char) 和16bit(unicode)两种。
整数的Hash算法使用的是Thomas Wang's 32 Bit / 64 Bit Mix Function ,这是一种基于位移运算的散列方法。基于移位的散列是使用Key值进行移位操作。通常是结合左移和右移。每个移位过程的结果进行累加,最后移位的结果作为最终结果。这种方法的好处是避免了乘法运算,从而提高Hash函数本身的性能。下面来看看 32bit整数的Hash函数实现:
- unsigned intHash(uint32_t key)
- {
- key += ~(key << 15);
- key ^= (key >> 10);
- key += (key << 3);
- key ^= (key >> 6);
- key += ~(key << 11);
- key ^= (key >> 16);
- return key;
- }
64bit 整数的版本同32bit类似,只是计算位数更多:
- unsigned intHash(uint64_t key)
- {
- key += ~(key << 32);
- key ^= (key >> 22);
- key += ~(key << 13);
- key ^= (key >> 8);
- key += (key << 3);
- key ^= (key >> 15);
- key += ~(key << 27);
- key ^= (key >> 31);
- return static_cast<unsigned>(key);
- }
字符串的Hash算法是WebKit中最重要的算法,它来自于Paul Hsieh's SuperFastHash算法。http://www.azillionmonkeys.com/qed/hash.html
Hash函数的设计原则是使用最小的代价迅速达到雪崩效应(如:输入中1bit的变化 影响 输出中1/4 到 1/2的bits变化)。来看看 Pual Hsieh的实现:
- #include "pstdint.h" /* Replace with <stdint.h> if appropriate */
- #undef get16bits
- #if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
- || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
- #define get16bits(d) (*((const uint16_t *) (d)))
- #endif
- #if !defined (get16bits)
- #define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\
- +(uint32_t)(((const uint8_t *)(d))[0]) )
- #endif
- uint32_t SuperFastHash (const char * data, int len) {
- uint32_t hash = len, tmp;
- int rem;
- if (len <= 0 || data == NULL) return 0;
- rem = len & 3;
- len >>= 2;
- /* Main loop */
- for (;len > 0; len--) {
- hash += get16bits (data);
- tmp = (get16bits (data+2) << 11) ^ hash;
- hash = (hash << 16) ^ tmp;
- data += 2*sizeof (uint16_t);
- hash += hash >> 11;
- }
- /* Handle end cases */
- switch (rem) {
- case 3: hash += get16bits (data);
- hash ^= hash << 16;
- hash ^= ((signed char)data[sizeof (uint16_t)]) << 18;
- hash += hash >> 11;
- break;
- case 2: hash += get16bits (data);
- hash ^= hash << 11;
- hash += hash >> 17;
- break;
- case 1: hash += (signed char)*data;
- hash ^= hash << 10;
- hash += hash >> 1;
- }
- /* Force "avalanching" of final 127 bits */
- hash ^= hash << 3;
- hash += hash >> 5;
- hash ^= hash << 4;
- hash += hash >> 17;
- hash ^= hash << 25;
- hash += hash >> 6;
- return hash;
- }
经过Benckmark的测试, 这种实现方法在主流平台比现有的其它Hash函数都要快很多。
|
|
III 1.2Ghz | ||||
Intel C/C++ /O2 /G6 /Qaxi /Qxi /Qip | MSVC /O2 /Ot /Og /G6 | WATCOM C/C++ /otexan /6r | GCC -O3 -march=athlon-xp | GCC -O3 -mpowerpc64 | CC 32bit -O | |
CRC32 | 6.42 | 5.66 | 5.66 | 5.67 | 14.06 | 8.75 |
One at a Time | 5.76 | 5.66 | 5.66 | 5.69 | 12.79 | 5.57 |
Alpha Numeric | 3.29 | 4.06 | 4.06 | 5.67 | 10.26 | 5.52 |
FNV Hash | 4.88 | 4.84 | 4.83 | 4.87 | 8.92 | 11.98 |
Bob Jenkins | 2.08 | 2.36 | 2.03 | 2.07 | 6.16 | 3.08 |
SuperFastHash | 1.54 | 1.92 | 1.59 | 1.34 | 3.71 | 2.15 |
Data is time in seconds taken to hash a random buffer of 256 bytes 5 million times.Download test here
结束语,WebKit性能很高来源于很多设计的非常优秀的算法和开源软件实现,Hash函数只是其中的一个方面。但正是由于字符串Hash函数性能很高,基于它实现的String类和AtomicString类等基础代码才能获得极高的性能。