3    Copyright (C) 2002-2006, 2009-2012 Free Software Foundation, Inc. 
   5    Contributed by Michael Hayes (m.hayes@elec.canterbury.ac.nz). 
   7    This program is free software: you can redistribute it and/or modify 
   8    it under the terms of the GNU General Public License as published by 
   9    the Free Software Foundation, either version 3 of the License, or 
  10    (at your option) any later version. 
  12    This program is distributed in the hope that it will be useful, 
  13    but WITHOUT ANY WARRANTY; without even the implied warranty of 
  14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  15    GNU General Public License for more details. 
  17    You should have received a copy of the GNU General Public License 
  18    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */ 
  20 /* This file is a wrapper bitset implementation for the other bitset 
  21    implementations.  It provides bitset compatibility checking and 
  22    statistics gathering without having to instrument the bitset 
  23    implementations.  When statistics gathering is enabled, the bitset 
  24    operations get vectored through here and we then call the appropriate 
  29 #include "bitset_stats.h" 
  41 #define _(Msgid)  gettext (Msgid) 
  43 /* Configuration macros.  */ 
  44 #define BITSET_STATS_FILE "bitset.dat" 
  45 #define BITSET_LOG_COUNT_BINS 10 
  46 #define BITSET_LOG_SIZE_BINS  16 
  47 #define BITSET_DENSITY_BINS  20 
  50 /* Accessor macros.  */ 
  51 #define BITSET_STATS_ALLOCS_INC(TYPE)                   \ 
  52     bitset_stats_info->types[(TYPE)].allocs++ 
  53 #define BITSET_STATS_FREES_INC(BSET)                    \ 
  54     bitset_stats_info->types[BITSET_TYPE_ (BSET)].frees++ 
  55 #define BITSET_STATS_SETS_INC(BSET)                     \ 
  56     bitset_stats_info->types[BITSET_TYPE_ (BSET)].sets++ 
  57 #define BITSET_STATS_CACHE_SETS_INC(BSET)               \ 
  58     bitset_stats_info->types[BITSET_TYPE_ (BSET)].cache_sets++ 
  59 #define BITSET_STATS_RESETS_INC(BSET)                   \ 
  60     bitset_stats_info->types[BITSET_TYPE_ (BSET)].resets++ 
  61 #define BITSET_STATS_CACHE_RESETS_INC(BSET)             \ 
  62     bitset_stats_info->types[BITSET_TYPE_ (BSET)].cache_resets++ 
  63 #define BITSET_STATS_TESTS_INC(BSET)                    \ 
  64     bitset_stats_info->types[BITSET_TYPE_ (BSET)].tests++ 
  65 #define BITSET_STATS_CACHE_TESTS_INC(BSET)              \ 
  66     bitset_stats_info->types[BITSET_TYPE_ (BSET)].cache_tests++ 
  67 #define BITSET_STATS_LISTS_INC(BSET)                    \ 
  68     bitset_stats_info->types[BITSET_TYPE_ (BSET)].lists++ 
  69 #define BITSET_STATS_LIST_COUNTS_INC(BSET, I)           \ 
  70     bitset_stats_info->types[BITSET_TYPE_ (BSET)].list_counts[(I)]++ 
  71 #define BITSET_STATS_LIST_SIZES_INC(BSET, I)            \ 
  72     bitset_stats_info->types[BITSET_TYPE_ (BSET)].list_sizes[(I)]++ 
  73 #define BITSET_STATS_LIST_DENSITY_INC(BSET, I)          \ 
  74     bitset_stats_info->types[BITSET_TYPE_ (BSET)].list_density[(I)]++ 
  77 struct bitset_type_info_struct
 
  83   unsigned int cache_sets
; 
  85   unsigned int cache_resets
; 
  87   unsigned int cache_tests
; 
  88   unsigned int list_counts
[BITSET_LOG_COUNT_BINS
]; 
  89   unsigned int list_sizes
[BITSET_LOG_SIZE_BINS
]; 
  90   unsigned int list_density
