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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [gdb-5.0/] [gdb/] [bcache.c] - Diff between revs 105 and 1765

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 105 Rev 1765
/* Implement a cached obstack.
/* Implement a cached obstack.
   Written by Fred Fish <fnf@cygnus.com>
   Written by Fred Fish <fnf@cygnus.com>
   Rewritten by Jim Blandy <jimb@cygnus.com>
   Rewritten by Jim Blandy <jimb@cygnus.com>
   Copyright 1999 Free Software Foundation, Inc.
   Copyright 1999 Free Software Foundation, Inc.
 
 
   This file is part of GDB.
   This file is part of GDB.
 
 
   This program is free software; you can redistribute it and/or modify
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
   (at your option) any later version.
 
 
   This program is distributed in the hope that it will be useful,
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   GNU General Public License for more details.
 
 
   You should have received a copy of the GNU General Public License
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330,
   Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.  */
   Boston, MA 02111-1307, USA.  */
 
 
#include <stddef.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdlib.h>
 
 
#include "defs.h"
#include "defs.h"
#include "obstack.h"
#include "obstack.h"
#include "bcache.h"
#include "bcache.h"
#include "gdb_string.h"         /* For memcpy declaration */
#include "gdb_string.h"         /* For memcpy declaration */
 
 
 
 


/* The hash function.  */
/* The hash function.  */
 
 
unsigned long
unsigned long
hash (void *addr, int length)
hash (void *addr, int length)
{
{
  /* If it's a short string, hash on every character.  Otherwise, sample
  /* If it's a short string, hash on every character.  Otherwise, sample
     characters from throughout the string.  */
     characters from throughout the string.  */
  if (length <= 64)
  if (length <= 64)
    {
    {
      char *byte = addr;
      char *byte = addr;
      unsigned long h = 0;
      unsigned long h = 0;
      int i;
      int i;
 
 
      for (i = 0; i < length; i++)
      for (i = 0; i < length; i++)
        h = h * 65793 ^ (h >> (sizeof (h) * 8 - 6)) ^ byte[i];
        h = h * 65793 ^ (h >> (sizeof (h) * 8 - 6)) ^ byte[i];
 
 
      return h;
      return h;
    }
    }
  else
  else
    {
    {
      char *byte = addr;
      char *byte = addr;
      int n, i;
      int n, i;
      unsigned long h = 0;
      unsigned long h = 0;
 
 
      for (n = i = 0; n < 64; n++)
      for (n = i = 0; n < 64; n++)
        {
        {
          h = h * 65793 + (h >> (sizeof (h) * 8 - 6)) + byte[i];
          h = h * 65793 + (h >> (sizeof (h) * 8 - 6)) + byte[i];
          i = h % length;
          i = h % length;
        }
        }
 
 
      return h;
      return h;
    }
    }
}
}
 
 


/* Growing the bcache's hash table.  */
/* Growing the bcache's hash table.  */
 
 
/* If the average chain length grows beyond this, then we want to
/* If the average chain length grows beyond this, then we want to
   resize our hash table.  */
   resize our hash table.  */
