Ignore:
Timestamp:
Mar 12, 2018, 8:32:29 PM (7 years ago)
Author:
bird
Message:

Imported make 4.2.1 (2e55f5e4abdc0e38c1d64be703b446695e70b3b6) from https://git.savannah.gnu.org/git/make.git.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • vendor/gnumake/current/strcache.c

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