[BITSET_DENSITY_BINS
]; 
  93 struct bitset_stats_info_struct
 
  96   struct bitset_type_info_struct types
[BITSET_TYPE_NUM
]; 
 100 struct bitset_stats_info_struct bitset_stats_info_data
; 
 101 struct bitset_stats_info_struct 
*bitset_stats_info
; 
 102 bool bitset_stats_enabled 
= false; 
 105 /* Print a percentage histogram with message MSG to FILE.  */ 
 107 bitset_percent_histogram_print (FILE *file
, const char *name
, const char *msg
, 
 108                                 unsigned int n_bins
, unsigned int *bins
) 
 114   for (i 
= 0; i 
< n_bins
; i
++) 
 120   fprintf (file
, "%s %s", name
, msg
); 
 121   for (i 
= 0; i 
< n_bins
; i
++) 
 122     fprintf (file
, "%.0f-%.0f%%\t%8u (%5.1f%%)\n", 
 124              (i 
+ 1) * 100.0 / n_bins
, bins
[i
], 
 125              (100.0 * bins
[i
]) / total
); 
 129 /* Print a log histogram with message MSG to FILE.  */ 
 131 bitset_log_histogram_print (FILE *file
, const char *name
, const char *msg
, 
 132                             unsigned int n_bins
, unsigned int *bins
) 
 136   unsigned int max_width
; 
 139   for (i 
= 0; i 
< n_bins
; i
++) 
 145   /* Determine number of useful bins.  */ 
 146   for (i 
= n_bins
; i 
> 3 && ! bins
[i 
- 1]; i
--) 
 150   /* 2 * ceil (log10 (2) * (N - 1)) + 1.  */ 
 151   max_width 
= 2 * (unsigned int) (0.30103 * (n_bins 
- 1) + 0.9999) + 1; 
 153   fprintf (file
, "%s %s", name
, msg
); 
 154   for (i 
= 0; i 
< 2; i
++) 
 155     fprintf (file
, "%*d\t%8u (%5.1f%%)\n", 
 156              max_width
, i
, bins
[i
], 100.0 * bins
[i
] / total
); 
 158   for (; i 
< n_bins
; i
++) 
 159     fprintf (file
, "%*lu-%lu\t%8u (%5.1f%%)\n", 
 160              max_width 
- ((unsigned int) (0.30103 * (i
) + 0.9999) + 1), 
 164              (100.0 * bins
[i
]) / total
); 
 168 /* Print bitset statistics to FILE.  */ 
 170 bitset_stats_print_1 (FILE *file
, const char *name
, 
 171                       struct bitset_type_info_struct 
*stats
) 
 176   fprintf (file
, "%s:\n", name
); 
 177   fprintf (file
, _("%u bitset_allocs, %u freed (%.2f%%).\n"), 
 178            stats
->allocs
, stats
->frees
, 
 179            stats
->allocs 
? 100.0 * stats
->frees 
/ stats
->allocs 
: 0); 
 180   fprintf (file
, _("%u bitset_sets, %u cached (%.2f%%)\n"), 
 181            stats
->sets
, stats
->cache_sets
, 
 182            stats
->sets 
? 100.0 * stats
->cache_sets 
/ stats
->sets 
: 0); 
 183   fprintf (file
, _("%u bitset_resets, %u cached (%.2f%%)\n"), 
 184            stats
->resets
, stats
->cache_resets
, 
 185            stats
->resets 
? 100.0 * stats
->cache_resets 
/ stats
->resets 
: 0); 
 186   fprintf (file
, _("%u bitset_tests, %u cached (%.2f%%)\n"), 
 187            stats
->tests
, stats
->cache_tests
, 
 188            stats
->tests 
? 100.0 * stats
->cache_tests 
/ stats
->tests 
: 0); 
 190   fprintf (file
, _("%u bitset_lists\n"), stats
->lists
); 
 192   bitset_log_histogram_print (file
, name
, _("count log histogram\n"), 
 193                               BITSET_LOG_COUNT_BINS
, stats
->list_counts
); 
 195   bitset_log_histogram_print (file
, name
, _("size log histogram\n"), 
 196                               BITSET_LOG_SIZE_BINS
, stats
->list_sizes
); 
 198   bitset_percent_histogram_print (file
, name
, _("density histogram\n"), 
 199                                   BITSET_DENSITY_BINS
, stats
->list_density
); 
 203 /* Print all bitset statistics to FILE.  */ 
 205 bitset_stats_print (FILE *file
, bool verbose ATTRIBUTE_UNUSED
) 
 209   if (!bitset_stats_info
) 
 212   fprintf (file
, _("Bitset statistics:\n\n")); 
 214   if (bitset_stats_info
->runs 
> 1) 
 215     fprintf (file
, _("Accumulated runs = %u\n"), bitset_stats_info
->runs
); 
 217   for (i 
= 0; i 
< BITSET_TYPE_NUM
; i
++) 
 218     bitset_stats_print_1 (file
, bitset_type_names
[i
], 
 219                           &bitset_stats_info
->types
[i
]); 
 223 /* Initialise bitset statistics logging.  */ 
 225 bitset_stats_enable (void) 
 227   if (!bitset_stats_info
) 
 228     bitset_stats_info 