#define CHAIN_LENGTH_THRESHOLD (5)
#define CHAIN_LENGTH_THRESHOLD (5)
 
 
static void
static void
expand_hash_table (struct bcache *bcache)
expand_hash_table (struct bcache *bcache)
{
{
  /* A table of good hash table sizes.  Whenever we grow, we pick the
  /* A table of good hash table sizes.  Whenever we grow, we pick the
     next larger size from this table.  sizes[i] is close to 1 << (i+10),
     next larger size from this table.  sizes[i] is close to 1 << (i+10),
     so we roughly double the table size each time.  After we fall off
     so we roughly double the table size each time.  After we fall off
     the end of this table, we just double.  Don't laugh --- there have
     the end of this table, we just double.  Don't laugh --- there have
     been executables sighted with a gigabyte of debug info.  */
     been executables sighted with a gigabyte of debug info.  */
  static unsigned long sizes[] = {
  static unsigned long sizes[] = {
    1021, 2053, 4099, 8191, 16381, 32771,
    1021, 2053, 4099, 8191, 16381, 32771,
    65537, 131071, 262144, 524287, 1048573, 2097143,
    65537, 131071, 262144, 524287, 1048573, 2097143,
    4194301, 8388617, 16777213, 33554467, 67108859, 134217757,
    4194301, 8388617, 16777213, 33554467, 67108859, 134217757,
    268435459, 536870923, 1073741827, 2147483659UL
    268435459, 536870923, 1073741827, 2147483659UL
  };
  };
  unsigned int new_num_buckets;
  unsigned int new_num_buckets;
  struct bstring **new_buckets;
  struct bstring **new_buckets;
  unsigned int i;
  unsigned int i;
 
 
  /* Find the next size.  */
  /* Find the next size.  */
  new_num_buckets = bcache->num_buckets * 2;
  new_num_buckets = bcache->num_buckets * 2;
  for (i = 0; i < (sizeof (sizes) / sizeof (sizes[0])); i++)
  for (i = 0; i < (sizeof (sizes) / sizeof (sizes[0])); i++)
    if (sizes[i] > bcache->num_buckets)
    if (sizes[i] > bcache->num_buckets)
      {
      {
        new_num_buckets = sizes[i];
        new_num_buckets = sizes[i];
        break;
        break;
      }
      }
 
 
  /* Allocate the new table.  */
  /* Allocate the new table.  */
  {
  {
    size_t new_size = new_num_buckets * sizeof (new_buckets[0]);
    size_t new_size = new_num_buckets * sizeof (new_buckets[0]);
    new_buckets = (struct bstring **) xmalloc (new_size);
    new_buckets = (struct bstring **) xmalloc (new_size);
    memset (new_buckets, 0, new_size);
    memset (new_buckets, 0, new_size);
 
 
    bcache->structure_size -= (bcache->num_buckets
    bcache->structure_size -= (bcache->num_buckets
                               * sizeof (bcache->bucket[0]));
                               * sizeof (bcache->bucket[0]));
    bcache->structure_size += new_size;
    bcache->structure_size += new_size;
  }
  }
 
 
  /* Rehash all existing strings.  */
  /* Rehash all existing strings.  */
  for (i = 0; i < bcache->num_buckets; i++)
  for (i = 0; i < bcache->num_buckets; i++)
    {
    {
      struct bstring *s, *next;
      struct bstring *s, *next;
 
 
      for (s = bcache->bucket[i]; s; s = next)
      for (s = bcache->bucket[i]; s; s = next)
        {
        {
          struct bstring **new_bucket;
          struct bstring **new_bucket;
          next = s->next;
          next = s->next;
 
 
          new_bucket = &new_buckets[(hash (&s->d.data, s->length)
          new_bucket = &new_buckets[(hash (&s->d.data, s->length)
                                     % new_num_buckets)];
                                     % new_num_buckets)];
          s->next = *new_bucket;
          s->next = *new_bucket;
          *new_bucket = s;
          *new_bucket = s;
        }
        }
    }
    }
 
 
  /* Plug in the new table.  */
  /* Plug in the new table.  */
  if (bcache->bucket)
  if (bcache->bucket)
    free (bcache->bucket);
    free (bcache->bucket);
  bcache->bucket = new_buckets;
  bcache->bucket = new_buckets;
  bcache->num_buckets = new_num_buckets;
  bcache->num_buckets = new_num_buckets;
}
}
 
 


/* Looking up things in the bcache.  */
/* Looking up things in the bcache.  */
 
 
/* The number of bytes needed to allocate a struct bstring whose data
/* The number of bytes needed to allocate a struct bstring whose data
   is N bytes long.  */
   is N bytes long.  */
#define BSTRING_SIZE(n) (offsetof (struct bstring, d.data) + (n))
#define BSTRING_SIZE(n) (offsetof (struct bstring, d.data) + (n))
 
 
/* Find a copy of the LENGTH bytes at ADDR in BCACHE.  If BCACHE has
/* Find a copy of the LENGTH bytes at ADDR in BCACHE.  If BCACHE has
   never seen those bytes before, add a copy of them to BCACHE.  In
   never seen those bytes before, add a copy of them to BCACHE.  In
   either case, return a pointer to BCACHE's copy of that string.  */
   either case, return a pointer to BCACHE's copy of that string.  */
