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