Changeset 1910 for trunk/src/kmk


Ignore:
Timestamp:
Oct 22, 2008, 9:50:39 PM (17 years ago)
Author:
bird
Message:

strcache2: switch to Paul Hsieh's superfash hash function (finally found one which is both faster and better). Implemented rehashing of chained hashing.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/kmk/strcache2.c

    r1909 r1910  
    3636#include "debug.h"
    3737
     38#ifdef _MSC_VER
     39typedef unsigned char  uint8_t;
     40typedef unsigned short uint16_t;
     41typedef unsigned int   uint32_t;
     42#else
     43# include <stdint.h>
     44#endif
     45
    3846#ifdef WINDOWS32
    3947# include <io.h>
     
    7280/* List of initialized string caches. */
    7381static struct strcache2 *strcache_head;
    74 
    7582
    7683
     
    107114}
    108115
    109 static struct strcache2_seg *
    110 strcache2_new_seg (struct strcache2 *cache, unsigned int minlen)
    111 {
    112   struct strcache2_seg *seg;
    113   size_t size;
    114   size_t off;
    115 
    116   size = cache->def_seg_size;
    117   if (size < (size_t)minlen + sizeof (struct strcache2_seg) + STRCACHE2_ENTRY_ALIGNMENT)
    118     {
    119       size = (size_t)minlen * 2;
    120       size = (size + 0xfff) & ~(size_t)0xfff;
    121     }
    122 
    123   seg = xmalloc (size);
    124   seg->start = (char *)(seg + 1);
    125   seg->size  = size - sizeof (struct strcache2_seg);
    126   off = (size_t)seg->start & (STRCACHE2_ENTRY_ALIGNMENT - 1);
    127   if (off)
    128     {
    129       seg->start += off;
    130       seg->size  -= off;
    131     }
    132   assert (seg->size > minlen);
    133   seg->cursor = seg->start;
    134   seg->avail  = seg->size;
    135 
    136   seg->next = cache->seg_head;
    137   cache->seg_head = seg;
    138 
    139   return seg;
    140 }
    141 
    142116MY_INLINE unsigned int
    143117strcache2_case_sensitive_hash_1 (const char *str, unsigned int len)
    144118{
    145119#if 1
     120  /* Paul Hsieh hash SuperFast function:
     121     http://www.azillionmonkeys.com/qed/hash.html
     122
     123     This performs very good and as a sligtly better distribution than
     124     STRING_N_HASH_1 on a typical kBuild run.
     125
     126     It is also 37% faster than return_STRING_N_HASH_1 when running the
     127     two 100 times over typical kBuild strings that end up here (did a
     128     fprintf here and built kBuild). Compiler was 32-bit gcc 4.0.1, darwin,
     129     with -O2.
     130
     131     FIXME: A path for well aligned data should be added to speed up
     132            execution on alignment sensitive systems.  */
     133
     134# if defined(__amd64__) || defined(__x86_64__) || defined(__AMD64__) || defined(_M_X64) || defined(__amd64) \
     135 || defined(__i386__) || defined(__x86__) || defined(__X86__) || defined(_M_IX86) || defined(__i386)
     136#  define strcache2_get_unaligned_16bits(ptr)   ( *((const uint16_t *)(ptr)))
     137# else
     138   /* (endian doesn't matter) */
     139#  define strcache2_get_unaligned_16bits(ptr)   (   (((const uint8_t *)(ptr))[0] << 8) \
     140                                                  | (((const uint8_t *)(ptr))[1]) )
     141# endif
     142  uint32_t hash = len;
     143  uint32_t tmp;
     144  int rem;
     145
     146  assert (sizeof (uint8_t) == sizeof (char));
     147  if (len == 0)
     148    return 0;
     149
     150  /* main loop, walking on 2 x uint16_t */
     151  rem = len & 3;
     152  len >>= 2;
     153  while (len > 0)
     154    {
     155      hash += strcache2_get_unaligned_16bits (str);
     156      tmp   = (strcache2_get_unaligned_16bits (str + 2) << 11) ^ hash;
     157      hash  = (hash << 16) ^ tmp;
     158      str  += 2 * sizeof (uint16_t);
     159      hash += hash >> 11;
     160      len--;
     161    }
     162
     163  /* the remainer */
     164  switch (rem)
     165    {
     166      case 3:
     167        hash += strcache2_get_unaligned_16bits (str);
     168        hash ^= hash << 16;
     169        hash ^= str[sizeof (uint16_t)] << 18;
     170        hash += hash >> 11;
     171        break;
     172      case 2:
     173        hash += strcache2_get_unaligned_16bits (str);
     174        hash ^= hash << 11;
     175        hash += hash >> 17;
     176        break;
     177      case 1:
     178        hash += *str;
     179        hash ^= hash << 10;
     180        hash += hash >> 1;
     181        break;
     182    }
     183
     184  /* force "avalanching" of final 127 bits. */
     185  hash ^= hash << 3;
     186  hash += hash >> 5;
     187  hash ^= hash << 4;
     188  hash += hash >> 17;
     189  hash ^= hash << 25;
     190  hash += hash >> 6;
     191
     192  return hash;
     193
     194#elif 1
    146195  /* Note! This implementation is 18% faster than return_STRING_N_HASH_1
    147196           when running the two 100 times over typical kBuild strings that
     
    183232    hash = 0;
    184233  return hash;
    185 #else
    186 # if 1
    187   /* This is SDBM.  This specific form and loop unroll was benchmarked to
    188      be 28% faster than return_STRING_N_HASH_1.  (Now the weird thing is
    189      that putting the (ch) first in the assignment made it noticably slower.)
     234
     235#elif 1
     236# if 0
     237  /* This is SDBM.  This specific form/unroll was benchmarked to be 28% faster
     238     than return_STRING_N_HASH_1.  (Now the weird thing is that putting the (ch)
     239     first in the assignment made it noticably slower.)
    190240
    191241     However, it is noticably slower in practice, most likely because of more
    192      collisions. Hrmpf.
    193      */
     242     collisions.  Hrmpf.  */
     243
    194244#  define UPDATE_HASH(ch) hash = (hash << 6) + (hash << 16) - hash + (ch)
    195245  unsigned int hash = 0;
     246
    196247# else
    197248 /* This is DJB2.  This specific form/unroll was benchmarked to be 27%
    198249    fast than return_STRING_N_HASH_1.
    199250
    200     Ditto. 2x Hrmpf */
     251    Ditto.  */
     252
    201253#  define UPDATE_HASH(ch) hash = (hash << 5) + hash + (ch)
    202254  unsigned int hash = 5381;
    203255# endif
     256
     257
    204258  while (len >= 4)
    205259    {
     
    366420#endif /* STRCACHE2_USE_CHAINING */
    367421}
    368 
    369 #ifdef _MSC_VER
    370   typedef unsigned int int32_t;
    371 #else
    372 # include <stdint.h>
    373 #endif
    374422
    375423MY_INLINE int
     
    561609
    562610  /* the simple stuff first. */
    563   if (   entry == NULL
    564       || entry->hash1 != hash1
     611  if (   entry->hash1 != hash1
    565612      || entry->length != length)
    566613      return 0;
     
    582629
    583630  /* the simple stuff first. */
    584   if (   entry == NULL
    585       || entry->hash1 != hash1
     631  if (   entry->hash1 != hash1
    586632      || entry->length != length)
    587633      return 0;
     
    620666
    621667  /* Copy the entries from the old to the new hash table. */
     668#ifdef STRCACHE2_USE_CHAINING
     669  cache->collision_count = 0;
     670  while (src-- > 0)
     671    {
     672      struct strcache2_entry *entry = src_tab[src];
     673      while (entry)
     674        {
     675          struct strcache2_entry *next = entry->next;
     676          unsigned int dst = STRCACHE2_MOD_IT (cache, entry->hash1);
     677          if ((entry->next = dst_tab[dst]) != 0)
     678            cache->collision_count++;
     679          dst_tab[dst] = entry;
     680
     681          entry = next;
     682        }
     683    }
     684#else  /* !STRCACHE2_USE_CHAINING */
    622685  while (src-- > 0)
    623686    {
     
    625688      if (entry)
    626689        {
    627 #ifdef STRCACHE2_USE_CHAINING
    628 assert(!"todo");
    629 #else
    630690          unsigned int dst = STRCACHE2_MOD_IT (cache, entry->hash1);
    631691          if (dst_tab[dst])
     
    644704                }
    645705            }
    646 
    647706          dst_tab[dst] = entry;
    648 #endif
    649         }
    650     }
     707        }
     708    }
     709#endif /* !STRCACHE2_USE_CHAINING */
    651710
    652711  /* That's it, just free the old table and we're done. */
    653712  free (src_tab);
     713}
     714
     715static struct strcache2_seg *
     716strcache2_new_seg (struct strcache2 *cache, unsigned int minlen)
     717{
     718  struct strcache2_seg *seg;
     719  size_t size;
     720  size_t off;
     721
     722  size = cache->def_seg_size;
     723  if (size < (size_t)minlen + sizeof (struct strcache2_seg) + STRCACHE2_ENTRY_ALIGNMENT)
     724    {
     725      size = (size_t)minlen * 2;
     726      size = (size + 0xfff) & ~(size_t)0xfff;
     727    }
     728
     729  seg = xmalloc (size);
     730  seg->start = (char *)(seg + 1);
     731  seg->size  = size - sizeof (struct strcache2_seg);
     732  off = (size_t)seg->start & (STRCACHE2_ENTRY_ALIGNMENT - 1);
     733  if (off)
     734    {
     735      seg->start += off;
     736      seg->size  -= off;
     737    }
     738  assert (seg->size > minlen);
     739  seg->cursor = seg->start;
     740  seg->avail  = seg->size;
     741
     742  seg->next = cache->seg_head;
     743  cache->seg_head = seg;
     744
     745  return seg;
    654746}
    655747
     
    696788  str_copy[length] = '\0';
    697789
    698 #ifndef STRCACHE2_USE_CHAINING
     790#ifdef STRCACHE2_USE_CHAINING
     791  if ((entry->next = cache->hash_tab[idx]) != 0)
     792    cache->collision_count++;
     793#endif /* STRCACHE2_USE_CHAINING */
    699794  cache->hash_tab[idx] = entry;
    700 #else  /* STRCACHE2_USE_CHAINING */
    701   if ((entry->next = cache->hash_tab[idx]) == 0)
    702     cache->hash_tab[idx] = entry;
    703   else
    704     {
    705       cache->hash_tab[idx] = entry;
    706       cache->collision_count++;
    707     }
    708 #endif /* STRCACHE2_USE_CHAINING */
    709795  cache->count++;
    710796  if (cache->count >= cache->rehash_count)
     
    13841470  printf (_("%s  %5u (%u%%) empty hash table slots\n"),
    13851471          prefix, chain_depths[0],       (unsigned int)((100.0 * chain_depths[0])  / cache->hash_size));
    1386   printf (_("%s  %5u (%u%%) in used hash table slots\n"),
     1472  printf (_("%s  %5u (%u%%) occupied hash table slots\n"),
    13871473          prefix, chain_depths[1],       (unsigned int)((100.0 * chain_depths[1])  / cache->hash_size));
    13881474  for (idx = 2; idx < 32; idx++)
Note: See TracChangeset for help on using the changeset viewer.