OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [gnu-src/] [gdb-6.8/] [gdb/] [bcache.c] - Blame information for rev 321

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.