Ignore:
Timestamp:
Oct 13, 2008, 5:58:07 AM (17 years ago)
Author:
bird
Message:

kmk: improved the hashing of file table entries by making the strcache cache their hash values along with the string length.

File:
1 edited

Legend:

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

    r1854 r1857  
    6161}
    6262
     63#ifndef CONFIG_WITH_VALUE_LENGTH
    6364static const char *
    6465add_string(const char *str, int len)
     
    6768  struct strcache *sp;
    6869  const char *res;
    69 #ifdef CONFIG_WITH_VALUE_LENGTH
    70   int str_len = len;
    71   char *tmp;
    72 
    73   /* Add space a length prefix and the terminator and assure
    74      (somewhat) natural alignment. */
    75   len += sizeof(unsigned int) + 1;
    76   len = (len + sizeof(void *) - 1) & ~(sizeof(void *) - 1);
    77   --len;
    78 #endif
    7970
    8071  /* If the string we want is too large to fit into a single buffer, then
     
    9889
    9990  /* Add the string to the best cache.  */
    100 #ifndef CONFIG_WITH_VALUE_LENGTH
    10191  res = best->end;
    10292  memcpy (best->end, str, len);
     
    10595  best->bytesfree -= len + 1;
    10696  ++best->count;
     97  return res;
     98}
     99
    107100#else  /* CONFIG_WITH_VALUE_LENGTH */
    108   tmp = best->end;
    109   best->end += len + 1;
    110   assert(!((size_t)tmp & (sizeof(void *) - 1)));
    111 
    112   *(unsigned int *)tmp = str_len; /* length prefix */
    113   tmp += sizeof(unsigned int);
    114 
    115   res = tmp;
    116   memcpy (tmp, str, str_len);
    117   tmp += str_len;
    118   *(tmp++) = '\0';
    119 
    120   best->bytesfree -= len + 1;
     101
     102static const char *
     103add_string(const char *str, struct strcache_pref *prefix)
     104{
     105  struct strcache *best = NULL;
     106  struct strcache *sp;
     107  struct strcache_pref *real_prefix;
     108  int len;
     109  const char *res;
     110  char *dst;
     111
     112  /* Calc the entry length; the prefix data + the string + alignment. */
     113  len = sizeof(struct strcache_pref) + prefix->len + 1;
     114  len = (len + sizeof(void *) - 1) & ~(sizeof(void *) - 1);
     115
     116  /* If the string we want is too large to fit into a single buffer, then
     117     we're screwed; nothing will ever fit!  Change the maximum size of the
     118     cache to be big enough.  */
     119  if (len > bufsize)
     120    bufsize = len * 2;
     121
     122  /* First, find a cache with enough free space.  We always look through all
     123     the blocks and choose the one with the best fit (the one that leaves the
     124     least amount of space free).  */
     125  for (sp = strcache; sp != NULL; sp = sp->next)
     126    if (sp->bytesfree >= len && (!best || best->bytesfree > sp->bytesfree))
     127      best = sp;
     128
     129  /* If nothing is big enough, make a new cache.  */
     130  if (!best)
     131    best = new_cache();
     132
     133  assert (best->bytesfree >= len);
     134
     135  /* Add the string to the best cache.  */
     136  real_prefix = (struct strcache_pref *)best->end;
     137  *real_prefix = *prefix;
     138
     139  res = dst = (char *)(real_prefix + 1);
     140  assert(!((size_t)res & (sizeof(void *) - 1)));
     141  memcpy (dst, str, prefix->len);
     142  dst += prefix->len;
     143  *(dst++) = '\0';
     144
     145  best->end += len;
     146  best->bytesfree -= len;
    121147  ++best->count;
    122148
    123   assert (tmp <= best->end);
    124   assert (!((size_t)res & (sizeof(void *) - 1)));
    125 #endif /* CONFIG_WITH_VALUE_LENGTH */
    126149  return res;
    127150}
    128151
    129 
    130 /* Hash table of strings in the cache.  */
    131 
    132 #ifdef CONFIG_WITH_VALUE_LENGTH
    133152/* Hackish globals for passing data to the hash functions.
    134153   There isn't really any other way without running the
    135154   risk of breaking rehashing. */
    136155static const char *lookup_string;
    137 static unsigned int lookup_string_len;
    138 # ifdef CONFIG_WITH_INCLUDEDEP
    139 static unsigned long lookup_string_hash1;
    140 static unsigned long lookup_string_hash2;
    141 # endif /* CONFIG_WITH_INCLUDEDEP */
     156static struct strcache_pref *lookup_prefix;
     157
    142158#endif /* CONFIG_WITH_VALUE_LENGTH */
     159
     160
     161/* Hash table of strings in the cache.  */
    143162
    144163static unsigned long
    145164str_hash_1 (const void *key)
    146165{
    147 #ifdef CONFIG_WITH_INCLUDEDEP
    148   if ((const char *) key == lookup_string && lookup_string_hash1)
    149     return lookup_string_hash1;
     166#ifdef CONFIG_WITH_VALUE_LENGTH
     167  if (MY_PREDICT_TRUE ((const char *) key == lookup_string))
     168    return lookup_prefix->hash1;
    150169#endif
    151170  return_ISTRING_HASH_1 ((const char *) key);
     
    155174str_hash_2 (const void *key)
    156175{
    157 #ifdef CONFIG_WITH_INCLUDEDEP
    158   if ((const char *) key == lookup_string && lookup_string_hash2)
    159     return lookup_string_hash2;
     176#ifdef CONFIG_WITH_VALUE_LENGTH
     177  if (MY_PREDICT_TRUE ((const char *) key == lookup_string))
     178    {
     179      if (lookup_prefix->hash2)
     180        {
     181          unsigned long hash2 = 0;
     182          ISTRING_HASH_2 ((const char *)key, hash2);
     183          lookup_prefix->hash2 = hash2;
     184        }
     185      return lookup_prefix->hash2;
     186    }
    160187#endif
    161188  return_ISTRING_HASH_2 ((const char *) key);
     
    172199     kBuild scenario.  */
    173200
    174   if ((const char *) x == lookup_string)
    175     {
    176       assert (lookup_string_len == strlen ((const char *)x));
    177       if (strcache_get_len ((const char *)y) != lookup_string_len)
     201  if (MY_PREDICT_TRUE ((const char *) x == lookup_string))
     202    {
     203      assert (lookup_prefix->len == strlen ((const char *)x));
     204      if (strcache_get_len ((const char *)y) != lookup_prefix->len)
    178205        return -1;
    179206    }
     
    185212static unsigned long total_adds = 0;
    186213
     214#ifndef CONFIG_WITH_VALUE_LENGTH
    187215static const char *
    188216add_hash (const char *str, int len)
    189217{
    190218  /* Look up the string in the hash.  If it's there, return it.  */
    191 #ifndef CONFIG_WITH_VALUE_LENGTH
    192219  char *const *slot = (char *const *) hash_find_slot (&strings, str);
    193220  const char *key = *slot;
    194 #else  /* CONFIG_WITH_VALUE_LENGTH */
    195   char *const *slot;
    196   const char *key;
    197 
    198   lookup_string = str;
    199   lookup_string_len = len;
    200   slot = (char *const *) hash_find_slot (&strings, str);
    201   key = *slot;
    202 #endif /* CONFIG_WITH_VALUE_LENGTH */
    203221
    204222  /* Count the total number of adds we performed.  */
     
    213231  return key;
    214232}
     233
     234#else  /* CONFIG_WITH_VALUE_LENGTH */
     235
     236static const char *
     237add_hash (const char *str, int len, unsigned long hash1, unsigned long hash2)
     238{
     239  char *const *slot;
     240  const char *key;
     241  struct strcache_pref prefix;
     242
     243  /* Look up the string in the hash.  If it's there, return it.  */
     244  prefix.len = len;
     245  prefix.hash2 = hash2;
     246  if (!hash1 && !hash2)
     247    ISTRING_HASH_1 (str, hash1);
     248  prefix.hash1 = hash1;
     249
     250  lookup_string = str;
     251  lookup_prefix = &prefix;
     252
     253  slot = (char *const *) hash_find_slot (&strings, str);
     254  key = *slot;
     255
     256  /* Count the total number of adds we performed.  */
     257  ++total_adds;
     258
     259  if (!HASH_VACANT (key))
     260    return key;
     261
     262  /* Not there yet so add it to a buffer, then into the hash table.  */
     263  key = add_string (str,  &prefix);
     264  hash_insert_at (&strings, key, slot);
     265  return key;
     266}
     267
     268/* Verifies that a string cache entry didn't change and that the
     269   prefix is still valid. */
     270int
     271strcache_check_sanity (const char *str)
     272{
     273  struct strcache_pref const *prefix = (struct strcache_pref const *)str - 1;
     274  unsigned long hash;
     275
     276  if (strlen (str) != prefix->len)
     277    {
     278      MY_ASSERT_MSG (0, ("len: %u != %u - '%s'\n", (unsigned int)strlen (str),
     279                         prefix->len, str));
     280      return -1;
     281    }
     282
     283  hash = 0;
     284  ISTRING_HASH_1 (str, hash);
     285  if (hash != prefix->hash1)
     286    {
     287      MY_ASSERT_MSG (0, ("hash1: %lx != %lx - '%s'\n", hash, prefix->hash1, str));
     288      return -1;
     289    }
     290
     291  if (prefix->hash2)
     292    {
     293      hash = 0;
     294      ISTRING_HASH_2 (str, hash);
     295      if (hash != prefix->hash2)
     296        {
     297          MY_ASSERT_MSG (0, ("hash2: %lx != %lx - '%s'\n", hash, prefix->hash2, str));
     298          return -1;
     299        }
     300    }
     301
     302  return 0;
     303}
     304
     305/* Fallback for when the hash2 value isn't present. */
     306unsigned long
     307strcache_get_hash2_fallback (const char *str)
     308{
     309  struct strcache_pref *prefix = (struct strcache_pref *)str - 1;
     310  unsigned long hash2 = 0;
     311
     312  ISTRING_HASH_2 (str, hash2);
     313  prefix->hash2 = hash2;
     314
     315  return hash2;
     316}
     317
     318#endif /* CONFIG_WITH_VALUE_LENGTH */
    215319
    216320/* Returns true if the string is in the cache; false if not.  */
     
    233337strcache_add (const char *str)
    234338{
     339#ifndef CONFIG_WITH_VALUE_LENGTH
    235340  return add_hash (str, strlen (str));
     341#else
     342  /* XXX: calc the hash1 while determining the string length. */
     343  return add_hash (str, strlen (str), 0, 0);
     344#endif
    236345}
    237346
     
    249358    }
    250359
     360#ifndef CONFIG_WITH_VALUE_LENGTH
    251361  return add_hash (str, len);
     362#else
     363  /* XXX: eliminate the alloca mess using the prefixing? */
     364  return add_hash (str, len, 0, 0);
     365#endif
    252366}
    253367
     
    260374                        unsigned long hash2)
    261375{
    262   const char *retstr;
    263 
    264   assert (hash1 == str_hash_1 (str));
    265   assert (hash2 == str_hash_2 (str));
    266 
    267   lookup_string_hash1 = hash1;
    268   lookup_string_hash2 = hash2;
    269 
    270   retstr = add_hash (str, len);
    271 
    272   lookup_string_hash1 = 0;
    273   lookup_string_hash2 = 0;
    274 
    275   return retstr;
     376  return add_hash (str, len, hash1, hash2);
    276377}
    277378
Note: See TracChangeset for help on using the changeset viewer.