void *
void *
bcache (void *addr, int length, struct bcache *bcache)
bcache (void *addr, int length, struct bcache *bcache)
{
{
  int hash_index;
  int hash_index;
  struct bstring *s;
  struct bstring *s;
 
 
  /* If our average chain length is too high, expand the hash table.  */
  /* If our average chain length is too high, expand the hash table.  */
  if (bcache->unique_count >= bcache->num_buckets * CHAIN_LENGTH_THRESHOLD)
  if (bcache->unique_count >= bcache->num_buckets * CHAIN_LENGTH_THRESHOLD)
    expand_hash_table (bcache);
    expand_hash_table (bcache);
 
 
  bcache->total_count++;
  bcache->total_count++;
  bcache->total_size += length;
  bcache->total_size += length;
 
 
  hash_index = hash (addr, length) % bcache->num_buckets;
  hash_index = hash (addr, length) % bcache->num_buckets;
 
 
  /* Search the hash bucket for a string identical to the caller's.  */
  /* Search the hash bucket for a string identical to the caller's.  */
  for (s = bcache->bucket[hash_index]; s; s = s->next)
  for (s = bcache->bucket[hash_index]; s; s = s->next)
    if (s->length == length
    if (s->length == length
        && ! memcmp (&s->d.data, addr, length))
        && ! memcmp (&s->d.data, addr, length))
      return &s->d.data;
      return &s->d.data;
 
 
  /* The user's string isn't in the list.  Insert it after *ps.  */
  /* The user's string isn't in the list.  Insert it after *ps.  */
  {
  {
    struct bstring *new
    struct bstring *new
      = obstack_alloc (&bcache->cache, BSTRING_SIZE (length));
      = obstack_alloc (&bcache->cache, BSTRING_SIZE (length));
    memcpy (&new->d.data, addr, length);
    memcpy (&new->d.data, addr, length);
    new->length = length;
    new->length = length;
    new->next = bcache->bucket[hash_index];
    new->next = bcache->bucket[hash_index];
    bcache->bucket[hash_index] = new;
    bcache->bucket[hash_index] = new;
 
 
    bcache->unique_count++;
    bcache->unique_count++;
    bcache->unique_size += length;
    bcache->unique_size += length;
    bcache->structure_size += BSTRING_SIZE (length);
    bcache->structure_size += BSTRING_SIZE (length);
 
 
    return &new->d.data;
    return &new->d.data;
  }
  }
}
}
 
 


/* Freeing bcaches.  */
/* Freeing bcaches.  */
 
 
/* Free all the storage associated with BCACHE.  */
/* Free all the storage associated with BCACHE.  */
void
void
free_bcache (struct bcache *bcache)
free_bcache (struct bcache *bcache)
{
{
  obstack_free (&bcache->cache, 0);
  obstack_free (&bcache->cache, 0);
  if (bcache->bucket)
  if (bcache->bucket)
    free (bcache->bucket);
    free (bcache->bucket);
 
 
  /* This isn't necessary, but at least the bcache is always in a
  /* This isn't necessary, but at least the bcache is always in a
     consistent state.  */
     consistent state.  */
  memset (bcache, 0, sizeof (*bcache));
  memset (bcache, 0, sizeof (*bcache));
}
}
 
 
 
 


/* Printing statistics.  */
/* Printing statistics.  */
 
 
static int
static int
compare_ints (const void *ap, const void *bp)
compare_ints (const void *ap, const void *bp)
{
{
  /* Because we know we're comparing two ints which are positive,
  /* Because we know we're comparing two ints which are positive,
     there's no danger of overflow here.  */
     there's no danger of overflow here.  */
  return * (int *) ap - * (int *) bp;
  return * (int *) ap - * (int *) bp;
}
}
 
 
 
 
static void
static void
print_percentage (int portion, int total)
print_percentage (int portion, int total)
{
{
  if (total == 0)
  if (total == 0)
    printf_filtered ("(not applicable)\n");
    printf_filtered ("(not applicable)\n");
  else
  else
    printf_filtered ("%3d%%\n", portion * 100 / total);
    printf_filtered ("%3d%%\n", portion * 100 / total);
}
}
 
 
 
 
/* Print statistics on BCACHE's memory usage and efficacity at
/* Print statistics on BCACHE's memory usage and efficacity at
   eliminating duplication.  NAME should describe the kind of data
   eliminating duplication.  NAME should describe the kind of data
   BCACHE holds.  Statistics are printed using `printf_filtered' and
   BCACHE holds.  Statistics are printed using `printf_filtered' and
   its ilk.  */
   its ilk.  */