= &bitset_stats_info_data
; 
 229   bitset_stats_enabled 
= true; 
 234 bitset_stats_disable (void) 
 236   bitset_stats_enabled 
= false; 
 240 /* Read bitset statistics file.  */ 
 242 bitset_stats_read (const char *file_name
) 
 246   if (!bitset_stats_info
) 
 250     file_name 
= BITSET_STATS_FILE
; 
 252   file 
= fopen (file_name
, "r"); 
 255       if (fread (&bitset_stats_info_data
, sizeof (bitset_stats_info_data
), 
 259             perror (_("cannot read stats file")); 
 261             fprintf (stderr
, _("bad stats file size\n")); 
 263       if (fclose (file
) != 0) 
 264         perror (_("cannot read stats file")); 
 266   bitset_stats_info_data
.runs
++; 
 270 /* Write bitset statistics file.  */ 
 272 bitset_stats_write (const char *file_name
) 
 276   if (!bitset_stats_info
) 
 280     file_name 
= BITSET_STATS_FILE
; 
 282   file 
= fopen (file_name
, "w"); 
 285       if (fwrite (&bitset_stats_info_data
, sizeof (bitset_stats_info_data
), 
 287         perror (_("cannot write stats file")); 
 288       if (fclose (file
) != 0) 
 289         perror (_("cannot write stats file")); 
 292     perror (_("cannot open stats file for writing")); 
 296 /* Dump bitset statistics to FILE.  */ 
 298 bitset_stats_dump (FILE *file
) 
 300   bitset_stats_print (file
, false); 
 304 /* Function to be called from debugger to print bitset stats.  */ 
 306 debug_bitset_stats (void) 
 308   bitset_stats_print (stderr
, true); 
 313 bitset_stats_set (bitset dst
, bitset_bindex bitno
) 
 315   bitset bset 
= dst
->s
.bset
; 
 316   bitset_windex wordno 
= bitno 
/ BITSET_WORD_BITS
; 
 317   bitset_windex offset 
= wordno 
- bset
->b
.cindex
; 
 319   BITSET_STATS_SETS_INC (bset
); 
 321   if (offset 
< bset
->b
.csize
) 
 323       bset
->b
.cdata
[offset
] |= (bitset_word
) 1 << (bitno 
% BITSET_WORD_BITS
); 
 324       BITSET_STATS_CACHE_SETS_INC (bset
); 
 327     BITSET_SET_ (bset
, bitno
); 
 332 bitset_stats_reset (bitset dst
, bitset_bindex bitno
) 
 334   bitset bset 
= dst
->s
.bset
; 
 335   bitset_windex wordno 
= bitno 
/ BITSET_WORD_BITS
; 
 336   bitset_windex offset 
= wordno 
- bset
->b
.cindex
; 
 338   BITSET_STATS_RESETS_INC (bset
); 
 340   if (offset 
< bset
->b
.csize
) 
 342       bset
->b
.cdata
[offset
] &= 
 343         ~((bitset_word
) 1 << (bitno 
% BITSET_WORD_BITS
)); 
 344       BITSET_STATS_CACHE_RESETS_INC (bset
); 
 347     BITSET_RESET_ (bset
, bitno
); 
 352 bitset_stats_toggle (bitset src
, bitset_bindex bitno
) 
 354     return BITSET_TOGGLE_ (src
->s
.bset
, bitno
); 
 359 bitset_stats_test (bitset src
, bitset_bindex bitno
) 
 361   bitset bset 
= src
->s
.bset
; 
 362   bitset_windex wordno 
= bitno 
/ BITSET_WORD_BITS
; 
 363   bitset_windex offset 
= wordno 
- bset
->b
.cindex
; 
 365   BITSET_STATS_TESTS_INC (bset
); 
 367   if (offset 
< bset
->b
.csize
) 
 369       BITSET_STATS_CACHE_TESTS_INC (bset
); 
 370       return (bset
->b
.cdata
[offset
] >> (bitno 
% BITSET_WORD_BITS
)) & 1; 
 373     return BITSET_TEST_ (bset
, bitno
); 
 378 bitset_stats_resize (bitset src
, bitset_bindex size
) 
 380     return BITSET_RESIZE_ (src
->s
.bset
, size
); 
 385 bitset_stats_size (bitset src
) 
 387   return BITSET_SIZE_ (src
->s
.bset
); 
 392 bitset_stats_count (bitset src
) 
 394   return BITSET_COUNT_ (src
->s
.bset
); 
 399 bitset_stats_empty_p (bitset dst
) 
 401   return BITSET_EMPTY_P_ (dst
->s
.bset
); 
 406 bitset_stats_ones (bitset dst
) 
 408   BITSET_ONES_ (dst
->s
.bset
); 
 413 bitset_stats_zero (bitset dst
) 
 415   BITSET_ZERO_ (dst
->s
.bset
); 
 420 bitset_stats_copy (bitset dst
, bitset src
) 
 422   BITSET_CHECK2_ (dst
, src
); 
 423   BITSET_COPY_ (dst
->s
.bset
, src
->s
.bset
); 
 428 bitset_stats_disjoint_p (bitset dst
, bitset src
) 
 430   BITSET_CHECK2_ (dst
, src
); 
 431   return BITSET_DISJOINT_P_ (dst
->s
.bset
, src
->s
.bset
); 
 436 bitset_stats_equal_p (bitset dst
, bitset src
) 
 438   BITSET_CHECK2_ (dst
, src
); 
 439   return BITSET_EQUAL_P_ (dst
->s
.bset
, src
->s
.bset
); 
 444 bitset_stats_not (bitset dst
, bitset src
) 
 446   BITSET_CHECK2_ (dst
, src
); 
 447   BITSET_NOT_ (dst
->s
.bset
, src
->s
.bset
); 
 452 bitset_stats_subset_p (bitset dst
, bitset src
) 
 454   BITSET_CHECK2_ (dst
, src
); 
 455   return BITSET_SUBSET_P_ (dst
->s
.bset
, src
->s
.bset
); 
 460 bitset_stats_and (bitset dst
, bitset src1
, bitset src2
) 
 462   BITSET_CHECK3_ (dst
, src1
, src2
); 
 463   BITSET_AND_ (dst
->s
.bset
, src1
->s
.bset
, src2
->s
.bset
); 
 468 bitset_stats_and_cmp (bitset dst
, bitset src1
, bitset src2
) 
 470   BITSET_CHECK3_ (dst
, src1
, src2
); 
 471   return BITSET_AND_CMP_ (dst
->s
.bset
, src1
->s
.bset
, src2
->s
.bset
); 
 476 bitset_stats_andn (bitset dst
, bitset src1
, bitset src2
) 
 478   BITSET_CHECK3_ (dst
, src1
, src2
); 
 479   BITSET_ANDN_ (dst
->s
.bset
, src1
->s
.bset
, src2
->s
.bset
); 
 484 bitset_stats_andn_cmp (bitset dst
, bitset src1
, bitset src2
) 
 486   BITSET_CHECK3_ (dst
, src1
, src2
); 
 487   return BITSET_ANDN_CMP_ (dst
->s
.bset
, src1
->s
.bset
, src2
->s
.bset
); 
 492 bitset_stats_or (bitset dst
, bitset src1
, bitset src2
) 
 494   BITSET_CHECK3_ (dst
, src1
, src2
); 
 495   BITSET_OR_ (dst
->s
.bset
, src1
->s
.bset
, src2
->s
.bset
); 
 500 bitset_stats_or_cmp (bitset dst
, bitset src1
, bitset src2
) 
 502   BITSET_CHECK3_ (dst
, src1
, src2
); 
 503   return BITSET_OR_CMP_ (dst
->s
.bset
, src1
->s
.bset
, src2
->s
.bset
); 
 508 bitset_stats_xor (bitset dst
, bitset src1
, bitset src2
) 
 510   BITSET_CHECK3_ (dst
, src1
, src2
); 
 511   BITSET_XOR_ (dst
->s
.bset
, src1
->s
.bset
, src2
->s
.bset
); 
 516 bitset_stats_xor_cmp (bitset dst
, bitset src1
, bitset src2
) 
 518   BITSET_CHECK3_ (dst
, src1
, src2
); 
 519   return BITSET_XOR_CMP_ (dst
->s
.bset
, src1
->s
.bset
, src2
->s
.bset
); 
 524 bitset_stats_and_or (bitset dst
, bitset src1
, bitset src2
, bitset src3
) 
 526   BITSET_CHECK4_ (dst
, src1
, src2
, src3
); 
 527   BITSET_AND_OR_ (dst
->s
.bset
, src1
->s
.bset
, src2
->s
.bset
, src3
->s
.bset
); 
 532 bitset_stats_and_or_cmp (bitset dst
, bitset src1
, bitset src2
, bitset src3
) 
 534   BITSET_CHECK4_ (dst
, src1
, src2
, src3
); 
 535   return BITSET_AND_OR_CMP_ (dst
->s
.bset
, src1
->s
.bset
, src2
->s
.bset
, src3
->s
.bset
); 
 540 bitset_stats_andn_or (bitset dst
, bitset src1
, bitset src2
, bitset src3
) 
 542   BITSET_CHECK4_ (dst
, src1
, src2
, src3
); 
 543   BITSET_ANDN_OR_ (dst
->s
.bset
, src1
->s
.bset
, src2
->s
.bset
, src3
->s
.bset
); 
 548 bitset_stats_andn_or_cmp (bitset dst
, bitset src1
, bitset src2
, bitset src3
) 
 550   BITSET_CHECK4_ (dst
, src1
, src2
, src3
); 
 551   return BITSET_ANDN_OR_CMP_ (dst
->s
.bset
, src1
->s
.bset
, src2
->s
.bset
, src3
->s
.bset
); 
 556 bitset_stats_or_and (bitset dst
, bitset src1
, bitset src2
, bitset src3
) 
 558   BITSET_CHECK4_ (dst
, src1
, src2
, src3
); 
 559   BITSET_OR_AND_ (dst
->s
.bset
, src1
->s
.bset
, src2
->s
.bset
, src3
->s
.bset
); 
 564 bitset_stats_or_and_cmp (bitset dst
, bitset src1
, bitset src2
, bitset src3
) 
 566   BITSET_CHECK4_ (dst
, src1
, src2
, src3
); 
 567   return BITSET_OR_AND_CMP_ (dst
->s
.bset
, src1
->s
.bset
, src2
->s
.bset
, src3
->s
.bset
); 
 572 bitset_stats_list (bitset bset
, bitset_bindex 
*list
, 
 573                    bitset_bindex num
, bitset_bindex 
*next
) 
 580   count 
= BITSET_LIST_ (bset
->s
.bset
, list
, num
, next
); 
 582   BITSET_STATS_LISTS_INC (bset
->s
.bset
); 
 584   /* Log histogram of number of set bits.  */ 
 585   for (i 
= 0, tmp 
= count
; tmp
; tmp 
>>= 1, i
++) 
 587   if (i 
>= BITSET_LOG_COUNT_BINS
) 
 588      i 
= BITSET_LOG_COUNT_BINS 
- 1; 
 589   BITSET_STATS_LIST_COUNTS_INC (bset
->s
.bset
, i
); 
 591   /* Log histogram of number of bits in set.  */ 
 592   size 
= BITSET_SIZE_ (bset
->s
.bset
); 
 593   for (i 
= 0, tmp 
= size
; tmp
; tmp 
>>= 1, i
++) 
 595   if (i 
>= BITSET_LOG_SIZE_BINS
) 
 596      i 
= BITSET_LOG_SIZE_BINS 
- 1; 
 597   BITSET_STATS_LIST_SIZES_INC (bset
->s
.bset
, i
); 
 599   /* Histogram of fraction of bits set.  */ 
 600   i 
= size 
? (count 
* BITSET_DENSITY_BINS
) / size 
: 0; 
 601   if (i 
>= BITSET_DENSITY_BINS
) 
 602      i 
= BITSET_DENSITY_BINS 
- 1; 
 603   BITSET_STATS_LIST_DENSITY_INC (bset
->s
.bset
, i
); 
 609 bitset_stats_list_reverse (bitset bset
, bitset_bindex 
*list
, 
 610                            bitset_bindex num
, bitset_bindex 
*next
) 
 612   return BITSET_LIST_REVERSE_ (bset
->s
.bset
, list
, num
, next
); 
 617 bitset_stats_free (bitset bset
) 
 619   BITSET_STATS_FREES_INC (bset
->s
.bset
); 
 620   BITSET_FREE_ (bset
->s
.bset
); 
 624 struct bitset_vtable bitset_stats_vtable 
= { 
 632   bitset_stats_empty_p
, 
 636   bitset_stats_disjoint_p
, 
 637   bitset_stats_equal_p
, 
 639   bitset_stats_subset_p
, 
 641   bitset_stats_and_cmp
, 
 643   bitset_stats_andn_cmp
, 
 647   bitset_stats_xor_cmp
, 
 649   bitset_stats_and_or_cmp
, 
 650   bitset_stats_andn_or
, 
 651   bitset_stats_andn_or_cmp
, 
 653   bitset_stats_or_and_cmp
, 
 655   bitset_stats_list_reverse
, 
 661 /* Return enclosed bitset type.  */ 
 663 bitset_stats_type_get (bitset bset
) 
 665    return BITSET_TYPE_ (bset
->s
.bset
); 
 670 bitset_stats_bytes (void) 
 672   return sizeof (struct bitset_stats_struct
); 
 677 bitset_stats_init (bitset bset
, bitset_bindex n_bits
, enum bitset_type type
) 
 682   bset
->b
.vtable 
= &bitset_stats_vtable
; 
 689   BITSET_NBITS_ (bset
) = n_bits
; 
 691   /* Set up the actual bitset implementation that 
 692      we are a wrapper over.  */ 
 699       bytes 
= abitset_bytes (n_bits
); 
 700       sbset 
= xcalloc (1, bytes
); 
 701       abitset_init (sbset
, n_bits
); 
 705       bytes 
= lbitset_bytes (n_bits
); 
 706       sbset 
= xcalloc (1, bytes
); 
 707       lbitset_init (sbset
, n_bits
); 
 711       bytes 
= ebitset_bytes (n_bits
); 
 712       sbset 
= xcalloc (1, bytes
); 
 713       ebitset_init (sbset
, n_bits
); 
 717       bytes 
= vbitset_bytes (n_bits
); 
 718       sbset 
= xcalloc (1, bytes
); 
 719       vbitset_init (sbset
, n_bits
); 
 723   bset
->s
.bset 
= sbset
; 
 725   BITSET_STATS_ALLOCS_INC (type
);