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