xref: /openbsd/gnu/usr.bin/binutils/gdb/bcache.c (revision 63addd46)
1e93f7393Sniklas /* Implement a cached obstack.
2b725ae77Skettenis    Written by Fred Fish <fnf@cygnus.com>
3b725ae77Skettenis    Rewritten by Jim Blandy <jimb@cygnus.com>
4b725ae77Skettenis 
5b725ae77Skettenis    Copyright 1999, 2000, 2002, 2003 Free Software Foundation, Inc.
6e93f7393Sniklas 
7e93f7393Sniklas    This file is part of GDB.
8e93f7393Sniklas 
9e93f7393Sniklas    This program is free software; you can redistribute it and/or modify
10e93f7393Sniklas    it under the terms of the GNU General Public License as published by
11e93f7393Sniklas    the Free Software Foundation; either version 2 of the License, or
12e93f7393Sniklas    (at your option) any later version.
13e93f7393Sniklas 
14e93f7393Sniklas    This program is distributed in the hope that it will be useful,
15e93f7393Sniklas    but WITHOUT ANY WARRANTY; without even the implied warranty of
16e93f7393Sniklas    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17e93f7393Sniklas    GNU General Public License for more details.
18e93f7393Sniklas 
19e93f7393Sniklas    You should have received a copy of the GNU General Public License
20e93f7393Sniklas    along with this program; if not, write to the Free Software
21b725ae77Skettenis    Foundation, Inc., 59 Temple Place - Suite 330,
22b725ae77Skettenis    Boston, MA 02111-1307, USA.  */
23e93f7393Sniklas 
24e93f7393Sniklas #include "defs.h"
25b725ae77Skettenis #include "gdb_obstack.h"
26e93f7393Sniklas #include "bcache.h"
27e93f7393Sniklas #include "gdb_string.h"		/* For memcpy declaration */
28b725ae77Skettenis #include "gdb_assert.h"
29e93f7393Sniklas 
30b725ae77Skettenis #include <stddef.h>
31b725ae77Skettenis #include <stdlib.h>
32e93f7393Sniklas 
33b725ae77Skettenis /* The type used to hold a single bcache string.  The user data is
34b725ae77Skettenis    stored in d.data.  Since it can be any type, it needs to have the
35b725ae77Skettenis    same alignment as the most strict alignment of any type on the host
36b725ae77Skettenis    machine.  I don't know of any really correct way to do this in
37b725ae77Skettenis    stock ANSI C, so just do it the same way obstack.h does.  */
38e93f7393Sniklas 
39b725ae77Skettenis struct bstring
40e93f7393Sniklas {
41b725ae77Skettenis   /* Hash chain.  */
42b725ae77Skettenis   struct bstring *next;
43b725ae77Skettenis   /* Assume the data length is no more than 64k.  */
44b725ae77Skettenis   unsigned short length;
45b725ae77Skettenis   /* The half hash hack.  This contains the upper 16 bits of the hash
46b725ae77Skettenis      value and is used as a pre-check when comparing two strings and
47b725ae77Skettenis      avoids the need to do length or memcmp calls.  It proves to be
48b725ae77Skettenis      roughly 100% effective.  */
49b725ae77Skettenis   unsigned short half_hash;
50e93f7393Sniklas 
51b725ae77Skettenis   union
52e93f7393Sniklas   {
53b725ae77Skettenis     char data[1];
54b725ae77Skettenis     double dummy;
55e93f7393Sniklas   }
56b725ae77Skettenis   d;
57b725ae77Skettenis };
58b725ae77Skettenis 
59b725ae77Skettenis 
60b725ae77Skettenis /* The structure for a bcache itself.  The bcache is initialized, in
61b725ae77Skettenis    bcache_xmalloc(), by filling it with zeros and then setting the
62b725ae77Skettenis    corresponding obstack's malloc() and free() methods.  */
63b725ae77Skettenis 
64b725ae77Skettenis struct bcache
65b725ae77Skettenis {
66b725ae77Skettenis   /* All the bstrings are allocated here.  */
67b725ae77Skettenis   struct obstack cache;
68b725ae77Skettenis 
69b725ae77Skettenis   /* How many hash buckets we're using.  */
70b725ae77Skettenis   unsigned int num_buckets;
71b725ae77Skettenis 
72b725ae77Skettenis   /* Hash buckets.  This table is allocated using malloc, so when we
73b725ae77Skettenis      grow the table we can return the old table to the system.  */
74b725ae77Skettenis   struct bstring **bucket;
75b725ae77Skettenis 
76b725ae77Skettenis   /* Statistics.  */
77b725ae77Skettenis   unsigned long unique_count;	/* number of unique strings */
78b725ae77Skettenis   long total_count;	/* total number of strings cached, including dups */
79b725ae77Skettenis   long unique_size;	/* size of unique strings, in bytes */
80b725ae77Skettenis   long total_size;      /* total number of bytes cached, including dups */
81b725ae77Skettenis   long structure_size;	/* total size of bcache, including infrastructure */
82b725ae77Skettenis   /* Number of times that the hash table is expanded and hence
83b725ae77Skettenis      re-built, and the corresponding number of times that a string is
84b725ae77Skettenis      [re]hashed as part of entering it into the expanded table.  The
85b725ae77Skettenis      total number of hashes can be computed by adding TOTAL_COUNT to
86b725ae77Skettenis      expand_hash_count.  */
87b725ae77Skettenis   unsigned long expand_count;
88b725ae77Skettenis   unsigned long expand_hash_count;
89b725ae77Skettenis   /* Number of times that the half-hash compare hit (compare the upper
90b725ae77Skettenis      16 bits of hash values) hit, but the corresponding combined
91b725ae77Skettenis      length/data compare missed.  */
92b725ae77Skettenis   unsigned long half_hash_miss_count;
93b725ae77Skettenis };
94b725ae77Skettenis 
95b725ae77Skettenis /* The old hash function was stolen from SDBM. This is what DB 3.0 uses now,
96b725ae77Skettenis  * and is better than the old one.
97b725ae77Skettenis  */
98b725ae77Skettenis 
99b725ae77Skettenis unsigned long
hash(const void * addr,int length)100b725ae77Skettenis hash(const void *addr, int length)
101b725ae77Skettenis {
102b725ae77Skettenis 		const unsigned char *k, *e;
103b725ae77Skettenis 		unsigned long h;
104b725ae77Skettenis 
105b725ae77Skettenis 		k = (const unsigned char *)addr;
106b725ae77Skettenis 		e = k+length;
107b725ae77Skettenis 		for (h=0; k< e;++k)
108b725ae77Skettenis 		{
109b725ae77Skettenis 				h *=16777619;
110b725ae77Skettenis 				h ^= *k;
111e93f7393Sniklas 		}
112b725ae77Skettenis 		return (h);
113b725ae77Skettenis }
114b725ae77Skettenis 
115b725ae77Skettenis /* Growing the bcache's hash table.  */
116e93f7393Sniklas 
117b725ae77Skettenis /* If the average chain length grows beyond this, then we want to
118b725ae77Skettenis    resize our hash table.  */
119b725ae77Skettenis #define CHAIN_LENGTH_THRESHOLD (5)
120e93f7393Sniklas 
121b725ae77Skettenis static void
expand_hash_table(struct bcache * bcache)122b725ae77Skettenis expand_hash_table (struct bcache *bcache)
123e93f7393Sniklas {
124b725ae77Skettenis   /* A table of good hash table sizes.  Whenever we grow, we pick the
125b725ae77Skettenis      next larger size from this table.  sizes[i] is close to 1 << (i+10),
126b725ae77Skettenis      so we roughly double the table size each time.  After we fall off
127b725ae77Skettenis      the end of this table, we just double.  Don't laugh --- there have
128b725ae77Skettenis      been executables sighted with a gigabyte of debug info.  */
129b725ae77Skettenis   static unsigned long sizes[] = {
130b725ae77Skettenis     1021, 2053, 4099, 8191, 16381, 32771,
131b725ae77Skettenis     65537, 131071, 262144, 524287, 1048573, 2097143,
132b725ae77Skettenis     4194301, 8388617, 16777213, 33554467, 67108859, 134217757,
133b725ae77Skettenis     268435459, 536870923, 1073741827, 2147483659UL
134b725ae77Skettenis   };
135b725ae77Skettenis   unsigned int new_num_buckets;
136b725ae77Skettenis   struct bstring **new_buckets;
137b725ae77Skettenis   unsigned int i;
138b725ae77Skettenis 
139b725ae77Skettenis   /* Count the stats.  Every unique item needs to be re-hashed and
140b725ae77Skettenis      re-entered.  */
141b725ae77Skettenis   bcache->expand_count++;
142b725ae77Skettenis   bcache->expand_hash_count += bcache->unique_count;
143b725ae77Skettenis 
144b725ae77Skettenis   /* Find the next size.  */
145b725ae77Skettenis   new_num_buckets = bcache->num_buckets * 2;
146b725ae77Skettenis   for (i = 0; i < (sizeof (sizes) / sizeof (sizes[0])); i++)
147b725ae77Skettenis     if (sizes[i] > bcache->num_buckets)
148e93f7393Sniklas       {
149b725ae77Skettenis 	new_num_buckets = sizes[i];
150e93f7393Sniklas 	break;
151e93f7393Sniklas       }
152b725ae77Skettenis 
153b725ae77Skettenis   /* Allocate the new table.  */
154b725ae77Skettenis   {
155b725ae77Skettenis     size_t new_size = new_num_buckets * sizeof (new_buckets[0]);
156b725ae77Skettenis     new_buckets = (struct bstring **) xmalloc (new_size);
157b725ae77Skettenis     memset (new_buckets, 0, new_size);
158b725ae77Skettenis 
159b725ae77Skettenis     bcache->structure_size -= (bcache->num_buckets
160b725ae77Skettenis 			       * sizeof (bcache->bucket[0]));
161b725ae77Skettenis     bcache->structure_size += new_size;
162b725ae77Skettenis   }
163b725ae77Skettenis 
164b725ae77Skettenis   /* Rehash all existing strings.  */
165b725ae77Skettenis   for (i = 0; i < bcache->num_buckets; i++)
166b725ae77Skettenis     {
167b725ae77Skettenis       struct bstring *s, *next;
168b725ae77Skettenis 
169b725ae77Skettenis       for (s = bcache->bucket[i]; s; s = next)
170b725ae77Skettenis 	{
171b725ae77Skettenis 	  struct bstring **new_bucket;
172b725ae77Skettenis 	  next = s->next;
173b725ae77Skettenis 
174b725ae77Skettenis 	  new_bucket = &new_buckets[(hash (&s->d.data, s->length)
175b725ae77Skettenis 				     % new_num_buckets)];
176b725ae77Skettenis 	  s->next = *new_bucket;
177b725ae77Skettenis 	  *new_bucket = s;
178e93f7393Sniklas 	}
179e93f7393Sniklas     }
180b725ae77Skettenis 
181b725ae77Skettenis   /* Plug in the new table.  */
182b725ae77Skettenis   if (bcache->bucket)
183b725ae77Skettenis     xfree (bcache->bucket);
184b725ae77Skettenis   bcache->bucket = new_buckets;
185b725ae77Skettenis   bcache->num_buckets = new_num_buckets;
186b725ae77Skettenis }
187b725ae77Skettenis 
188b725ae77Skettenis 
189b725ae77Skettenis /* Looking up things in the bcache.  */
190b725ae77Skettenis 
191b725ae77Skettenis /* The number of bytes needed to allocate a struct bstring whose data
192b725ae77Skettenis    is N bytes long.  */
193b725ae77Skettenis #define BSTRING_SIZE(n) (offsetof (struct bstring, d.data) + (n))
194b725ae77Skettenis 
195b725ae77Skettenis /* Find a copy of the LENGTH bytes at ADDR in BCACHE.  If BCACHE has
196b725ae77Skettenis    never seen those bytes before, add a copy of them to BCACHE.  In
197b725ae77Skettenis    either case, return a pointer to BCACHE's copy of that string.  */
198b725ae77Skettenis static void *
bcache_data(const void * addr,int length,struct bcache * bcache)199b725ae77Skettenis bcache_data (const void *addr, int length, struct bcache *bcache)
200b725ae77Skettenis {
201b725ae77Skettenis   unsigned long full_hash;
202b725ae77Skettenis   unsigned short half_hash;
203b725ae77Skettenis   int hash_index;
204b725ae77Skettenis   struct bstring *s;
205b725ae77Skettenis 
206b725ae77Skettenis   /* If our average chain length is too high, expand the hash table.  */
207b725ae77Skettenis   if (bcache->unique_count >= bcache->num_buckets * CHAIN_LENGTH_THRESHOLD)
208b725ae77Skettenis     expand_hash_table (bcache);
209b725ae77Skettenis 
210b725ae77Skettenis   bcache->total_count++;
211b725ae77Skettenis   bcache->total_size += length;
212b725ae77Skettenis 
213b725ae77Skettenis   full_hash = hash (addr, length);
214b725ae77Skettenis   half_hash = (full_hash >> 16);
215b725ae77Skettenis   hash_index = full_hash % bcache->num_buckets;
216b725ae77Skettenis 
217b725ae77Skettenis   /* Search the hash bucket for a string identical to the caller's.
218b725ae77Skettenis      As a short-circuit first compare the upper part of each hash
219b725ae77Skettenis      values.  */
220b725ae77Skettenis   for (s = bcache->bucket[hash_index]; s; s = s->next)
221b725ae77Skettenis     {
222b725ae77Skettenis       if (s->half_hash == half_hash)
223b725ae77Skettenis 	{
224b725ae77Skettenis 	  if (s->length == length
225b725ae77Skettenis 	      && ! memcmp (&s->d.data, addr, length))
226b725ae77Skettenis 	    return &s->d.data;
227b725ae77Skettenis 	  else
228b725ae77Skettenis 	    bcache->half_hash_miss_count++;
229b725ae77Skettenis 	}
230b725ae77Skettenis     }
231b725ae77Skettenis 
232b725ae77Skettenis   /* The user's string isn't in the list.  Insert it after *ps.  */
233b725ae77Skettenis   {
234b725ae77Skettenis     struct bstring *new
235b725ae77Skettenis       = obstack_alloc (&bcache->cache, BSTRING_SIZE (length));
236b725ae77Skettenis     memcpy (&new->d.data, addr, length);
237b725ae77Skettenis     new->length = length;
238b725ae77Skettenis     new->next = bcache->bucket[hash_index];
239b725ae77Skettenis     new->half_hash = half_hash;
240b725ae77Skettenis     bcache->bucket[hash_index] = new;
241b725ae77Skettenis 
242b725ae77Skettenis     bcache->unique_count++;
243b725ae77Skettenis     bcache->unique_size += length;
244b725ae77Skettenis     bcache->structure_size += BSTRING_SIZE (length);
245b725ae77Skettenis 
246b725ae77Skettenis     return &new->d.data;
247b725ae77Skettenis   }
248e93f7393Sniklas }
249e93f7393Sniklas 
250e93f7393Sniklas void *
deprecated_bcache(const void * addr,int length,struct bcache * bcache)251b725ae77Skettenis deprecated_bcache (const void *addr, int length, struct bcache *bcache)
252e93f7393Sniklas {
253b725ae77Skettenis   return bcache_data (addr, length, bcache);
254e93f7393Sniklas }
255e93f7393Sniklas 
256b725ae77Skettenis const void *
bcache(const void * addr,int length,struct bcache * bcache)257b725ae77Skettenis bcache (const void *addr, int length, struct bcache *bcache)
258b725ae77Skettenis {
259b725ae77Skettenis   return bcache_data (addr, length, bcache);
260b725ae77Skettenis }
261b725ae77Skettenis 
262b725ae77Skettenis /* Allocating and freeing bcaches.  */
263e93f7393Sniklas 
264b725ae77Skettenis struct bcache *
bcache_xmalloc(void)265b725ae77Skettenis bcache_xmalloc (void)
266b725ae77Skettenis {
267b725ae77Skettenis   /* Allocate the bcache pre-zeroed.  */
268b725ae77Skettenis   struct bcache *b = XCALLOC (1, struct bcache);
269b725ae77Skettenis   /* We could use obstack_specify_allocation here instead, but
270b725ae77Skettenis      gdb_obstack.h specifies the allocation/deallocation
271b725ae77Skettenis      functions.  */
272b725ae77Skettenis   obstack_init (&b->cache);
273b725ae77Skettenis   return b;
274b725ae77Skettenis }
275b725ae77Skettenis 
276b725ae77Skettenis /* Free all the storage associated with BCACHE.  */
277e93f7393Sniklas void
bcache_xfree(struct bcache * bcache)278b725ae77Skettenis bcache_xfree (struct bcache *bcache)
279e93f7393Sniklas {
280b725ae77Skettenis   if (bcache == NULL)
281b725ae77Skettenis     return;
282b725ae77Skettenis   obstack_free (&bcache->cache, 0);
283b725ae77Skettenis   xfree (bcache->bucket);
284b725ae77Skettenis   xfree (bcache);
285e93f7393Sniklas }
286e93f7393Sniklas 
287b725ae77Skettenis 
288b725ae77Skettenis 
289b725ae77Skettenis /* Printing statistics.  */
290b725ae77Skettenis 
291b725ae77Skettenis static int
compare_ints(const void * ap,const void * bp)292b725ae77Skettenis compare_ints (const void *ap, const void *bp)
293b725ae77Skettenis {
294b725ae77Skettenis   /* Because we know we're comparing two ints which are positive,
295b725ae77Skettenis      there's no danger of overflow here.  */
296b725ae77Skettenis   return * (int *) ap - * (int *) bp;
297b725ae77Skettenis }
298b725ae77Skettenis 
299b725ae77Skettenis 
300b725ae77Skettenis static void
print_percentage(int portion,int total)301b725ae77Skettenis print_percentage (int portion, int total)
302b725ae77Skettenis {
303b725ae77Skettenis   if (total == 0)
304b725ae77Skettenis     printf_filtered ("(not applicable)\n");
305b725ae77Skettenis   else
306*63addd46Skettenis     printf_filtered ("%3d%%\n", (int) (portion * 100.0 / total));
307b725ae77Skettenis }
308b725ae77Skettenis 
309b725ae77Skettenis 
310b725ae77Skettenis /* Print statistics on BCACHE's memory usage and efficacity at
311b725ae77Skettenis    eliminating duplication.  NAME should describe the kind of data
312b725ae77Skettenis    BCACHE holds.  Statistics are printed using `printf_filtered' and
313b725ae77Skettenis    its ilk.  */
314b725ae77Skettenis void
print_bcache_statistics(struct bcache * c,char * type)315b725ae77Skettenis print_bcache_statistics (struct bcache *c, char *type)
316b725ae77Skettenis {
317b725ae77Skettenis   int occupied_buckets;
318b725ae77Skettenis   int max_chain_length;
319b725ae77Skettenis   int median_chain_length;
320b725ae77Skettenis   int max_entry_size;
321b725ae77Skettenis   int median_entry_size;
322b725ae77Skettenis 
323b725ae77Skettenis   /* Count the number of occupied buckets, tally the various string
324b725ae77Skettenis      lengths, and measure chain lengths.  */
325b725ae77Skettenis   {
326b725ae77Skettenis     unsigned int b;
327b725ae77Skettenis     int *chain_length = XCALLOC (c->num_buckets + 1, int);
328b725ae77Skettenis     int *entry_size = XCALLOC (c->unique_count + 1, int);
329b725ae77Skettenis     int stringi = 0;
330b725ae77Skettenis 
331b725ae77Skettenis     occupied_buckets = 0;
332b725ae77Skettenis 
333b725ae77Skettenis     for (b = 0; b < c->num_buckets; b++)
334b725ae77Skettenis       {
335b725ae77Skettenis 	struct bstring *s = c->bucket[b];
336b725ae77Skettenis 
337b725ae77Skettenis 	chain_length[b] = 0;
338b725ae77Skettenis 
339b725ae77Skettenis 	if (s)
340b725ae77Skettenis 	  {
341b725ae77Skettenis 	    occupied_buckets++;
342b725ae77Skettenis 
343b725ae77Skettenis 	    while (s)
344b725ae77Skettenis 	      {
345b725ae77Skettenis 		gdb_assert (b < c->num_buckets);
346b725ae77Skettenis 		chain_length[b]++;
347b725ae77Skettenis 		gdb_assert (stringi < c->unique_count);
348b725ae77Skettenis 		entry_size[stringi++] = s->length;
349b725ae77Skettenis 		s = s->next;
350b725ae77Skettenis 	      }
351b725ae77Skettenis 	  }
352b725ae77Skettenis       }
353b725ae77Skettenis 
354b725ae77Skettenis     /* To compute the median, we need the set of chain lengths sorted.  */
355b725ae77Skettenis     qsort (chain_length, c->num_buckets, sizeof (chain_length[0]),
356b725ae77Skettenis 	   compare_ints);
357b725ae77Skettenis     qsort (entry_size, c->unique_count, sizeof (entry_size[0]),
358b725ae77Skettenis 	   compare_ints);
359b725ae77Skettenis 
360b725ae77Skettenis     if (c->num_buckets > 0)
361b725ae77Skettenis       {
362b725ae77Skettenis 	max_chain_length = chain_length[c->num_buckets - 1];
363b725ae77Skettenis 	median_chain_length = chain_length[c->num_buckets / 2];
364b725ae77Skettenis       }
365b725ae77Skettenis     else
366b725ae77Skettenis       {
367b725ae77Skettenis 	max_chain_length = 0;
368b725ae77Skettenis 	median_chain_length = 0;
369b725ae77Skettenis       }
370b725ae77Skettenis     if (c->unique_count > 0)
371b725ae77Skettenis       {
372b725ae77Skettenis 	max_entry_size = entry_size[c->unique_count - 1];
373b725ae77Skettenis 	median_entry_size = entry_size[c->unique_count / 2];
374b725ae77Skettenis       }
375b725ae77Skettenis     else
376b725ae77Skettenis       {
377b725ae77Skettenis 	max_entry_size = 0;
378b725ae77Skettenis 	median_entry_size = 0;
379b725ae77Skettenis       }
380b725ae77Skettenis 
381b725ae77Skettenis     xfree (chain_length);
382b725ae77Skettenis     xfree (entry_size);
383b725ae77Skettenis   }
384b725ae77Skettenis 
385b725ae77Skettenis   printf_filtered ("  Cached '%s' statistics:\n", type);
386b725ae77Skettenis   printf_filtered ("    Total object count:  %ld\n", c->total_count);
387b725ae77Skettenis   printf_filtered ("    Unique object count: %lu\n", c->unique_count);
388b725ae77Skettenis   printf_filtered ("    Percentage of duplicates, by count: ");
389b725ae77Skettenis   print_percentage (c->total_count - c->unique_count, c->total_count);
390b725ae77Skettenis   printf_filtered ("\n");
391b725ae77Skettenis 
392b725ae77Skettenis   printf_filtered ("    Total object size:   %ld\n", c->total_size);
393b725ae77Skettenis   printf_filtered ("    Unique object size:  %ld\n", c->unique_size);
394b725ae77Skettenis   printf_filtered ("    Percentage of duplicates, by size:  ");
395b725ae77Skettenis   print_percentage (c->total_size - c->unique_size, c->total_size);
396b725ae77Skettenis   printf_filtered ("\n");
397b725ae77Skettenis 
398b725ae77Skettenis   printf_filtered ("    Max entry size:     %d\n", max_entry_size);
399b725ae77Skettenis   printf_filtered ("    Average entry size: ");
400b725ae77Skettenis   if (c->unique_count > 0)
401b725ae77Skettenis     printf_filtered ("%ld\n", c->unique_size / c->unique_count);
402b725ae77Skettenis   else
403b725ae77Skettenis     printf_filtered ("(not applicable)\n");
404b725ae77Skettenis   printf_filtered ("    Median entry size:  %d\n", median_entry_size);
405b725ae77Skettenis   printf_filtered ("\n");
406b725ae77Skettenis 
407b725ae77Skettenis   printf_filtered ("    Total memory used by bcache, including overhead: %ld\n",
408b725ae77Skettenis 		   c->structure_size);
409b725ae77Skettenis   printf_filtered ("    Percentage memory overhead: ");
410b725ae77Skettenis   print_percentage (c->structure_size - c->unique_size, c->unique_size);
411b725ae77Skettenis   printf_filtered ("    Net memory savings:         ");
412b725ae77Skettenis   print_percentage (c->total_size - c->structure_size, c->total_size);
413b725ae77Skettenis   printf_filtered ("\n");
414b725ae77Skettenis 
415b725ae77Skettenis   printf_filtered ("    Hash table size:           %3d\n", c->num_buckets);
416b725ae77Skettenis   printf_filtered ("    Hash table expands:        %lu\n",
417b725ae77Skettenis 		   c->expand_count);
418b725ae77Skettenis   printf_filtered ("    Hash table hashes:         %lu\n",
419b725ae77Skettenis 		   c->total_count + c->expand_hash_count);
420b725ae77Skettenis   printf_filtered ("    Half hash misses:          %lu\n",
421b725ae77Skettenis 		   c->half_hash_miss_count);
422b725ae77Skettenis   printf_filtered ("    Hash table population:     ");
423b725ae77Skettenis   print_percentage (occupied_buckets, c->num_buckets);
424b725ae77Skettenis   printf_filtered ("    Median hash chain length:  %3d\n",
425b725ae77Skettenis 		   median_chain_length);
426b725ae77Skettenis   printf_filtered ("    Average hash chain length: ");
427b725ae77Skettenis   if (c->num_buckets > 0)
428b725ae77Skettenis     printf_filtered ("%3lu\n", c->unique_count / c->num_buckets);
429b725ae77Skettenis   else
430b725ae77Skettenis     printf_filtered ("(not applicable)\n");
431b725ae77Skettenis   printf_filtered ("    Maximum hash chain length: %3d\n", max_chain_length);
432b725ae77Skettenis   printf_filtered ("\n");
433b725ae77Skettenis }
434b725ae77Skettenis 
435b725ae77Skettenis int
bcache_memory_used(struct bcache * bcache)436b725ae77Skettenis bcache_memory_used (struct bcache *bcache)
437b725ae77Skettenis {
438b725ae77Skettenis   return obstack_memory_used (&bcache->cache);
439b725ae77Skettenis }
440