Ignore:
Timestamp:
Mar 14, 2018, 10:28:10 PM (7 years ago)
Author:
bird
Message:

kmk: Merged in changes from GNU make 4.2.1 (2e55f5e4abdc0e38c1d64be703b446695e70b3b6 / https://git.savannah.gnu.org/git/make.git).

Location:
trunk/src/kmk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/kmk

  • trunk/src/kmk/strcache.c

    r3090 r3140  
    11/* Constant string caching for GNU Make.
    2 Copyright (C) 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
     2Copyright (C) 2006-2016 Free Software Foundation, Inc.
    33This file is part of GNU Make.
    44
     
    1515this program.  If not, see <http://www.gnu.org/licenses/>.  */
    1616
    17 #include "make.h"
     17#include "makeint.h"
    1818#ifndef CONFIG_WITH_STRCACHE2
    1919
     20#include <stddef.h>
    2021#include <assert.h>
    2122
    2223#include "hash.h"
    23 
    24 /* The size (in bytes) of each cache buffer.
    25    Try to pick something that will map well into the heap.  */
    26 #define CACHE_BUFFER_SIZE   (8192 - 16)
    27 
    2824
    2925/* A string cached here will never be freed, so we don't need to worry about
     
    3127   hash so it can be looked up again. */
    3228
     29typedef unsigned short int sc_buflen_t;
     30
    3331struct strcache {
    34   struct strcache *next;    /* The next block of strings.  */
    35   char *end;                /* Pointer to the beginning of the free space.  */
    36   int count;                /* # of strings in this buffer (for stats).  */
    37   int bytesfree;            /* The amount of the buffer that is free.  */
     32  struct strcache *next;    /* The next block of strings.  Must be first!  */
     33  sc_buflen_t end;          /* Offset to the beginning of free space.  */
     34  sc_buflen_t bytesfree;    /* Free space left in this buffer.  */
     35  sc_buflen_t count;        /* # of strings in this buffer (for stats).  */
    3836  char buffer[1];           /* The buffer comes after this.  */
    3937};
    4038
    41 static int bufsize = CACHE_BUFFER_SIZE;
     39/* The size (in bytes) of each cache buffer.
     40   Try to pick something that will map well into the heap.
     41   This must be able to be represented by a short int (<=65535).  */
     42#define CACHE_BUFFER_BASE       (8192)
     43#define CACHE_BUFFER_ALLOC(_s)  ((_s) - (2 * sizeof (size_t)))
     44#define CACHE_BUFFER_OFFSET     (offsetof (struct strcache, buffer))
     45#define CACHE_BUFFER_SIZE(_s)   (CACHE_BUFFER_ALLOC(_s) - CACHE_BUFFER_OFFSET)
     46#define BUFSIZE                 CACHE_BUFFER_SIZE (CACHE_BUFFER_BASE)
     47
    4248static struct strcache *strcache = NULL;
     49static struct strcache *fullcache = NULL;
     50
     51static unsigned long total_buffers = 0;
     52static unsigned long total_strings = 0;
     53static unsigned long total_size = 0;
    4354
    4455/* Add a new buffer to the cache.  Add it at the front to reduce search time.
     
    4859 */
    4960static struct strcache *
    50 new_cache()
    51 {
    52   struct strcache *new;
    53   new = xmalloc (sizeof (*new) + bufsize);
    54   new->end = new->buffer;
     61new_cache (struct strcache **head, sc_buflen_t buflen)
     62{
     63  struct strcache *new = xmalloc (buflen + CACHE_BUFFER_OFFSET);
     64  new->end = 0;
    5565  new->count = 0;
    56   new->bytesfree = bufsize;
    57 
    58   new->next = strcache;
    59   strcache = new;
    60 
     66  new->bytesfree = buflen;
     67
     68  new->next = *head;
     69  *head = new;
     70
     71  ++total_buffers;
    6172  return new;
    6273}
    6374
    6475static const char *
    65 add_string(const char *str, int len)
    66 {
    67   struct strcache *best = NULL;
     76copy_string (struct strcache *sp, const char *str, unsigned int len)
     77{
     78  /* Add the string to this cache.  */
     79  char *res = &sp->buffer[sp->end];
     80
     81  memmove (res, str, len);
     82  res[len++] = '\0';
     83  sp->end += len;
     84  sp->bytesfree -= len;
     85  ++sp->count;
     86
     87  return res;
     88}
     89
     90static const char *
     91add_string (const char *str, unsigned int len)
     92{
     93  const char *res;
    6894  struct strcache *sp;
    69   const char *res;
     95  struct strcache **spp = &strcache;
     96  /* We need space for the nul char.  */
     97  unsigned int sz = len + 1;
     98
     99  ++total_strings;
     100  total_size += sz;
    70101
    71102  /* If the string we want is too large to fit into a single buffer, then
    72      we're screwed; nothing will ever fit!  Change the maximum size of the
    73      cache to be big enough.  */
    74   if (len > bufsize)
    75     bufsize = len * 2;
    76 
    77   /* First, find a cache with enough free space.  We always look through all
    78      the blocks and choose the one with the best fit (the one that leaves the
    79      least amount of space free).  */
    80   for (sp = strcache; sp != NULL; sp = sp->next)
    81     if (sp->bytesfree > len && (!best || best->bytesfree > sp->bytesfree))
    82       best = sp;
    83 
    84   /* If nothing is big enough, make a new cache.  */
    85   if (!best)
    86     best = new_cache();
    87 
    88   assert (best->bytesfree > len);
    89 
    90   /* Add the string to the best cache.  */
    91   res = best->end;
    92   memcpy (best->end, str, len);
    93   best->end += len;
    94   *(best->end++) = '\0';
    95   best->bytesfree -= len + 1;
    96   ++best->count;
     103     no existing cache is large enough.  Add it directly to the fullcache.  */
     104  if (sz > BUFSIZE)
     105    {
     106      sp = new_cache (&fullcache, sz);
     107      return copy_string (sp, str, len);
     108    }
     109
     110  /* Find the first cache with enough free space.  */
     111  for (; *spp != NULL; spp = &(*spp)->next)
     112    if ((*spp)->bytesfree > sz)
     113      break;
     114  sp = *spp;
     115
     116  /* If nothing is big enough, make a new cache at the front.  */
     117  if (sp == NULL)
     118    {
     119      sp = new_cache (&strcache, BUFSIZE);
     120      spp = &strcache;
     121    }
     122
     123  /* Add the string to this cache.  */
     124  res = copy_string (sp, str, len);
     125
     126  /* If the amount free in this cache is less than the average string size,
     127     consider it full and move it to the full list.  */
     128  if (total_strings > 20 && sp->bytesfree < (total_size / total_strings) + 1)
     129    {
     130      *spp = sp->next;
     131      sp->next = fullcache;
     132      fullcache = sp;
     133    }
    97134
    98135  return res;
    99136}
    100137
     138/* For strings too large for the strcache, we just save them in a list.  */
     139struct hugestring {
     140  struct hugestring *next;  /* The next string.  */
     141  char buffer[1];           /* The string.  */
     142};
     143
     144static struct hugestring *hugestrings = NULL;
     145
     146static const char *
     147add_hugestring (const char *str, unsigned int len)
     148{
     149  struct hugestring *new = xmalloc (sizeof (struct hugestring) + len);
     150  memcpy (new->buffer, str, len);
     151  new->buffer[len] = '\0';
     152
     153  new->next = hugestrings;
     154  hugestrings = new;
     155
     156  return new->buffer;
     157}
    101158
    102159/* Hash table of strings in the cache.  */
     
    124181
    125182static const char *
    126 add_hash (const char *str, int len)
    127 {
     183add_hash (const char *str, unsigned int len)
     184{
     185  char *const *slot;
     186  const char *key;
     187
     188  /* If it's too large for the string cache, just copy it.
     189     We don't bother trying to match these.  */
     190  if (len > USHRT_MAX - 1)
     191    return add_hugestring (str, len);
     192
    128193  /* Look up the string in the hash.  If it's there, return it.  */
    129   char *const *slot = (char *const *) hash_find_slot (&strings, str);
    130   const char *key = *slot;
    131 
    132   /* Count the total number of adds we performed.  */
     194  slot = (char *const *) hash_find_slot (&strings, str);
     195  key = *slot;
     196
     197  /* Count the total number of add operations we performed.  */
    133198  ++total_adds;
    134199
     
    149214
    150215  for (sp = strcache; sp != 0; sp = sp->next)
    151     if (str >= sp->buffer && str < sp->end)
     216    if (str >= sp->buffer && str < sp->buffer + sp->end)
    152217      return 1;
     218  for (sp = fullcache; sp != 0; sp = sp->next)
     219    if (str >= sp->buffer && str < sp->buffer + sp->end)
     220      return 1;
     221
     222  {
     223    struct hugestring *hp;
     224    for (hp = hugestrings; hp != 0; hp = hp->next)
     225      if (str == hp->buffer)
     226        return 1;
     227  }
    153228
    154229  return 0;
     
    165240
    166241const char *
    167 strcache_add_len (const char *str, int len)
     242strcache_add_len (const char *str, unsigned int len)
    168243{
    169244  /* If we're not given a nul-terminated string we have to create one, because
     
    180255}
    181256
    182 int
    183 strcache_setbufsize(int size)
    184 {
    185   if (size > bufsize)
    186     bufsize = size;
    187   return bufsize;
    188 }
    189 
    190257void
    191258strcache_init (void)
     
    200267strcache_print_stats (const char *prefix)
    201268{
    202   int numbuffs = 0, numstrs = 0;
    203   int totsize = 0, avgsize, maxsize = 0, minsize = bufsize;
    204   int totfree = 0, avgfree, maxfree = 0, minfree = bufsize;
    205   int lastused = 0, lastfree = 0;
    206 
    207   if (strcache)
    208     {
    209       const struct strcache *sp;
    210 
    211       /* Count the first buffer separately since it's not full.  */
    212       lastused = strcache->end - strcache->buffer;
    213       lastfree = strcache->bytesfree;
    214 
    215       for (sp = strcache->next; sp != NULL; sp = sp->next)
    216         {
    217           int bf = sp->bytesfree;
    218           int sz = sp->end - sp->buffer;
    219 
    220           ++numbuffs;
    221           numstrs += sp->count;
    222 
    223           totsize += sz;
    224           maxsize = (sz > maxsize ? sz : maxsize);
    225           minsize = (sz < minsize ? sz : minsize);
    226 
    227           totfree += bf;
    228           maxfree = (bf > maxfree ? bf : maxfree);
    229           minfree = (bf < minfree ? bf : minfree);
    230         }
    231     }
    232 
    233   avgsize = numbuffs ? (int)(totsize / numbuffs) : 0;
    234   avgfree = numbuffs ? (int)(totfree / numbuffs) : 0;
    235 
    236   printf (_("\n%s # of strings in strcache: %d / lookups = %lu / hits = %lu\n"),
    237           prefix, numstrs, total_adds, (total_adds - numstrs));
    238   printf (_("%s # of strcache buffers: %d (* %d B/buffer = %d B)\n"),
    239           prefix, (numbuffs + 1), bufsize, ((numbuffs + 1) * bufsize));
    240   printf (_("%s strcache used: total = %d (%d) / max = %d / min = %d / avg = %d\n"),
    241           prefix, totsize, lastused, maxsize, minsize, avgsize);
    242   printf (_("%s strcache free: total = %d (%d) / max = %d / min = %d / avg = %d\n"),
    243           prefix, totfree, lastfree, maxfree, minfree, avgfree);
    244 
    245   fputs (_("\n# strcache hash-table stats:\n# "), stdout);
     269  const struct strcache *sp;
     270  unsigned long numbuffs = 0, fullbuffs = 0;
     271  unsigned long totfree = 0, maxfree = 0, minfree = BUFSIZE;
     272
     273  if (! strcache)
     274    {
     275      printf (_("\n%s No strcache buffers\n"), prefix);
     276      return;
     277    }
     278
     279  /* Count the first buffer separately since it's not full.  */
     280  for (sp = strcache->next; sp != NULL; sp = sp->next)
     281    {
     282      sc_buflen_t bf = sp->bytesfree;
     283
     284      totfree += bf;
     285      maxfree = (bf > maxfree ? bf : maxfree);
     286      minfree = (bf < minfree ? bf : minfree);
     287
     288      ++numbuffs;
     289    }
     290  for (sp = fullcache; sp != NULL; sp = sp->next)
     291    {
     292      sc_buflen_t bf = sp->bytesfree;
     293
     294      totfree += bf;
     295      maxfree = (bf > maxfree ? bf : maxfree);
     296      minfree = (bf < minfree ? bf : minfree);
     297
     298      ++numbuffs;
     299      ++fullbuffs;
     300    }
     301
     302  /* Make sure we didn't lose any buffers.  */
     303  assert (total_buffers == numbuffs + 1);
     304
     305  printf (_("\n%s strcache buffers: %lu (%lu) / strings = %lu / storage = %lu B / avg = %lu B\n"),
     306          prefix, numbuffs + 1, fullbuffs, total_strings, total_size,
     307          (total_size / total_strings));
     308
     309  printf (_("%s current buf: size = %hu B / used = %hu B / count = %hu / avg = %hu B\n"),
     310          prefix, (sc_buflen_t)BUFSIZE, strcache->end, strcache->count,
     311          (strcache->end / strcache->count));
     312
     313  if (numbuffs)
     314    {
     315      /* Show information about non-current buffers.  */
     316      unsigned long sz = total_size - strcache->end;
     317      unsigned long cnt = total_strings - strcache->count;
     318      sc_buflen_t avgfree = totfree / numbuffs;
     319
     320      printf (_("%s other used: total = %lu B / count = %lu / avg = %lu B\n"),
     321              prefix, sz, cnt, sz / cnt);
     322
     323      printf (_("%s other free: total = %lu B / max = %lu B / min = %lu B / avg = %hu B\n"),
     324              prefix, totfree, maxfree, minfree, avgfree);
     325    }
     326
     327  printf (_("\n%s strcache performance: lookups = %lu / hit rate = %lu%%\n"),
     328          prefix, total_adds, (long unsigned)(100.0 * (total_adds - total_strings) / total_adds));
     329  fputs (_("# hash-table stats:\n# "), stdout);
    246330  hash_print_stats (&strings, stdout);
    247331}
Note: See TracChangeset for help on using the changeset viewer.