1 /* Bitset statistics. 2 3 Copyright (C) 2002-2006, 2009-2012 Free Software Foundation, Inc. 4 5 Contributed by Michael Hayes (m.hayes (at) elec.canterbury.ac.nz). 6 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. 11 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. 16 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/>. */ 19 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 25 routines. */ 26 27 #include <config.h> 28 29 #include "bitset_stats.h" 30 31 #include "bbitset.h" 32 #include "abitset.h" 33 #include "ebitset.h" 34 #include "lbitset.h" 35 #include "vbitset.h" 36 #include <stdlib.h> 37 #include <string.h> 38 #include <stdio.h> 39 40 #include "gettext.h" 41 #define _(Msgid) gettext (Msgid) 42 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 48 49 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)]++ 75 76 77 struct bitset_type_info_struct 78 { 79 unsigned int allocs; 80 unsigned int frees; 81 unsigned int lists; 82 unsigned int sets; 83 unsigned int cache_sets; 84 unsigned int resets; 85 unsigned int cache_resets; 86 unsigned int tests; 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]; 91 }; 92 93 struct bitset_stats_info_struct 94 { 95 unsigned int runs; 96 struct bitset_type_info_struct types[BITSET_TYPE_NUM]; 97 }; 98 99 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; 103 104 105 /* Print a percentage histogram with message MSG to FILE. */ 106 static void 107 bitset_percent_histogram_print (FILE *file, const char *name, const char *msg, 108 unsigned int n_bins, unsigned int *bins) 109 { 110 unsigned int i; 111 unsigned int total; 112 113 total = 0; 114 for (i = 0; i < n_bins; i++) 115 total += bins[i]; 116 117 if (!total) 118 return; 119 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", 123 i * 100.0 / n_bins, 124 (i + 1) * 100.0 / n_bins, bins[i], 125 (100.0 * bins[i]) / total); 126 } 127 128 129 /* Print a log histogram with message MSG to FILE. */ 130 static void 131 bitset_log_histogram_print (FILE *file, const char *name, const char *msg, 132 unsigned int n_bins, unsigned int *bins) 133 { 134 unsigned int i; 135 unsigned int total; 136 unsigned int max_width; 137 138 total = 0; 139 for (i = 0; i < n_bins; i++) 140 total += bins[i]; 141 142 if (!total) 143 return; 144 145 /* Determine number of useful bins. */ 146 for (i = n_bins; i > 3 && ! bins[i - 1]; i--) 147 continue; 148 n_bins = i; 149 150 /* 2 * ceil (log10 (2) * (N - 1)) + 1. */ 151 max_width = 2 * (unsigned int) (0.30103 * (n_bins - 1) + 0.9999) + 1; 152 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); 157 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), 161 1UL << (i - 1), 162 (1UL << i) - 1, 163 bins[i], 164 (100.0 * bins[i]) / total); 165 } 166 167 168 /* Print bitset statistics to FILE. */ 169 static void 170 bitset_stats_print_1 (FILE *file, const char *name, 171 struct bitset_type_info_struct *stats) 172 { 173 if (!stats) 174 return; 175 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); 189 190 fprintf (file, _("%u bitset_lists\n"), stats->lists); 191 192 bitset_log_histogram_print (file, name, _("count log histogram\n"), 193 BITSET_LOG_COUNT_BINS, stats->list_counts); 194 195 bitset_log_histogram_print (file, name, _("size log histogram\n"), 196 BITSET_LOG_SIZE_BINS, stats->list_sizes); 197 198 bitset_percent_histogram_print (file, name, _("density histogram\n"), 199 BITSET_DENSITY_BINS, stats->list_density); 200 } 201 202 203 /* Print all bitset statistics to FILE. */ 204 static void 205 bitset_stats_print (FILE *file, bool verbose ATTRIBUTE_UNUSED) 206 { 207 int i; 208 209 if (!bitset_stats_info) 210 return; 211 212 fprintf (file, _("Bitset statistics:\n\n")); 213 214 if (bitset_stats_info->runs > 1) 215 fprintf (file, _("Accumulated runs = %u\n"), bitset_stats_info->runs); 216 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]); 220 } 221 222 223 /* Initialise bitset statistics logging. */ 224 void 225 bitset_stats_enable (void) 226 { 227 if (!bitset_stats_info) 228 bitset_stats_info = &bitset_stats_info_data; 229 bitset_stats_enabled = true; 230 } 231 232 233 void 234 bitset_stats_disable (void) 235 { 236 bitset_stats_enabled = false; 237 } 238 239 240 /* Read bitset statistics file. */ 241 void 242 bitset_stats_read (const char *file_name) 243 { 244 FILE *file; 245 246 if (!bitset_stats_info) 247 return; 248 249 if (!file_name) 250 file_name = BITSET_STATS_FILE; 251 252 file = fopen (file_name, "r"); 253 if (file) 254 { 255 if (fread (&bitset_stats_info_data, sizeof (bitset_stats_info_data), 256 1, file) != 1) 257 { 258 if (ferror (file)) 259 perror (_("cannot read stats file")); 260 else 261 fprintf (stderr, _("bad stats file size\n")); 262 } 263 if (fclose (file) != 0) 264 perror (_("cannot read stats file")); 265 } 266 bitset_stats_info_data.runs++; 267 } 268 269 270 /* Write bitset statistics file. */ 271 void 272 bitset_stats_write (const char *file_name) 273 { 274 FILE *file; 275 276 if (!bitset_stats_info) 277 return; 278 279 if (!file_name) 280 file_name = BITSET_STATS_FILE; 281 282 file = fopen (file_name, "w"); 283 if (file) 284 { 285 if (fwrite (&bitset_stats_info_data, sizeof (bitset_stats_info_data), 286 1, file) != 1) 287 perror (_("cannot write stats file")); 288 if (fclose (file) != 0) 289 perror (_("cannot write stats file")); 290 } 291 else 292 perror (_("cannot open stats file for writing")); 293 } 294 295 296 /* Dump bitset statistics to FILE. */ 297 void 298 bitset_stats_dump (FILE *file) 299 { 300 bitset_stats_print (file, false); 301 } 302 303 304 /* Function to be called from debugger to print bitset stats. */ 305 void 306 debug_bitset_stats (void) 307 { 308 bitset_stats_print (stderr, true); 309 } 310 311 312 static void 313 bitset_stats_set (bitset dst, bitset_bindex bitno) 314 { 315 bitset bset = dst->s.bset; 316 bitset_windex wordno = bitno / BITSET_WORD_BITS; 317 bitset_windex offset = wordno - bset->b.cindex; 318 319 BITSET_STATS_SETS_INC (bset); 320 321 if (offset < bset->b.csize) 322 { 323 bset->b.cdata[offset] |= (bitset_word) 1 << (bitno % BITSET_WORD_BITS); 324 BITSET_STATS_CACHE_SETS_INC (bset); 325 } 326 else 327 BITSET_SET_ (bset, bitno); 328 } 329 330 331 static void 332 bitset_stats_reset (bitset dst, bitset_bindex bitno) 333 { 334 bitset bset = dst->s.bset; 335 bitset_windex wordno = bitno / BITSET_WORD_BITS; 336 bitset_windex offset = wordno - bset->b.cindex; 337 338 BITSET_STATS_RESETS_INC (bset); 339 340 if (offset < bset->b.csize) 341 { 342 bset->b.cdata[offset] &= 343 ~((bitset_word) 1 << (bitno % BITSET_WORD_BITS)); 344 BITSET_STATS_CACHE_RESETS_INC (bset); 345 } 346 else 347 BITSET_RESET_ (bset, bitno); 348 } 349 350 351 static bool 352 bitset_stats_toggle (bitset src, bitset_bindex bitno) 353 { 354 return BITSET_TOGGLE_ (src->s.bset, bitno); 355 } 356 357 358 static bool 359 bitset_stats_test (bitset src, bitset_bindex bitno) 360 { 361 bitset bset = src->s.bset; 362 bitset_windex wordno = bitno / BITSET_WORD_BITS; 363 bitset_windex offset = wordno - bset->b.cindex; 364 365 BITSET_STATS_TESTS_INC (bset); 366 367 if (offset < bset->b.csize) 368 { 369 BITSET_STATS_CACHE_TESTS_INC (bset); 370 return (bset->b.cdata[offset] >> (bitno % BITSET_WORD_BITS)) & 1; 371 } 372 else 373 return BITSET_TEST_ (bset, bitno); 374 } 375 376 377 static bitset_bindex 378 bitset_stats_resize (bitset src, bitset_bindex size) 379 { 380 return BITSET_RESIZE_ (src->s.bset, size); 381 } 382 383 384 static bitset_bindex 385 bitset_stats_size (bitset src) 386 { 387 return BITSET_SIZE_ (src->s.bset); 388 } 389 390 391 static bitset_bindex 392 bitset_stats_count (bitset src) 393 { 394 return BITSET_COUNT_ (src->s.bset); 395 } 396 397 398 static bool 399 bitset_stats_empty_p (bitset dst) 400 { 401 return BITSET_EMPTY_P_ (dst->s.bset); 402 } 403 404 405 static void 406 bitset_stats_ones (bitset dst) 407 { 408 BITSET_ONES_ (dst->s.bset); 409 } 410 411 412 static void 413 bitset_stats_zero (bitset dst) 414 { 415 BITSET_ZERO_ (dst->s.bset); 416 } 417 418 419 static void 420 bitset_stats_copy (bitset dst, bitset src) 421 { 422 BITSET_CHECK2_ (dst, src); 423 BITSET_COPY_ (dst->s.bset, src->s.bset); 424 } 425 426 427 static bool 428 bitset_stats_disjoint_p (bitset dst, bitset src) 429 { 430 BITSET_CHECK2_ (dst, src); 431 return BITSET_DISJOINT_P_ (dst->s.bset, src->s.bset); 432 } 433 434 435 static bool 436 bitset_stats_equal_p (bitset dst, bitset src) 437 { 438 BITSET_CHECK2_ (dst, src); 439 return BITSET_EQUAL_P_ (dst->s.bset, src->s.bset); 440 } 441 442 443 static void 444 bitset_stats_not (bitset dst, bitset src) 445 { 446 BITSET_CHECK2_ (dst, src); 447 BITSET_NOT_ (dst->s.bset, src->s.bset); 448 } 449 450 451 static bool 452 bitset_stats_subset_p (bitset dst, bitset src) 453 { 454 BITSET_CHECK2_ (dst, src); 455 return BITSET_SUBSET_P_ (dst->s.bset, src->s.bset); 456 } 457 458 459 static void 460 bitset_stats_and (bitset dst, bitset src1, bitset src2) 461 { 462 BITSET_CHECK3_ (dst, src1, src2); 463 BITSET_AND_ (dst->s.bset, src1->s.bset, src2->s.bset); 464 } 465 466 467 static bool 468 bitset_stats_and_cmp (bitset dst, bitset src1, bitset src2) 469 { 470 BITSET_CHECK3_ (dst, src1, src2); 471 return BITSET_AND_CMP_ (dst->s.bset, src1->s.bset, src2->s.bset); 472 } 473 474 475 static void 476 bitset_stats_andn (bitset dst, bitset src1, bitset src2) 477 { 478 BITSET_CHECK3_ (dst, src1, src2); 479 BITSET_ANDN_ (dst->s.bset, src1->s.bset, src2->s.bset); 480 } 481 482 483 static bool 484 bitset_stats_andn_cmp (bitset dst, bitset src1, bitset src2) 485 { 486 BITSET_CHECK3_ (dst, src1, src2); 487 return BITSET_ANDN_CMP_ (dst->s.bset, src1->s.bset, src2->s.bset); 488 } 489 490 491 static void 492 bitset_stats_or (bitset dst, bitset src1, bitset src2) 493 { 494 BITSET_CHECK3_ (dst, src1, src2); 495 BITSET_OR_ (dst->s.bset, src1->s.bset, src2->s.bset); 496 } 497 498 499 static bool 500 bitset_stats_or_cmp (bitset dst, bitset src1, bitset src2) 501 { 502 BITSET_CHECK3_ (dst, src1, src2); 503 return BITSET_OR_CMP_ (dst->s.bset, src1->s.bset, src2->s.bset); 504 } 505 506 507 static void 508 bitset_stats_xor (bitset dst, bitset src1, bitset src2) 509 { 510 BITSET_CHECK3_ (dst, src1, src2); 511 BITSET_XOR_ (dst->s.bset, src1->s.bset, src2->s.bset); 512 } 513 514 515 static bool 516 bitset_stats_xor_cmp (bitset dst, bitset src1, bitset src2) 517 { 518 BITSET_CHECK3_ (dst, src1, src2); 519 return BITSET_XOR_CMP_ (dst->s.bset, src1->s.bset, src2->s.bset); 520 } 521 522 523 static void 524 bitset_stats_and_or (bitset dst, bitset src1, bitset src2, bitset src3) 525 { 526 BITSET_CHECK4_ (dst, src1, src2, src3); 527 BITSET_AND_OR_ (dst->s.bset, src1->s.bset, src2->s.bset, src3->s.bset); 528 } 529 530 531 static bool 532 bitset_stats_and_or_cmp (bitset dst, bitset src1, bitset src2, bitset src3) 533 { 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); 536 } 537 538 539 static void 540 bitset_stats_andn_or (bitset dst, bitset src1, bitset src2, bitset src3) 541 { 542 BITSET_CHECK4_ (dst, src1, src2, src3); 543 BITSET_ANDN_OR_ (dst->s.bset, src1->s.bset, src2->s.bset, src3->s.bset); 544 } 545 546 547 static bool 548 bitset_stats_andn_or_cmp (bitset dst, bitset src1, bitset src2, bitset src3) 549 { 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); 552 } 553 554 555 static void 556 bitset_stats_or_and (bitset dst, bitset src1, bitset src2, bitset src3) 557 { 558 BITSET_CHECK4_ (dst, src1, src2, src3); 559 BITSET_OR_AND_ (dst->s.bset, src1->s.bset, src2->s.bset, src3->s.bset); 560 } 561 562 563 static bool 564 bitset_stats_or_and_cmp (bitset dst, bitset src1, bitset src2, bitset src3) 565 { 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); 568 } 569 570 571 static bitset_bindex 572 bitset_stats_list (bitset bset, bitset_bindex *list, 573 bitset_bindex num, bitset_bindex *next) 574 { 575 bitset_bindex count; 576 bitset_bindex tmp; 577 bitset_bindex size; 578 bitset_bindex i; 579 580 count = BITSET_LIST_ (bset->s.bset, list, num, next); 581 582 BITSET_STATS_LISTS_INC (bset->s.bset); 583 584 /* Log histogram of number of set bits. */ 585 for (i = 0, tmp = count; tmp; tmp >>= 1, i++) 586 continue; 587 if (i >= BITSET_LOG_COUNT_BINS) 588 i = BITSET_LOG_COUNT_BINS - 1; 589 BITSET_STATS_LIST_COUNTS_INC (bset->s.bset, i); 590 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++) 594 continue; 595 if (i >= BITSET_LOG_SIZE_BINS) 596 i = BITSET_LOG_SIZE_BINS - 1; 597 BITSET_STATS_LIST_SIZES_INC (bset->s.bset, i); 598 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); 604 return count; 605 } 606 607 608 static bitset_bindex 609 bitset_stats_list_reverse (bitset bset, bitset_bindex *list, 610 bitset_bindex num, bitset_bindex *next) 611 { 612 return BITSET_LIST_REVERSE_ (bset->s.bset, list, num, next); 613 } 614 615 616 static void 617 bitset_stats_free (bitset bset) 618 { 619 BITSET_STATS_FREES_INC (bset->s.bset); 620 BITSET_FREE_ (bset->s.bset); 621 } 622 623 624 struct bitset_vtable bitset_stats_vtable = { 625 bitset_stats_set, 626 bitset_stats_reset, 627 bitset_stats_toggle, 628 bitset_stats_test, 629 bitset_stats_resize, 630 bitset_stats_size, 631 bitset_stats_count, 632 bitset_stats_empty_p, 633 bitset_stats_ones, 634 bitset_stats_zero, 635 bitset_stats_copy, 636 bitset_stats_disjoint_p, 637 bitset_stats_equal_p, 638 bitset_stats_not, 639 bitset_stats_subset_p, 640 bitset_stats_and, 641 bitset_stats_and_cmp, 642 bitset_stats_andn, 643 bitset_stats_andn_cmp, 644 bitset_stats_or, 645 bitset_stats_or_cmp, 646 bitset_stats_xor, 647 bitset_stats_xor_cmp, 648 bitset_stats_and_or, 649 bitset_stats_and_or_cmp, 650 bitset_stats_andn_or, 651 bitset_stats_andn_or_cmp, 652 bitset_stats_or_and, 653 bitset_stats_or_and_cmp, 654 bitset_stats_list, 655 bitset_stats_list_reverse, 656 bitset_stats_free, 657 BITSET_STATS 658 }; 659 660 661 /* Return enclosed bitset type. */ 662 enum bitset_type 663 bitset_stats_type_get (bitset bset) 664 { 665 return BITSET_TYPE_ (bset->s.bset); 666 } 667 668 669 size_t 670 bitset_stats_bytes (void) 671 { 672 return sizeof (struct bitset_stats_struct); 673 } 674 675 676 bitset 677 bitset_stats_init (bitset bset, bitset_bindex n_bits, enum bitset_type type) 678 { 679 size_t bytes; 680 bitset sbset; 681 682 bset->b.vtable = &bitset_stats_vtable; 683 684 /* Disable cache. */ 685 bset->b.cindex = 0; 686 bset->b.csize = 0; 687 bset->b.cdata = 0; 688 689 BITSET_NBITS_ (bset) = n_bits; 690 691 /* Set up the actual bitset implementation that 692 we are a wrapper over. */ 693 switch (type) 694 { 695 default: 696 abort (); 697 698 case BITSET_ARRAY: 699 bytes = abitset_bytes (n_bits); 700 sbset = xcalloc (1, bytes); 701 abitset_init (sbset, n_bits); 702 break; 703 704 case BITSET_LIST: 705 bytes = lbitset_bytes (n_bits); 706 sbset = xcalloc (1, bytes); 707 lbitset_init (sbset, n_bits); 708 break; 709 710 case BITSET_TABLE: 711 bytes = ebitset_bytes (n_bits); 712 sbset = xcalloc (1, bytes); 713 ebitset_init (sbset, n_bits); 714 break; 715 716 case BITSET_VARRAY: 717 bytes = vbitset_bytes (n_bits); 718 sbset = xcalloc (1, bytes); 719 vbitset_init (sbset, n_bits); 720 break; 721 } 722 723 bset->s.bset = sbset; 724 725 BITSET_STATS_ALLOCS_INC (type); 726 727 return bset; 728 } 729