diff options
author | Akim Demaille <akim@epita.fr> | 2002-07-02 13:51:27 +0000 |
---|---|---|
committer | Akim Demaille <akim@epita.fr> | 2002-07-02 13:51:27 +0000 |
commit | 613f5e1a895b0742c9b6c5e9461e4cf3f7389d7e (patch) | |
tree | 0560faaca9522756393d5a9951d57b1face9a5de /lib/bitset_stats.c | |
parent | 524346a3a3088f7d28420fe711a7720980b88f48 (diff) | |
download | bison-613f5e1a895b0742c9b6c5e9461e4cf3f7389d7e.tar.gz |
* lib/libiberty.h: New.
* lib: Update the bitset implementation from upstream.
* src/closure.c, src/lalr.c, src/output.c, src/print_graph.c,
* src/state.c: Use BITSET_FOR_EACH, not BITSET_EXECUTE.
* src/main.c: Adjust bitset stats calls.
Diffstat (limited to 'lib/bitset_stats.c')
-rw-r--r-- | lib/bitset_stats.c | 627 |
1 files changed, 627 insertions, 0 deletions
diff --git a/lib/bitset_stats.c b/lib/bitset_stats.c new file mode 100644 index 00000000..47dec487 --- /dev/null +++ b/lib/bitset_stats.c @@ -0,0 +1,627 @@ +/* Bitset statistics. + Copyright (C) 2002 Free Software Foundation, Inc. + Contributed by Michael Hayes (m.hayes@elec.canterbury.ac.nz). + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/* This file is a wrapper bitset implementation for the other bitset + implementations. It provides bitset compatibility checking and + statistics gathering without having to instrument the bitset + implementations. When statistics gathering is enabled, the bitset + operations get vectored through here and we then call the appropriate + routines. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "bbitset.h" +#include "abitset.h" +#include "ebitset.h" +#include "lbitset.h" +#include "bitset_stats.h" +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + + +/* Configuration macros. */ +#define BITSET_STATS_FILE "bitset.dat" +#define BITSET_LOG_COUNT_BINS 10 +#define BITSET_LOG_SIZE_BINS 16 +#define BITSET_DENSITY_BINS 20 + + +/* Accessor macros. */ +#define BITSET_STATS_ALLOCS_INC(TYPE) \ + bitset_stats_info->types[(TYPE)].allocs++ +#define BITSET_STATS_FREES_INC(BSET) \ + bitset_stats_info->types[BITSET_TYPE_ (BSET)].frees++ +#define BITSET_STATS_SETS_INC(BSET) \ + bitset_stats_info->types[BITSET_TYPE_ (BSET)].sets++ +#define BITSET_STATS_CACHE_SETS_INC(BSET) \ + bitset_stats_info->types[BITSET_TYPE_ (BSET)].cache_sets++ +#define BITSET_STATS_RESETS_INC(BSET) \ + bitset_stats_info->types[BITSET_TYPE_ (BSET)].resets++ +#define BITSET_STATS_CACHE_RESETS_INC(BSET) \ + bitset_stats_info->types[BITSET_TYPE_ (BSET)].cache_resets++ +#define BITSET_STATS_TESTS_INC(BSET) \ + bitset_stats_info->types[BITSET_TYPE_ (BSET)].tests++ +#define BITSET_STATS_CACHE_TESTS_INC(BSET) \ + bitset_stats_info->types[BITSET_TYPE_ (BSET)].cache_tests++ +#define BITSET_STATS_LISTS_INC(BSET) \ + bitset_stats_info->types[BITSET_TYPE_ (BSET)].lists++ +#define BITSET_STATS_LIST_COUNTS_INC(BSET, I) \ + bitset_stats_info->types[BITSET_TYPE_ (BSET)].list_counts[(I)]++ +#define BITSET_STATS_LIST_SIZES_INC(BSET, I) \ + bitset_stats_info->types[BITSET_TYPE_ (BSET)].list_sizes[(I)]++ +#define BITSET_STATS_LIST_DENSITY_INC(BSET, I) \ + bitset_stats_info->types[BITSET_TYPE_ (BSET)].list_density[(I)]++ + + +typedef struct bitset_stats_struct +{ + bitset bset; +} *bitset_stats; + + +struct bitset_struct +{ + struct bbitset_struct b; + struct bitset_stats_struct s; +}; + + +struct bitset_type_info_struct +{ + unsigned int allocs; + unsigned int frees; + unsigned int lists; + unsigned int sets; + unsigned int cache_sets; + unsigned int resets; + unsigned int cache_resets; + unsigned int tests; + unsigned int cache_tests; + unsigned int list_counts[BITSET_LOG_COUNT_BINS]; + unsigned int list_sizes[BITSET_LOG_SIZE_BINS]; + unsigned int list_density[BITSET_DENSITY_BINS]; +}; + +struct bitset_stats_info_struct +{ + unsigned int runs; + struct bitset_type_info_struct types[BITSET_TYPE_NUM]; +}; + + +struct bitset_stats_info_struct bitset_stats_info_data; +struct bitset_stats_info_struct *bitset_stats_info; +int bitset_stats_enabled = 0; + + +static void bitset_stats_set PARAMS ((bitset, bitset_bindex)); +static void bitset_stats_reset PARAMS ((bitset, bitset_bindex)); +static int bitset_stats_test PARAMS ((bitset, bitset_bindex)); +static int bitset_stats_size PARAMS ((bitset)); +static int bitset_stats_op1 PARAMS ((bitset, enum bitset_ops)); +static int bitset_stats_op2 PARAMS ((bitset, bitset, enum bitset_ops)); +static int bitset_stats_op3 PARAMS ((bitset, bitset, bitset, enum bitset_ops)); +static int bitset_stats_op4 PARAMS ((bitset, bitset, bitset, bitset, + enum bitset_ops)); +static int bitset_stats_list PARAMS ((bitset, bitset_bindex *, bitset_bindex, + bitset_bindex *)); +static int bitset_stats_reverse_list +PARAMS ((bitset, bitset_bindex *, bitset_bindex, bitset_bindex *)); +static void bitset_stats_free PARAMS ((bitset)); +static void bitset_percent_histogram_print PARAMS ((FILE *, const char *, + const char *, + unsigned int, + unsigned int *)); +static void bitset_log_histogram_print PARAMS ((FILE *, const char *, + const char *, + unsigned int, + unsigned int *)); +static void bitset_stats_print_1 +PARAMS ((FILE *, const char *, struct bitset_type_info_struct *)); +static void bitset_stats_print PARAMS ((FILE *, int)); + + +/* Print a percentage histogram with message MSG to FILE. */ +static void +bitset_percent_histogram_print (file, name, msg, n_bins, bins) + FILE *file; + const char *name; + const char *msg; + unsigned int n_bins; + unsigned int *bins; +{ + unsigned int i; + unsigned int total; + + total = 0; + for (i = 0; i < n_bins; i++) + total += bins[i]; + + if (!total) + return; + + fprintf (file, "%s %s", name, msg); + for (i = 0; i < n_bins; i++) + fprintf (file, "%.0f-%.0f%%\t%8d (%5.1f%%)\n", + i * 100.0 / n_bins, + (i + 1) * 100.0 / n_bins, bins[i], + (100.0 * bins[i]) / total); +} + + +/* Print a log histogram with message MSG to FILE. */ +static void +bitset_log_histogram_print (file, name, msg, n_bins, bins) + FILE *file; + const char *name; + const char *msg; + unsigned int n_bins; + unsigned int *bins; +{ + unsigned int i; + unsigned int total; + unsigned int max_width; + unsigned int last_bin; + + total = 0; + for (i = 0; i < n_bins; i++) + total += bins[i]; + + if (!total) + return; + + for (i = n_bins; i > 3 && ! bins[i - 1]; i--) + continue; + last_bin = i - 1; + + /* 2 * ceil (log10 (2) * (N - 1)) + 1. */ + max_width = 2 * (unsigned int) (0.30103 * (n_bins - 1) + 0.9999) + 1; + + fprintf (file, "%s %s", name, msg); + for (i = 0; i < 2; i++) + fprintf (file, "%*d\t%8d (%5.1f%%)\n", + max_width, i, bins[i], 100.0 * bins[i] / total); + + for (; i <= last_bin; i++) + fprintf (file, "%*d-%d\t%8d (%5.1f%%)\n", + max_width - ((unsigned int) (0.30103 * (i) + 0.9999) + 1), + 1 << (i - 1), (1 << i) - 1, bins[i], + (100.0 * bins[i]) / total); +} + + +/* Print bitset statistics to FILE. */ +static void +bitset_stats_print_1 (file, name, stats) + FILE *file; + const char *name; + struct bitset_type_info_struct *stats; +{ + if (!stats) + return; + + fprintf (file, "%s:\n", name); + fprintf (file, "%d bitset_allocs, %d freed (%.2f%%).\n", + stats->allocs, stats->frees, + stats->allocs ? 100.0 * stats->frees / stats->allocs : 0); + fprintf (file, "%d bitset_sets, %d cached (%.2f%%)\n", + stats->sets, stats->cache_sets, + stats->sets ? 100.0 * stats->cache_sets / stats->sets : 0); + fprintf (file, "%d bitset_resets, %d cached (%.2f%%)\n", + stats->resets, stats->cache_resets, + stats->resets ? 100.0 * stats->cache_resets / stats->resets : 0); + fprintf (file, "%d bitset_tests, %d cached (%.2f%%)\n", + stats->tests, stats->cache_tests, + stats->tests ? 100.0 * stats->cache_tests / stats->tests : 0); + + fprintf (file, "%d bitset_lists\n", stats->lists); + + bitset_log_histogram_print (file, name, "count log histogram\n", + BITSET_LOG_COUNT_BINS, stats->list_counts); + + bitset_log_histogram_print (file, name, "size log histogram\n", + BITSET_LOG_SIZE_BINS, stats->list_sizes); + + bitset_percent_histogram_print (file, name, "density histogram\n", + BITSET_DENSITY_BINS, stats->list_density); +} + + +/* Print all bitset statistics to FILE. */ +static void +bitset_stats_print (file, verbose) + FILE *file; + int verbose ATTRIBUTE_UNUSED; +{ + int i; + static const char *names[] = BITSET_TYPE_NAMES; + + if (!bitset_stats_info) + return; + + fprintf (file, "Bitset statistics:\n\n"); + + if (bitset_stats_info->runs > 1) + fprintf (file, "Accumulated runs = %d\n", bitset_stats_info->runs); + + for (i = 0; i < BITSET_TYPE_NUM; i++) + bitset_stats_print_1 (file, names[i], &bitset_stats_info->types[i]); +} + + +/* Initialise bitset statistics logging. */ +void +bitset_stats_enable () +{ + if (!bitset_stats_info) + bitset_stats_info = &bitset_stats_info_data; + bitset_stats_enabled = 1; +} + + +void +bitset_stats_disable () +{ + bitset_stats_enabled = 0; +} + + +/* Read bitset statistics file. */ +void +bitset_stats_read (filename) + const char *filename; +{ + FILE *file; + + if (!bitset_stats_info) + return; + + if (!filename) + filename = BITSET_STATS_FILE; + + file = fopen (filename, "r"); + if (file) + { + if (fread (&bitset_stats_info_data, sizeof (bitset_stats_info_data), + 1, file) != 1) + { + if (ferror (file)) + perror ("Could not read stats file."); + else + fprintf (stderr, "Bad stats file size.\n"); + } + fclose (file); + } + bitset_stats_info_data.runs++; +} + + +/* Write bitset statistics file. */ +void +bitset_stats_write (filename) + const char *filename; +{ + FILE *file; + + if (!bitset_stats_info) + return; + + if (!filename) + filename = BITSET_STATS_FILE; + + file = fopen (filename, "w"); + if (file) + { + if (fwrite (&bitset_stats_info_data, sizeof (bitset_stats_info_data), + 1, file) != 1) + perror ("Could not write stats file."); + fclose (file); + } + else + perror ("Could not open stats file for writing."); +} + + +/* Dump bitset statistics to FILE. */ +void +bitset_stats_dump (file) + FILE *file; +{ + bitset_stats_print (file, 0); +} + + +/* Function to be called from debugger to print bitset stats. */ +void +debug_bitset_stats (void) +{ + bitset_stats_print (stderr, 1); +} + + +static void +bitset_stats_set (dst, bitno) + bitset dst; + bitset_bindex bitno; +{ + bitset bset = dst->s.bset; + bitset_windex index = bitno / BITSET_WORD_BITS; + bitset_windex offset = index - bset->b.cindex; + + BITSET_STATS_SETS_INC (bset); + + if (offset < bset->b.csize) + { + bset->b.cdata[offset] |= (1 << (bitno % BITSET_WORD_BITS)); + BITSET_STATS_CACHE_SETS_INC (bset); + } + else + BITSET_SET_ (bset, bitno); +} + + +static void +bitset_stats_reset (dst, bitno) + bitset dst; + bitset_bindex bitno; +{ + bitset bset = dst->s.bset; + bitset_windex index = bitno / BITSET_WORD_BITS; + bitset_windex offset = index - bset->b.cindex; + + BITSET_STATS_RESETS_INC (bset); + + if (offset < bset->b.csize) + { + bset->b.cdata[offset] &= ~(1 << (bitno % BITSET_WORD_BITS)); + BITSET_STATS_CACHE_RESETS_INC (bset); + } + else + BITSET_RESET_ (bset, bitno); +} + + +static int +bitset_stats_test (src, bitno) + bitset src; + bitset_bindex bitno; +{ + bitset bset = src->s.bset; + bitset_windex index = bitno / BITSET_WORD_BITS; + bitset_windex offset = index - bset->b.cindex; + + BITSET_STATS_TESTS_INC (bset); + + if (offset < bset->b.csize) + { + BITSET_STATS_CACHE_TESTS_INC (bset); + return (bset->b.cdata[offset] >> (bitno % BITSET_WORD_BITS)) & 1; + } + else + return BITSET_TEST_ (bset, bitno); +} + + +static int +bitset_stats_size (src) + bitset src; +{ + return BITSET_SIZE_ (src->s.bset); +} + + +static int +bitset_stats_op1 (dst, op) + bitset dst; + enum bitset_ops op; +{ + return BITSET_OP1_ (dst->s.bset, op); +} + + +static int +bitset_stats_op2 (dst, src, op) + bitset dst; + bitset src; + enum bitset_ops op; +{ + BITSET_CHECK2_ (dst, src); + return BITSET_OP2_ (dst->s.bset, src->s.bset, op); +} + + +static int +bitset_stats_op3 (dst, src1, src2, op) + bitset dst; + bitset src1; + bitset src2; + enum bitset_ops op; +{ + BITSET_CHECK3_ (dst, src1, src2); + return BITSET_OP3_ (dst->s.bset, src1->s.bset, src2->s.bset, op); +} + + +static int +bitset_stats_op4 (dst, src1, src2, src3, op) + bitset dst; + bitset src1; + bitset src2; + bitset src3; + enum bitset_ops op; +{ + BITSET_CHECK4_ (dst, src1, src2, src3); + + /* This is a bit of a hack. If the implementation handles + a four operand operation then vector to it, passing + the enclosed bitsets. Otherwise use the fallback + bitset_op4 routine. */ + if (dst->s.bset->b.ops->op4 != bitset_op4) + return BITSET_OP4_ (dst->s.bset, src1->s.bset, src2->s.bset, + src3->s.bset, op); + + return bitset_op4 (dst, src1, src2, src3, op); +} + + +static int +bitset_stats_list (bset, list, num, next) + bitset bset; + bitset_bindex *list; + bitset_bindex num; + bitset_bindex *next; +{ + bitset_bindex count; + bitset_bindex tmp; + bitset_bindex size; + bitset_bindex i; + enum bitset_type type; + + count = BITSET_LIST_ (bset->s.bset, list, num, next); + + type = BITSET_TYPE_ (bset->s.bset); + BITSET_STATS_LISTS_INC (bset->s.bset); + + /* Log histogram of number of set bits. */ + for (i = 0, tmp = count; tmp; tmp >>= 1, i++) + continue; + if (i >= BITSET_LOG_COUNT_BINS) + i = BITSET_LOG_COUNT_BINS - 1; + BITSET_STATS_LIST_COUNTS_INC (bset->s.bset, i); + + /* Log histogram of number of bits in set. */ + size = BITSET_SIZE_ (bset->s.bset); + for (i = 0, tmp = size; tmp; tmp >>= 1, i++) + continue; + if (i >= BITSET_LOG_SIZE_BINS) + i = BITSET_LOG_SIZE_BINS - 1; + BITSET_STATS_LIST_SIZES_INC (bset->s.bset, i); + + /* Histogram of fraction of bits set. */ + i = size ? (count * BITSET_DENSITY_BINS) / size : 0; + if (i >= BITSET_DENSITY_BINS) + i = BITSET_DENSITY_BINS - 1; + BITSET_STATS_LIST_DENSITY_INC (bset->s.bset, i); + return count; +} + + +static int +bitset_stats_reverse_list (bset, list, num, next) + bitset bset; + bitset_bindex *list; + bitset_bindex num; + bitset_bindex *next; +{ + return BITSET_REVERSE_LIST_ (bset->s.bset, list, num, next); +} + + +static void +bitset_stats_free (bset) + bitset bset; +{ + BITSET_STATS_FREES_INC (bset->s.bset); + BITSET_FREE_ (bset->s.bset); +} + + +struct bitset_ops_struct bitset_stats_ops = { + bitset_stats_set, + bitset_stats_reset, + bitset_stats_test, + bitset_stats_size, + bitset_stats_op1, + bitset_stats_op2, + bitset_stats_op3, + bitset_stats_op4, + bitset_stats_list, + bitset_stats_reverse_list, + bitset_stats_free, + BITSET_STATS +}; + + +/* Return enclosed bitset type. */ +enum bitset_type +bitset_stats_type_get (bset) + bitset bset; +{ + return BITSET_TYPE_ (bset->s.bset); +} + + +int bitset_stats_bytes (void) +{ + return sizeof (struct bitset_struct); +} + + +bitset +bitset_stats_init (bset, n_bits, type) + bitset bset; + bitset_bindex n_bits; + enum bitset_type type; +{ + unsigned int bytes; + bitset sbset; + + bset->b.ops = &bitset_stats_ops; + + /* Disable cache. */ + bset->b.cindex = 0; + bset->b.csize = 0; + bset->b.cdata = 0; + + /* Set up the actual bitset implementation that + we are a wrapper over. */ + switch (type) + { + case BITSET_ARRAY: + bytes = abitset_bytes (n_bits); + sbset = (bitset) xcalloc (1, bytes); + abitset_init (sbset, n_bits); + break; + + case BITSET_LIST: + bytes = lbitset_bytes (n_bits); + sbset = (bitset) xcalloc (1, bytes); + lbitset_init (sbset, n_bits); + break; + + case BITSET_TABLE: + bytes = ebitset_bytes (n_bits); + sbset = (bitset) xcalloc (1, bytes); + ebitset_init (sbset, n_bits); + break; + + default: + abort (); + } + + bset->s.bset = sbset; + + BITSET_STATS_ALLOCS_INC (type); + + return bset; +} |