void
void
print_bcache_statistics (struct bcache *c, char *type)
print_bcache_statistics (struct bcache *c, char *type)
{
{
  int occupied_buckets;
  int occupied_buckets;
  int max_chain_length;
  int max_chain_length;
  int median_chain_length;
  int median_chain_length;
 
 
  /* Count the number of occupied buckets, and measure chain lengths.  */
  /* Count the number of occupied buckets, and measure chain lengths.  */
  {
  {
    unsigned int b;
    unsigned int b;
    int *chain_length
    int *chain_length
      = (int *) alloca (c->num_buckets * sizeof (*chain_length));
      = (int *) alloca (c->num_buckets * sizeof (*chain_length));
 
 
    occupied_buckets = 0;
    occupied_buckets = 0;
 
 
    for (b = 0; b < c->num_buckets; b++)
    for (b = 0; b < c->num_buckets; b++)
      {
      {
        struct bstring *s = c->bucket[b];
        struct bstring *s = c->bucket[b];
 
 
        chain_length[b] = 0;
        chain_length[b] = 0;
 
 
        if (s)
        if (s)
          {
          {
            occupied_buckets++;
            occupied_buckets++;
 
 
            while (s)
            while (s)
              {
              {
                chain_length[b]++;
                chain_length[b]++;
                s = s->next;
                s = s->next;
              }
              }
          }
          }
      }
      }
 
 
    /* To compute the median, we need the set of chain lengths sorted.  */
    /* To compute the median, we need the set of chain lengths sorted.  */
    qsort (chain_length, c->num_buckets, sizeof (chain_length[0]),
    qsort (chain_length, c->num_buckets, sizeof (chain_length[0]),
           compare_ints);
           compare_ints);
 
 
    if (c->num_buckets > 0)
    if (c->num_buckets > 0)
      {
      {
        max_chain_length = chain_length[c->num_buckets - 1];
        max_chain_length = chain_length[c->num_buckets - 1];
        median_chain_length = chain_length[c->num_buckets / 2];
        median_chain_length = chain_length[c->num_buckets / 2];
      }
      }
    else
    else
      {
      {
        max_chain_length = 0;
        max_chain_length = 0;
        median_chain_length = 0;
        median_chain_length = 0;
      }
      }
  }
  }
 
 
  printf_filtered ("  Cached '%s' statistics:\n", type);
  printf_filtered ("  Cached '%s' statistics:\n", type);
  printf_filtered ("    Total object count:  %ld\n", c->total_count);
  printf_filtered ("    Total object count:  %ld\n", c->total_count);
  printf_filtered ("    Unique object count: %lu\n", c->unique_count);
  printf_filtered ("    Unique object count: %lu\n", c->unique_count);
  printf_filtered ("    Percentage of duplicates, by count: ");
  printf_filtered ("    Percentage of duplicates, by count: ");
  print_percentage (c->total_count - c->unique_count, c->total_count);
  print_percentage (c->total_count - c->unique_count, c->total_count);
  printf_filtered ("\n");
  printf_filtered ("\n");
 
 
  printf_filtered ("    Total object size:   %ld\n", c->total_size);
  printf_filtered ("    Total object size:   %ld\n", c->total_size);
  printf_filtered ("    Unique object size:  %ld\n", c->unique_size);
  printf_filtered ("    Unique object size:  %ld\n", c->unique_size);
  printf_filtered ("    Percentage of duplicates, by size:  ");
  printf_filtered ("    Percentage of duplicates, by size:  ");
  print_percentage (c->total_size - c->unique_size, c->total_size);
  print_percentage (c->total_size - c->unique_size, c->total_size);
  printf_filtered ("\n");
  printf_filtered ("\n");
 
 
  printf_filtered ("    Total memory used by bcache, including overhead: %ld\n",
  printf_filtered ("    Total memory used by bcache, including overhead: %ld\n",
                   c->structure_size);
                   c->structure_size);
  printf_filtered ("    Percentage memory overhead: ");
  printf_filtered ("    Percentage memory overhead: ");
  print_percentage (c->structure_size - c->unique_size, c->unique_size);
  print_percentage (c->structure_size - c->unique_size, c->unique_size);
  printf_filtered ("    Net memory savings:         ");
  printf_filtered ("    Net memory savings:         ");
  print_percentage (c->total_size - c->structure_size, c->total_size);
  print_percentage (c->total_size - c->structure_size, c->total_size);
  printf_filtered ("\n");
  printf_filtered ("\n");
 
 
  printf_filtered ("    Hash table size:           %3d\n", c->num_buckets);
  printf_filtered ("    Hash table size:           %3d\n", c->num_buckets);
  printf_filtered ("    Hash table population:     ");
  printf_filtered ("    Hash table population:     ");
  print_percentage (occupied_buckets, c->num_buckets);
  print_percentage (occupied_buckets, c->num_buckets);
  printf_filtered ("    Median hash chain length:  %3d\n",
  printf_filtered ("    Median hash chain length:  %3d\n",
                   median_chain_length);
                   median_chain_length);
  printf_filtered ("    Average hash chain length: ");
  printf_filtered ("    Average hash chain length: ");
  if (c->num_buckets > 0)
  if (c->num_buckets > 0)
    printf_filtered ("%3lu\n", c->unique_count / c->num_buckets);
    printf_filtered ("%3lu\n", c->unique_count / c->num_buckets);
  else
  else
    printf_filtered ("(not applicable)\n");
    printf_filtered ("(not applicable)\n");
  printf_filtered ("    Maximum hash chain length: %3d\n", max_chain_length);
  printf_filtered ("    Maximum hash chain length: %3d\n", max_chain_length);
  printf_filtered ("\n");
  printf_filtered ("\n");
}
}
 
 

powered by: WebSVN 2.1.0

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