xref: /dragonfly/contrib/gdb-7/gdb/bcache.c (revision ef5ccd6c)
15796c8dcSSimon Schubert /* Implement a cached obstack.
25796c8dcSSimon Schubert    Written by Fred Fish <fnf@cygnus.com>
35796c8dcSSimon Schubert    Rewritten by Jim Blandy <jimb@cygnus.com>
45796c8dcSSimon Schubert 
5*ef5ccd6cSJohn Marino    Copyright (C) 1999-2013 Free Software Foundation, Inc.
65796c8dcSSimon Schubert 
75796c8dcSSimon Schubert    This file is part of GDB.
85796c8dcSSimon Schubert 
95796c8dcSSimon Schubert    This program is free software; you can redistribute it and/or modify
105796c8dcSSimon Schubert    it under the terms of the GNU General Public License as published by
115796c8dcSSimon Schubert    the Free Software Foundation; either version 3 of the License, or
125796c8dcSSimon Schubert    (at your option) any later version.
135796c8dcSSimon Schubert 
145796c8dcSSimon Schubert    This program is distributed in the hope that it will be useful,
155796c8dcSSimon Schubert    but WITHOUT ANY WARRANTY; without even the implied warranty of
165796c8dcSSimon Schubert    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
175796c8dcSSimon Schubert    GNU General Public License for more details.
185796c8dcSSimon Schubert 
195796c8dcSSimon Schubert    You should have received a copy of the GNU General Public License
205796c8dcSSimon Schubert    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
215796c8dcSSimon Schubert 
225796c8dcSSimon Schubert #include "defs.h"
235796c8dcSSimon Schubert #include "gdb_obstack.h"
245796c8dcSSimon Schubert #include "bcache.h"
255796c8dcSSimon Schubert #include "gdb_string.h"		/* For memcpy declaration */
265796c8dcSSimon Schubert #include "gdb_assert.h"
275796c8dcSSimon Schubert 
285796c8dcSSimon Schubert #include <stddef.h>
295796c8dcSSimon Schubert #include <stdlib.h>
305796c8dcSSimon Schubert 
315796c8dcSSimon Schubert /* The type used to hold a single bcache string.  The user data is
325796c8dcSSimon Schubert    stored in d.data.  Since it can be any type, it needs to have the
335796c8dcSSimon Schubert    same alignment as the most strict alignment of any type on the host
345796c8dcSSimon Schubert    machine.  I don't know of any really correct way to do this in
355796c8dcSSimon Schubert    stock ANSI C, so just do it the same way obstack.h does.  */
365796c8dcSSimon Schubert 
375796c8dcSSimon Schubert struct bstring
385796c8dcSSimon Schubert {
395796c8dcSSimon Schubert   /* Hash chain.  */
405796c8dcSSimon Schubert   struct bstring *next;
415796c8dcSSimon Schubert   /* Assume the data length is no more than 64k.  */
425796c8dcSSimon Schubert   unsigned short length;
435796c8dcSSimon Schubert   /* The half hash hack.  This contains the upper 16 bits of the hash
445796c8dcSSimon Schubert      value and is used as a pre-check when comparing two strings and
455796c8dcSSimon Schubert      avoids the need to do length or memcmp calls.  It proves to be
465796c8dcSSimon Schubert      roughly 100% effective.  */
475796c8dcSSimon Schubert   unsigned short half_hash;
485796c8dcSSimon Schubert 
495796c8dcSSimon Schubert   union
505796c8dcSSimon Schubert   {
515796c8dcSSimon Schubert     char data[1];
525796c8dcSSimon Schubert     double dummy;
535796c8dcSSimon Schubert   }
545796c8dcSSimon Schubert   d;
555796c8dcSSimon Schubert };
565796c8dcSSimon Schubert 
575796c8dcSSimon Schubert 
585796c8dcSSimon Schubert /* The structure for a bcache itself.  The bcache is initialized, in
595796c8dcSSimon Schubert    bcache_xmalloc(), by filling it with zeros and then setting the
605796c8dcSSimon Schubert    corresponding obstack's malloc() and free() methods.  */
615796c8dcSSimon Schubert 
625796c8dcSSimon Schubert struct bcache
635796c8dcSSimon Schubert {
645796c8dcSSimon Schubert   /* All the bstrings are allocated here.  */
655796c8dcSSimon Schubert   struct obstack cache;
665796c8dcSSimon Schubert 
675796c8dcSSimon Schubert   /* How many hash buckets we're using.  */
685796c8dcSSimon Schubert   unsigned int num_buckets;
695796c8dcSSimon Schubert 
705796c8dcSSimon Schubert   /* Hash buckets.  This table is allocated using malloc, so when we
715796c8dcSSimon Schubert      grow the table we can return the old table to the system.  */
725796c8dcSSimon Schubert   struct bstring **bucket;
735796c8dcSSimon Schubert 
745796c8dcSSimon Schubert   /* Statistics.  */
755796c8dcSSimon Schubert   unsigned long unique_count;	/* number of unique strings */
765796c8dcSSimon Schubert   long total_count;	/* total number of strings cached, including dups */
775796c8dcSSimon Schubert   long unique_size;	/* size of unique strings, in bytes */
785796c8dcSSimon Schubert   long total_size;      /* total number of bytes cached, including dups */
795796c8dcSSimon Schubert   long structure_size;	/* total size of bcache, including infrastructure */
805796c8dcSSimon Schubert   /* Number of times that the hash table is expanded and hence
815796c8dcSSimon Schubert      re-built, and the corresponding number of times that a string is
825796c8dcSSimon Schubert      [re]hashed as part of entering it into the expanded table.  The
835796c8dcSSimon Schubert      total number of hashes can be computed by adding TOTAL_COUNT to
845796c8dcSSimon Schubert      expand_hash_count.  */
855796c8dcSSimon Schubert   unsigned long expand_count;
865796c8dcSSimon Schubert   unsigned long expand_hash_count;
875796c8dcSSimon Schubert   /* Number of times that the half-hash compare hit (compare the upper
885796c8dcSSimon Schubert      16 bits of hash values) hit, but the corresponding combined
895796c8dcSSimon Schubert      length/data compare missed.  */
905796c8dcSSimon Schubert   unsigned long half_hash_miss_count;
91c50c785cSJohn Marino 
92c50c785cSJohn Marino   /* Hash function to be used for this bcache object.  */
93c50c785cSJohn Marino   unsigned long (*hash_function)(const void *addr, int length);
94c50c785cSJohn Marino 
95c50c785cSJohn Marino   /* Compare function to be used for this bcache object.  */
96c50c785cSJohn Marino   int (*compare_function)(const void *, const void *, int length);
975796c8dcSSimon Schubert };
985796c8dcSSimon Schubert 
99c50c785cSJohn Marino /* The old hash function was stolen from SDBM. This is what DB 3.0
100c50c785cSJohn Marino    uses now, and is better than the old one.  */
1015796c8dcSSimon Schubert 
1025796c8dcSSimon Schubert unsigned long
hash(const void * addr,int length)1035796c8dcSSimon Schubert hash(const void *addr, int length)
1045796c8dcSSimon Schubert {
105c50c785cSJohn Marino   return hash_continue (addr, length, 0);
106c50c785cSJohn Marino }
107c50c785cSJohn Marino 
108c50c785cSJohn Marino /* Continue the calculation of the hash H at the given address.  */
109c50c785cSJohn Marino 
110c50c785cSJohn Marino unsigned long
hash_continue(const void * addr,int length,unsigned long h)111c50c785cSJohn Marino hash_continue (const void *addr, int length, unsigned long h)
112c50c785cSJohn Marino {
1135796c8dcSSimon Schubert   const unsigned char *k, *e;
1145796c8dcSSimon Schubert 
1155796c8dcSSimon Schubert   k = (const unsigned char *)addr;
1165796c8dcSSimon Schubert   e = k+length;
117c50c785cSJohn Marino   for (; k< e;++k)
1185796c8dcSSimon Schubert     {
1195796c8dcSSimon Schubert       h *=16777619;
1205796c8dcSSimon Schubert       h ^= *k;
1215796c8dcSSimon Schubert     }
1225796c8dcSSimon Schubert   return (h);
1235796c8dcSSimon Schubert }
1245796c8dcSSimon Schubert 
1255796c8dcSSimon Schubert /* Growing the bcache's hash table.  */
1265796c8dcSSimon Schubert 
1275796c8dcSSimon Schubert /* If the average chain length grows beyond this, then we want to
1285796c8dcSSimon Schubert    resize our hash table.  */
1295796c8dcSSimon Schubert #define CHAIN_LENGTH_THRESHOLD (5)
1305796c8dcSSimon Schubert 
1315796c8dcSSimon Schubert static void
expand_hash_table(struct bcache * bcache)1325796c8dcSSimon Schubert expand_hash_table (struct bcache *bcache)
1335796c8dcSSimon Schubert {
1345796c8dcSSimon Schubert   /* A table of good hash table sizes.  Whenever we grow, we pick the
1355796c8dcSSimon Schubert      next larger size from this table.  sizes[i] is close to 1 << (i+10),
1365796c8dcSSimon Schubert      so we roughly double the table size each time.  After we fall off
1375796c8dcSSimon Schubert      the end of this table, we just double.  Don't laugh --- there have
1385796c8dcSSimon Schubert      been executables sighted with a gigabyte of debug info.  */
1395796c8dcSSimon Schubert   static unsigned long sizes[] = {
1405796c8dcSSimon Schubert     1021, 2053, 4099, 8191, 16381, 32771,
1415796c8dcSSimon Schubert     65537, 131071, 262144, 524287, 1048573, 2097143,
1425796c8dcSSimon Schubert     4194301, 8388617, 16777213, 33554467, 67108859, 134217757,
1435796c8dcSSimon Schubert     268435459, 536870923, 1073741827, 2147483659UL
1445796c8dcSSimon Schubert   };
1455796c8dcSSimon Schubert   unsigned int new_num_buckets;
1465796c8dcSSimon Schubert   struct bstring **new_buckets;
1475796c8dcSSimon Schubert   unsigned int i;
1485796c8dcSSimon Schubert 
1495796c8dcSSimon Schubert   /* Count the stats.  Every unique item needs to be re-hashed and
1505796c8dcSSimon Schubert      re-entered.  */
1515796c8dcSSimon Schubert   bcache->expand_count++;
1525796c8dcSSimon Schubert   bcache->expand_hash_count += bcache->unique_count;
1535796c8dcSSimon Schubert 
1545796c8dcSSimon Schubert   /* Find the next size.  */
1555796c8dcSSimon Schubert   new_num_buckets = bcache->num_buckets * 2;
1565796c8dcSSimon Schubert   for (i = 0; i < (sizeof (sizes) / sizeof (sizes[0])); i++)
1575796c8dcSSimon Schubert     if (sizes[i] > bcache->num_buckets)
1585796c8dcSSimon Schubert       {
1595796c8dcSSimon Schubert 	new_num_buckets = sizes[i];
1605796c8dcSSimon Schubert 	break;
1615796c8dcSSimon Schubert       }
1625796c8dcSSimon Schubert 
1635796c8dcSSimon Schubert   /* Allocate the new table.  */
1645796c8dcSSimon Schubert   {
1655796c8dcSSimon Schubert     size_t new_size = new_num_buckets * sizeof (new_buckets[0]);
166cf7f2e2dSJohn Marino 
1675796c8dcSSimon Schubert     new_buckets = (struct bstring **) xmalloc (new_size);
1685796c8dcSSimon Schubert     memset (new_buckets, 0, new_size);
1695796c8dcSSimon Schubert 
1705796c8dcSSimon Schubert     bcache->structure_size -= (bcache->num_buckets
1715796c8dcSSimon Schubert 			       * sizeof (bcache->bucket[0]));
1725796c8dcSSimon Schubert     bcache->structure_size += new_size;
1735796c8dcSSimon Schubert   }
1745796c8dcSSimon Schubert 
1755796c8dcSSimon Schubert   /* Rehash all existing strings.  */
1765796c8dcSSimon Schubert   for (i = 0; i < bcache->num_buckets; i++)
1775796c8dcSSimon Schubert     {
1785796c8dcSSimon Schubert       struct bstring *s, *next;
1795796c8dcSSimon Schubert 
1805796c8dcSSimon Schubert       for (s = bcache->bucket[i]; s; s = next)
1815796c8dcSSimon Schubert 	{
1825796c8dcSSimon Schubert 	  struct bstring **new_bucket;
1835796c8dcSSimon Schubert 	  next = s->next;
1845796c8dcSSimon Schubert 
185c50c785cSJohn Marino 	  new_bucket = &new_buckets[(bcache->hash_function (&s->d.data,
186c50c785cSJohn Marino 							    s->length)
1875796c8dcSSimon Schubert 				     % new_num_buckets)];
1885796c8dcSSimon Schubert 	  s->next = *new_bucket;
1895796c8dcSSimon Schubert 	  *new_bucket = s;
1905796c8dcSSimon Schubert 	}
1915796c8dcSSimon Schubert     }
1925796c8dcSSimon Schubert 
1935796c8dcSSimon Schubert   /* Plug in the new table.  */
1945796c8dcSSimon Schubert   if (bcache->bucket)
1955796c8dcSSimon Schubert     xfree (bcache->bucket);
1965796c8dcSSimon Schubert   bcache->bucket = new_buckets;
1975796c8dcSSimon Schubert   bcache->num_buckets = new_num_buckets;
1985796c8dcSSimon Schubert }
1995796c8dcSSimon Schubert 
2005796c8dcSSimon Schubert 
2015796c8dcSSimon Schubert /* Looking up things in the bcache.  */
2025796c8dcSSimon Schubert 
2035796c8dcSSimon Schubert /* The number of bytes needed to allocate a struct bstring whose data
2045796c8dcSSimon Schubert    is N bytes long.  */
2055796c8dcSSimon Schubert #define BSTRING_SIZE(n) (offsetof (struct bstring, d.data) + (n))
2065796c8dcSSimon Schubert 
2075796c8dcSSimon Schubert /* Find a copy of the LENGTH bytes at ADDR in BCACHE.  If BCACHE has
2085796c8dcSSimon Schubert    never seen those bytes before, add a copy of them to BCACHE.  In
2095796c8dcSSimon Schubert    either case, return a pointer to BCACHE's copy of that string.  */
2105796c8dcSSimon Schubert const void *
bcache(const void * addr,int length,struct bcache * cache)211a45ae5f8SJohn Marino bcache (const void *addr, int length, struct bcache *cache)
2125796c8dcSSimon Schubert {
213a45ae5f8SJohn Marino   return bcache_full (addr, length, cache, NULL);
2145796c8dcSSimon Schubert }
2155796c8dcSSimon Schubert 
2165796c8dcSSimon Schubert /* Find a copy of the LENGTH bytes at ADDR in BCACHE.  If BCACHE has
2175796c8dcSSimon Schubert    never seen those bytes before, add a copy of them to BCACHE.  In
2185796c8dcSSimon Schubert    either case, return a pointer to BCACHE's copy of that string.  If
2195796c8dcSSimon Schubert    optional ADDED is not NULL, return 1 in case of new entry or 0 if
2205796c8dcSSimon Schubert    returning an old entry.  */
2215796c8dcSSimon Schubert 
2225796c8dcSSimon Schubert const void *
bcache_full(const void * addr,int length,struct bcache * bcache,int * added)2235796c8dcSSimon Schubert bcache_full (const void *addr, int length, struct bcache *bcache, int *added)
2245796c8dcSSimon Schubert {
2255796c8dcSSimon Schubert   unsigned long full_hash;
2265796c8dcSSimon Schubert   unsigned short half_hash;
2275796c8dcSSimon Schubert   int hash_index;
2285796c8dcSSimon Schubert   struct bstring *s;
2295796c8dcSSimon Schubert 
2305796c8dcSSimon Schubert   if (added)
2315796c8dcSSimon Schubert     *added = 0;
2325796c8dcSSimon Schubert 
2335796c8dcSSimon Schubert   /* Lazily initialize the obstack.  This can save quite a bit of
2345796c8dcSSimon Schubert      memory in some cases.  */
2355796c8dcSSimon Schubert   if (bcache->total_count == 0)
2365796c8dcSSimon Schubert     {
2375796c8dcSSimon Schubert       /* We could use obstack_specify_allocation here instead, but
2385796c8dcSSimon Schubert 	 gdb_obstack.h specifies the allocation/deallocation
2395796c8dcSSimon Schubert 	 functions.  */
2405796c8dcSSimon Schubert       obstack_init (&bcache->cache);
2415796c8dcSSimon Schubert     }
2425796c8dcSSimon Schubert 
2435796c8dcSSimon Schubert   /* If our average chain length is too high, expand the hash table.  */
2445796c8dcSSimon Schubert   if (bcache->unique_count >= bcache->num_buckets * CHAIN_LENGTH_THRESHOLD)
2455796c8dcSSimon Schubert     expand_hash_table (bcache);
2465796c8dcSSimon Schubert 
2475796c8dcSSimon Schubert   bcache->total_count++;
2485796c8dcSSimon Schubert   bcache->total_size += length;
2495796c8dcSSimon Schubert 
250c50c785cSJohn Marino   full_hash = bcache->hash_function (addr, length);
251c50c785cSJohn Marino 
2525796c8dcSSimon Schubert   half_hash = (full_hash >> 16);
2535796c8dcSSimon Schubert   hash_index = full_hash % bcache->num_buckets;
2545796c8dcSSimon Schubert 
2555796c8dcSSimon Schubert   /* Search the hash bucket for a string identical to the caller's.
2565796c8dcSSimon Schubert      As a short-circuit first compare the upper part of each hash
2575796c8dcSSimon Schubert      values.  */
2585796c8dcSSimon Schubert   for (s = bcache->bucket[hash_index]; s; s = s->next)
2595796c8dcSSimon Schubert     {
2605796c8dcSSimon Schubert       if (s->half_hash == half_hash)
2615796c8dcSSimon Schubert 	{
2625796c8dcSSimon Schubert 	  if (s->length == length
263c50c785cSJohn Marino 	      && bcache->compare_function (&s->d.data, addr, length))
2645796c8dcSSimon Schubert 	    return &s->d.data;
2655796c8dcSSimon Schubert 	  else
2665796c8dcSSimon Schubert 	    bcache->half_hash_miss_count++;
2675796c8dcSSimon Schubert 	}
2685796c8dcSSimon Schubert     }
2695796c8dcSSimon Schubert 
2705796c8dcSSimon Schubert   /* The user's string isn't in the list.  Insert it after *ps.  */
2715796c8dcSSimon Schubert   {
2725796c8dcSSimon Schubert     struct bstring *new
2735796c8dcSSimon Schubert       = obstack_alloc (&bcache->cache, BSTRING_SIZE (length));
274cf7f2e2dSJohn Marino 
2755796c8dcSSimon Schubert     memcpy (&new->d.data, addr, length);
2765796c8dcSSimon Schubert     new->length = length;
2775796c8dcSSimon Schubert     new->next = bcache->bucket[hash_index];
2785796c8dcSSimon Schubert     new->half_hash = half_hash;
2795796c8dcSSimon Schubert     bcache->bucket[hash_index] = new;
2805796c8dcSSimon Schubert 
2815796c8dcSSimon Schubert     bcache->unique_count++;
2825796c8dcSSimon Schubert     bcache->unique_size += length;
2835796c8dcSSimon Schubert     bcache->structure_size += BSTRING_SIZE (length);
2845796c8dcSSimon Schubert 
2855796c8dcSSimon Schubert     if (added)
2865796c8dcSSimon Schubert       *added = 1;
2875796c8dcSSimon Schubert 
2885796c8dcSSimon Schubert     return &new->d.data;
2895796c8dcSSimon Schubert   }
2905796c8dcSSimon Schubert }
2915796c8dcSSimon Schubert 
292c50c785cSJohn Marino 
293c50c785cSJohn Marino /* Compare the byte string at ADDR1 of lenght LENGHT to the
294c50c785cSJohn Marino    string at ADDR2.  Return 1 if they are equal.  */
295c50c785cSJohn Marino 
296c50c785cSJohn Marino static int
bcache_compare(const void * addr1,const void * addr2,int length)297c50c785cSJohn Marino bcache_compare (const void *addr1, const void *addr2, int length)
298c50c785cSJohn Marino {
299c50c785cSJohn Marino   return memcmp (addr1, addr2, length) == 0;
300c50c785cSJohn Marino }
301c50c785cSJohn Marino 
3025796c8dcSSimon Schubert /* Allocating and freeing bcaches.  */
3035796c8dcSSimon Schubert 
304c50c785cSJohn Marino /* Allocated a bcache.  HASH_FUNCTION and COMPARE_FUNCTION can be used
305c50c785cSJohn Marino    to pass in custom hash, and compare functions to be used by this
306c50c785cSJohn Marino    bcache.  If HASH_FUNCTION is NULL hash() is used and if
307c50c785cSJohn Marino    COMPARE_FUNCTION is NULL memcmp() is used.  */
308c50c785cSJohn Marino 
3095796c8dcSSimon Schubert struct bcache *
bcache_xmalloc(unsigned long (* hash_function)(const void *,int length),int (* compare_function)(const void *,const void *,int length))310c50c785cSJohn Marino bcache_xmalloc (unsigned long (*hash_function)(const void *, int length),
311c50c785cSJohn Marino                 int (*compare_function)(const void *,
312c50c785cSJohn Marino 					const void *,
313c50c785cSJohn Marino 					int length))
3145796c8dcSSimon Schubert {
3155796c8dcSSimon Schubert   /* Allocate the bcache pre-zeroed.  */
3165796c8dcSSimon Schubert   struct bcache *b = XCALLOC (1, struct bcache);
317cf7f2e2dSJohn Marino 
318c50c785cSJohn Marino   if (hash_function)
319c50c785cSJohn Marino     b->hash_function = hash_function;
320c50c785cSJohn Marino   else
321c50c785cSJohn Marino     b->hash_function = hash;
322c50c785cSJohn Marino 
323c50c785cSJohn Marino   if (compare_function)
324c50c785cSJohn Marino     b->compare_function = compare_function;
325c50c785cSJohn Marino   else
326c50c785cSJohn Marino     b->compare_function = bcache_compare;
3275796c8dcSSimon Schubert   return b;
3285796c8dcSSimon Schubert }
3295796c8dcSSimon Schubert 
3305796c8dcSSimon Schubert /* Free all the storage associated with BCACHE.  */
3315796c8dcSSimon Schubert void
bcache_xfree(struct bcache * bcache)3325796c8dcSSimon Schubert bcache_xfree (struct bcache *bcache)
3335796c8dcSSimon Schubert {
3345796c8dcSSimon Schubert   if (bcache == NULL)
3355796c8dcSSimon Schubert     return;
3365796c8dcSSimon Schubert   /* Only free the obstack if we actually initialized it.  */
3375796c8dcSSimon Schubert   if (bcache->total_count > 0)
3385796c8dcSSimon Schubert     obstack_free (&bcache->cache, 0);
3395796c8dcSSimon Schubert   xfree (bcache->bucket);
3405796c8dcSSimon Schubert   xfree (bcache);
3415796c8dcSSimon Schubert }
3425796c8dcSSimon Schubert 
3435796c8dcSSimon Schubert 
3445796c8dcSSimon Schubert 
3455796c8dcSSimon Schubert /* Printing statistics.  */
3465796c8dcSSimon Schubert 
3475796c8dcSSimon Schubert static void
print_percentage(int portion,int total)3485796c8dcSSimon Schubert print_percentage (int portion, int total)
3495796c8dcSSimon Schubert {
3505796c8dcSSimon Schubert   if (total == 0)
351c50c785cSJohn Marino     /* i18n: Like "Percentage of duplicates, by count: (not applicable)".  */
3525796c8dcSSimon Schubert     printf_filtered (_("(not applicable)\n"));
3535796c8dcSSimon Schubert   else
3545796c8dcSSimon Schubert     printf_filtered ("%3d%%\n", (int) (portion * 100.0 / total));
3555796c8dcSSimon Schubert }
3565796c8dcSSimon Schubert 
3575796c8dcSSimon Schubert 
3585796c8dcSSimon Schubert /* Print statistics on BCACHE's memory usage and efficacity at
3595796c8dcSSimon Schubert    eliminating duplication.  NAME should describe the kind of data
3605796c8dcSSimon Schubert    BCACHE holds.  Statistics are printed using `printf_filtered' and
3615796c8dcSSimon Schubert    its ilk.  */
3625796c8dcSSimon Schubert void
print_bcache_statistics(struct bcache * c,char * type)3635796c8dcSSimon Schubert print_bcache_statistics (struct bcache *c, char *type)
3645796c8dcSSimon Schubert {
3655796c8dcSSimon Schubert   int occupied_buckets;
3665796c8dcSSimon Schubert   int max_chain_length;
3675796c8dcSSimon Schubert   int median_chain_length;
3685796c8dcSSimon Schubert   int max_entry_size;
3695796c8dcSSimon Schubert   int median_entry_size;
3705796c8dcSSimon Schubert 
3715796c8dcSSimon Schubert   /* Count the number of occupied buckets, tally the various string
3725796c8dcSSimon Schubert      lengths, and measure chain lengths.  */
3735796c8dcSSimon Schubert   {
3745796c8dcSSimon Schubert     unsigned int b;
3755796c8dcSSimon Schubert     int *chain_length = XCALLOC (c->num_buckets + 1, int);
3765796c8dcSSimon Schubert     int *entry_size = XCALLOC (c->unique_count + 1, int);
3775796c8dcSSimon Schubert     int stringi = 0;
3785796c8dcSSimon Schubert 
3795796c8dcSSimon Schubert     occupied_buckets = 0;
3805796c8dcSSimon Schubert 
3815796c8dcSSimon Schubert     for (b = 0; b < c->num_buckets; b++)
3825796c8dcSSimon Schubert       {
3835796c8dcSSimon Schubert 	struct bstring *s = c->bucket[b];
3845796c8dcSSimon Schubert 
3855796c8dcSSimon Schubert 	chain_length[b] = 0;
3865796c8dcSSimon Schubert 
3875796c8dcSSimon Schubert 	if (s)
3885796c8dcSSimon Schubert 	  {
3895796c8dcSSimon Schubert 	    occupied_buckets++;
3905796c8dcSSimon Schubert 
3915796c8dcSSimon Schubert 	    while (s)
3925796c8dcSSimon Schubert 	      {
3935796c8dcSSimon Schubert 		gdb_assert (b < c->num_buckets);
3945796c8dcSSimon Schubert 		chain_length[b]++;
3955796c8dcSSimon Schubert 		gdb_assert (stringi < c->unique_count);
3965796c8dcSSimon Schubert 		entry_size[stringi++] = s->length;
3975796c8dcSSimon Schubert 		s = s->next;
3985796c8dcSSimon Schubert 	      }
3995796c8dcSSimon Schubert 	  }
4005796c8dcSSimon Schubert       }
4015796c8dcSSimon Schubert 
402c50c785cSJohn Marino     /* To compute the median, we need the set of chain lengths
403c50c785cSJohn Marino        sorted.  */
4045796c8dcSSimon Schubert     qsort (chain_length, c->num_buckets, sizeof (chain_length[0]),
405cf7f2e2dSJohn Marino 	   compare_positive_ints);
4065796c8dcSSimon Schubert     qsort (entry_size, c->unique_count, sizeof (entry_size[0]),
407cf7f2e2dSJohn Marino 	   compare_positive_ints);
4085796c8dcSSimon Schubert 
4095796c8dcSSimon Schubert     if (c->num_buckets > 0)
4105796c8dcSSimon Schubert       {
4115796c8dcSSimon Schubert 	max_chain_length = chain_length[c->num_buckets - 1];
4125796c8dcSSimon Schubert 	median_chain_length = chain_length[c->num_buckets / 2];
4135796c8dcSSimon Schubert       }
4145796c8dcSSimon Schubert     else
4155796c8dcSSimon Schubert       {
4165796c8dcSSimon Schubert 	max_chain_length = 0;
4175796c8dcSSimon Schubert 	median_chain_length = 0;
4185796c8dcSSimon Schubert       }
4195796c8dcSSimon Schubert     if (c->unique_count > 0)
4205796c8dcSSimon Schubert       {
4215796c8dcSSimon Schubert 	max_entry_size = entry_size[c->unique_count - 1];
4225796c8dcSSimon Schubert 	median_entry_size = entry_size[c->unique_count / 2];
4235796c8dcSSimon Schubert       }
4245796c8dcSSimon Schubert     else
4255796c8dcSSimon Schubert       {
4265796c8dcSSimon Schubert 	max_entry_size = 0;
4275796c8dcSSimon Schubert 	median_entry_size = 0;
4285796c8dcSSimon Schubert       }
4295796c8dcSSimon Schubert 
4305796c8dcSSimon Schubert     xfree (chain_length);
4315796c8dcSSimon Schubert     xfree (entry_size);
4325796c8dcSSimon Schubert   }
4335796c8dcSSimon Schubert 
4345796c8dcSSimon Schubert   printf_filtered (_("  Cached '%s' statistics:\n"), type);
4355796c8dcSSimon Schubert   printf_filtered (_("    Total object count:  %ld\n"), c->total_count);
4365796c8dcSSimon Schubert   printf_filtered (_("    Unique object count: %lu\n"), c->unique_count);
4375796c8dcSSimon Schubert   printf_filtered (_("    Percentage of duplicates, by count: "));
4385796c8dcSSimon Schubert   print_percentage (c->total_count - c->unique_count, c->total_count);
4395796c8dcSSimon Schubert   printf_filtered ("\n");
4405796c8dcSSimon Schubert 
4415796c8dcSSimon Schubert   printf_filtered (_("    Total object size:   %ld\n"), c->total_size);
4425796c8dcSSimon Schubert   printf_filtered (_("    Unique object size:  %ld\n"), c->unique_size);
4435796c8dcSSimon Schubert   printf_filtered (_("    Percentage of duplicates, by size:  "));
4445796c8dcSSimon Schubert   print_percentage (c->total_size - c->unique_size, c->total_size);
4455796c8dcSSimon Schubert   printf_filtered ("\n");
4465796c8dcSSimon Schubert 
4475796c8dcSSimon Schubert   printf_filtered (_("    Max entry size:     %d\n"), max_entry_size);
4485796c8dcSSimon Schubert   printf_filtered (_("    Average entry size: "));
4495796c8dcSSimon Schubert   if (c->unique_count > 0)
4505796c8dcSSimon Schubert     printf_filtered ("%ld\n", c->unique_size / c->unique_count);
4515796c8dcSSimon Schubert   else
452c50c785cSJohn Marino     /* i18n: "Average entry size: (not applicable)".  */
4535796c8dcSSimon Schubert     printf_filtered (_("(not applicable)\n"));
4545796c8dcSSimon Schubert   printf_filtered (_("    Median entry size:  %d\n"), median_entry_size);
4555796c8dcSSimon Schubert   printf_filtered ("\n");
4565796c8dcSSimon Schubert 
457c50c785cSJohn Marino   printf_filtered (_("    \
458c50c785cSJohn Marino Total memory used by bcache, including overhead: %ld\n"),
4595796c8dcSSimon Schubert 		   c->structure_size);
4605796c8dcSSimon Schubert   printf_filtered (_("    Percentage memory overhead: "));
4615796c8dcSSimon Schubert   print_percentage (c->structure_size - c->unique_size, c->unique_size);
4625796c8dcSSimon Schubert   printf_filtered (_("    Net memory savings:         "));
4635796c8dcSSimon Schubert   print_percentage (c->total_size - c->structure_size, c->total_size);
4645796c8dcSSimon Schubert   printf_filtered ("\n");
4655796c8dcSSimon Schubert 
466c50c785cSJohn Marino   printf_filtered (_("    Hash table size:           %3d\n"),
467c50c785cSJohn Marino 		   c->num_buckets);
4685796c8dcSSimon Schubert   printf_filtered (_("    Hash table expands:        %lu\n"),
4695796c8dcSSimon Schubert 		   c->expand_count);
4705796c8dcSSimon Schubert   printf_filtered (_("    Hash table hashes:         %lu\n"),
4715796c8dcSSimon Schubert 		   c->total_count + c->expand_hash_count);
4725796c8dcSSimon Schubert   printf_filtered (_("    Half hash misses:          %lu\n"),
4735796c8dcSSimon Schubert 		   c->half_hash_miss_count);
4745796c8dcSSimon Schubert   printf_filtered (_("    Hash table population:     "));
4755796c8dcSSimon Schubert   print_percentage (occupied_buckets, c->num_buckets);
4765796c8dcSSimon Schubert   printf_filtered (_("    Median hash chain length:  %3d\n"),
4775796c8dcSSimon Schubert 		   median_chain_length);
4785796c8dcSSimon Schubert   printf_filtered (_("    Average hash chain length: "));
4795796c8dcSSimon Schubert   if (c->num_buckets > 0)
4805796c8dcSSimon Schubert     printf_filtered ("%3lu\n", c->unique_count / c->num_buckets);
4815796c8dcSSimon Schubert   else
482c50c785cSJohn Marino     /* i18n: "Average hash chain length: (not applicable)".  */
4835796c8dcSSimon Schubert     printf_filtered (_("(not applicable)\n"));
484c50c785cSJohn Marino   printf_filtered (_("    Maximum hash chain length: %3d\n"),
485c50c785cSJohn Marino 		   max_chain_length);
4865796c8dcSSimon Schubert   printf_filtered ("\n");
4875796c8dcSSimon Schubert }
4885796c8dcSSimon Schubert 
4895796c8dcSSimon Schubert int
bcache_memory_used(struct bcache * bcache)4905796c8dcSSimon Schubert bcache_memory_used (struct bcache *bcache)
4915796c8dcSSimon Schubert {
4925796c8dcSSimon Schubert   if (bcache->total_count == 0)
4935796c8dcSSimon Schubert     return 0;
4945796c8dcSSimon Schubert   return obstack_memory_used (&bcache->cache);
4955796c8dcSSimon Schubert }
496