]>
Commit | Line | Data |
---|---|---|
7086e707 AD |
1 | /* General bitsets. |
2 | Copyright (C) 2002 Free Software Foundation, Inc. | |
3 | Contributed by Michael Hayes (m.hayes@elec.canterbury.ac.nz). | |
4 | ||
5 | This program is free software; you can redistribute it and/or modify | |
6 | it under the terms of the GNU General Public License as published by | |
7 | the Free Software Foundation; either version 2 of the License, or | |
8 | (at your option) any later version. | |
9 | ||
10 | This program is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | GNU General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU General Public License | |
16 | along with this program; if not, write to the Free Software | |
17 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | |
18 | ||
19 | #ifdef HAVE_CONFIG_H | |
20 | #include "config.h" | |
21 | #endif | |
22 | ||
23 | #include <stdlib.h> | |
24 | #include "bitset.h" | |
25 | #include "obstack.h" | |
26 | ||
27 | static void bitset_print PARAMS ((FILE *, bitset, int)); | |
28 | ||
29 | #if BITSET_CHECK | |
30 | #define BITSET__CHECK2(DST, SRC) \ | |
31 | if ((DST)->OPS != (SRC)->OPS) abort (); | |
32 | ||
33 | #define BITSET__CHECK3(DST, SRC1, SRC2) \ | |
34 | if ((DST)->OPS != (SRC1)->OPS || (DST)->OPS != (SRC2)->OPS) abort (); | |
35 | ||
36 | #define BITSET__CHECK4(DST, SRC1, SRC2) \ | |
37 | if ((DST)->OPS != (SRC1)->OPS || (DST)->OPS != (SRC2)->OPS \ | |
38 | || (DST)->OPS != (SRC3)->OPS) abort (); | |
39 | #else | |
40 | #define BITSET__CHECK2(DST, SRC) | |
41 | ||
42 | #define BITSET__CHECK3(DST, SRC1, SRC2) | |
43 | ||
44 | #define BITSET__CHECK4(DST, SRC1, SRC2, SRC3) | |
45 | #endif | |
46 | ||
47 | #if BITSET_STATS | |
48 | #define BITSET_STATS_FILE "bitset.dat" | |
49 | ||
50 | #define BITSET_LOG_COUNT_BINS 10 | |
51 | #define BITSET_LOG_SIZE_BINS 16 | |
52 | #define BITSET_DENSITY_BINS 20 | |
53 | ||
54 | struct bitset_type_stats_struct | |
55 | { | |
56 | unsigned int xmallocs; | |
57 | unsigned int xfrees; | |
58 | unsigned int oballocs; | |
59 | unsigned int obfrees; | |
60 | unsigned int lists; | |
61 | unsigned int list_counts[BITSET_LOG_COUNT_BINS]; | |
62 | unsigned int list_sizes[BITSET_LOG_SIZE_BINS]; | |
63 | unsigned int list_density[BITSET_DENSITY_BINS]; | |
64 | }; | |
65 | ||
66 | struct bitset_stats_struct | |
67 | { | |
68 | unsigned int runs; | |
69 | struct bitset_type_stats_struct types[BITSET_TYPE_NUM]; | |
70 | }; | |
71 | ||
72 | struct bitset_stats_struct bitset_stats_data; | |
73 | struct bitset_stats_struct *bitset_stats; | |
74 | ||
75 | static void bitset_percent_histogram_print PARAMS ((FILE *, const char *, | |
76 | const char *, | |
77 | unsigned int, | |
78 | unsigned int *)); | |
79 | static void bitset_log_histogram_print PARAMS ((FILE *, const char *, | |
80 | const char *, | |
81 | unsigned int, unsigned int *)); | |
82 | static void bitset_stats_print_1 PARAMS ((FILE *, const char *, | |
83 | struct bitset_type_stats_struct *)); | |
84 | static void bitset_stats_print PARAMS ((FILE *, int)); | |
85 | static void bitset_stats_read PARAMS ((void)); | |
86 | static void bitset_stats_write PARAMS ((void)); | |
87 | ||
88 | #define BITSET_STATS_XMALLOCS_INC(TYPE) \ | |
89 | if (bitset_stats) \ | |
90 | bitset_stats->types[(TYPE)].xmallocs++ | |
91 | ||
92 | #define BITSET_STATS_XFREES_INC(BSET) \ | |
93 | if (bitset_stats) \ | |
94 | bitset_stats->types[(BSET)->ops->type].xfrees++ | |
95 | ||
96 | #define BITSET_STATS_OBALLOCS_INC(TYPE) \ | |
97 | if (bitset_stats) \ | |
98 | bitset_stats->types[(TYPE)].oballocs++ | |
99 | ||
100 | #define BITSET_STATS_OBFREES_INC(BSET) \ | |
101 | if (bitset_stats) \ | |
102 | bitset_stats->types[(BSET)->ops->type].obfrees++ | |
103 | ||
104 | #define BITSET_STATS_LISTS_INC(BSET) \ | |
105 | if (bitset_stats) \ | |
106 | bitset_stats->types[(BSET)->ops->type].lists++ | |
107 | ||
108 | #define BITSET_STATS_LIST_COUNTS_INC(BSET, I) \ | |
109 | if (bitset_stats) \ | |
110 | bitset_stats->types[(BSET)->ops->type].list_counts[(I)]++ | |
111 | ||
112 | #define BITSET_STATS_LIST_SIZES_INC(BSET, I) \ | |
113 | if (bitset_stats) \ | |
114 | bitset_stats->types[(BSET)->ops->type].list_sizes[(I)]++ | |
115 | ||
116 | #define BITSET_STATS_LIST_DENSITY_INC(BSET, I) \ | |
117 | if (bitset_stats) \ | |
118 | bitset_stats->types[(BSET)->ops->type].list_density[(I)]++ | |
119 | ||
120 | #else | |
121 | #define BITSET_STATS_XMALLOCS_INC(TYPE) | |
122 | ||
123 | #define BITSET_STATS_XFREES_INC(BSET) | |
124 | ||
125 | #define BITSET_STATS_OBALLOCS_INC(TYPE) | |
126 | ||
127 | #define BITSET_STATS_OBFREES_INC(BSET) | |
128 | ||
129 | #define BITSET_STATS_LISTS_INC(BSET) | |
130 | ||
131 | #define BITSET_STATS_LIST_COUNTS_INC(BSET, I) | |
132 | ||
133 | #define BITSET_STATS_LIST_SIZES_INC(BSET, I) | |
134 | ||
135 | #define BITSET_STATS_LIST_DENSITY_INC(BSET, I) | |
136 | #endif /* BITSET_STATS */ | |
137 | ||
138 | ||
139 | ||
140 | /* Return number of bytes required to create a N_BIT bitset | |
141 | of TYPE. The bitset may grow to require more bytes than this. */ | |
142 | int | |
143 | bitset_bytes (type, n_bits) | |
144 | enum bitset_type type; | |
145 | bitset_bindex n_bits; | |
146 | { | |
147 | unsigned int bytes; | |
148 | ||
149 | switch (type) | |
150 | { | |
151 | case BITSET_ARRAY: | |
152 | bytes = sbitset_bytes (n_bits); | |
153 | break; | |
154 | ||
155 | case BITSET_LIST: | |
156 | bytes = lbitset_bytes (n_bits); | |
157 | break; | |
158 | ||
159 | case BITSET_TABLE: | |
160 | bytes = ebitset_bytes (n_bits); | |
161 | break; | |
162 | ||
163 | default: | |
164 | abort (); | |
165 | } | |
166 | ||
167 | return bytes; | |
168 | } | |
169 | ||
170 | ||
171 | /* Initialise bitset BSET of TYPE for N_BITS. */ | |
172 | bitset | |
173 | bitset_init (bset, n_bits, type) | |
174 | bitset bset; | |
175 | bitset_bindex n_bits; | |
176 | enum bitset_type type; | |
177 | { | |
178 | switch (type) | |
179 | { | |
180 | case BITSET_ARRAY: | |
181 | return sbitset_init (bset, n_bits); | |
182 | ||
183 | case BITSET_LIST: | |
184 | return lbitset_init (bset, n_bits); | |
185 | ||
186 | case BITSET_TABLE: | |
187 | return ebitset_init (bset, n_bits); | |
188 | ||
189 | default: | |
190 | abort (); | |
191 | } | |
192 | } | |
193 | ||
194 | ||
195 | /* Select a bitset type for a set of N_BITS and with attribute hints | |
196 | specified by ATTR. For variable size bitsets, N_BITS is only a | |
197 | hint and may be zero. */ | |
198 | enum bitset_type | |
199 | bitset_type_choose (n_bits, attr) | |
200 | bitset_bindex n_bits ATTRIBUTE_UNUSED; | |
201 | unsigned int attr; | |
202 | { | |
203 | enum bitset_type type; | |
204 | ||
205 | #ifdef ENABLE_CHECKING | |
206 | /* Check attributes. */ | |
207 | if (attr & BITSET_FIXED && attr & BITSET_VARIABLE) | |
208 | abort (); | |
209 | if (attr & BITSET_SPARSE && attr & BITSET_DENSE) | |
210 | abort (); | |
211 | ||
212 | /* Note that sometimes we will be asked for a zero length | |
213 | fixed size bitset. */ | |
214 | #endif | |
215 | ||
216 | /* Choose the type of bitset. */ | |
217 | ||
218 | type = BITSET_ARRAY; | |
219 | /* Currently, the simple bitsets do not support a variable size. */ | |
220 | if (attr & BITSET_VARIABLE || attr & BITSET_SPARSE) | |
221 | { | |
222 | type = BITSET_LIST; | |
223 | if (attr & BITSET_DENSE || attr & BITSET_GREEDY) | |
224 | type = BITSET_TABLE; | |
225 | } | |
226 | ||
227 | return type; | |
228 | } | |
229 | ||
230 | ||
231 | /* Create a bitset of N_BITS of type TYPE. */ | |
232 | bitset | |
233 | bitset_alloc (n_bits, type) | |
234 | bitset_bindex n_bits; | |
235 | enum bitset_type type; | |
236 | { | |
237 | unsigned int bytes; | |
238 | bitset bset; | |
239 | ||
240 | BITSET_STATS_XMALLOCS_INC (type); | |
241 | ||
242 | bytes = bitset_bytes (type, n_bits); | |
243 | ||
244 | bset = (bitset) xmalloc (bytes); | |
245 | ||
246 | return bitset_init (bset, n_bits, type); | |
247 | } | |
248 | ||
249 | ||
250 | /* Create a bitset of N_BITS of type TYPE. */ | |
251 | bitset | |
252 | bitset_obstack_alloc (bobstack, n_bits, type) | |
253 | struct obstack *bobstack; | |
254 | bitset_bindex n_bits; | |
255 | enum bitset_type type; | |
256 | { | |
257 | unsigned int bytes; | |
258 | ||
259 | BITSET_STATS_OBALLOCS_INC (type); | |
260 | ||
261 | bytes = bitset_bytes (type, n_bits); | |
262 | ||
263 | return bitset_init (obstack_alloc (bobstack, bytes), n_bits, type); | |
264 | } | |
265 | ||
266 | ||
267 | /* Create a bitset of N_BITS and with attribute hints specified by | |
268 | ATTR. */ | |
269 | bitset | |
270 | bitset_create (n_bits, attr) | |
271 | bitset_bindex n_bits; | |
272 | unsigned int attr; | |
273 | { | |
274 | enum bitset_type type; | |
275 | ||
276 | type = bitset_type_choose (n_bits, attr); | |
277 | ||
278 | return bitset_alloc (n_bits, type); | |
279 | } | |
280 | ||
281 | ||
282 | /* Free bitset BSET. */ | |
283 | void | |
284 | bitset_free (bset) | |
285 | bitset bset; | |
286 | { | |
287 | BITSET_STATS_XFREES_INC (bset); | |
288 | ||
289 | if (bset->ops->free) | |
290 | BITSET__FREE (bset); | |
291 | ||
292 | bset->ops = NULL; | |
293 | free (bset); | |
294 | } | |
295 | ||
296 | ||
297 | /* Free bitset BSET allocated on obstack. */ | |
298 | void | |
299 | bitset_obstack_free (bset) | |
300 | bitset bset; | |
301 | { | |
302 | BITSET_STATS_OBFREES_INC (bset); | |
303 | ||
304 | if (bset->ops->free) | |
305 | BITSET__FREE (bset); | |
306 | bset->ops = NULL; | |
307 | } | |
308 | ||
309 | ||
310 | /* Find next bit set in SRC starting from and including BITNO. | |
311 | Return -1 if SRC empty. */ | |
312 | int | |
313 | bitset_next (src, bitno) | |
314 | bitset src; | |
315 | bitset_bindex bitno; | |
316 | { | |
317 | bitset_bindex val; | |
318 | bitset_bindex next = bitno; | |
319 | ||
320 | if (!bitset_list (src, &val, 1, &next)) | |
321 | return -1; | |
322 | return val; | |
323 | } | |
324 | ||
325 | ||
326 | /* Find previous bit set in SRC starting from and including BITNO. | |
327 | Return -1 if SRC empty. */ | |
328 | int | |
329 | bitset_prev (src, bitno) | |
330 | bitset src; | |
331 | bitset_bindex bitno; | |
332 | { | |
333 | bitset_bindex val; | |
334 | bitset_bindex next = bitno; | |
335 | ||
336 | if (!bitset_reverse_list (src, &val, 1, &next)) | |
337 | return -1; | |
338 | return val; | |
339 | } | |
340 | ||
341 | ||
342 | /* Find first set bit. */ | |
343 | int | |
344 | bitset_first (src) | |
345 | bitset src; | |
346 | { | |
347 | return bitset_next (src, 0); | |
348 | } | |
349 | ||
350 | ||
351 | /* Find last set bit. */ | |
352 | int | |
353 | bitset_last (src) | |
354 | bitset src; | |
355 | { | |
356 | return bitset_prev (src, 0); | |
357 | } | |
358 | ||
359 | ||
360 | static void | |
361 | bitset_print (file, bset, verbose) | |
362 | FILE *file; | |
363 | bitset bset; | |
364 | int verbose; | |
365 | { | |
366 | unsigned int i, pos; | |
367 | ||
368 | if (verbose) | |
369 | fprintf (file, "n_bits = %d, set = {", bitset_size (bset)); | |
370 | ||
371 | pos = 30; | |
372 | BITSET_EXECUTE (bset, 0, i, | |
373 | { | |
374 | if (pos > 70) | |
375 | { | |
376 | fprintf (file, "\n"); | |
377 | pos = 0; | |
378 | } | |
379 | ||
380 | fprintf (file, "%d ", i); | |
381 | pos += 1 + (i >= 10) + (i >= 100); | |
382 | }); | |
383 | ||
384 | if (verbose) | |
385 | fprintf (file, "}\n"); | |
386 | } | |
387 | ||
388 | ||
389 | int | |
390 | bitset_copy (dst, src) | |
391 | bitset dst; | |
392 | bitset src; | |
393 | { | |
394 | unsigned int i; | |
395 | ||
396 | if (dst->ops == src->ops) | |
397 | return BITSET__COPY (dst, src); | |
398 | ||
399 | /* Convert bitset types. We assume that the DST bitset | |
400 | is large enough to hold the SRC bitset. */ | |
401 | bitset_zero (dst); | |
402 | BITSET_EXECUTE (src, 0, i, | |
403 | { | |
404 | bitset_set (dst, i); | |
405 | }); | |
406 | ||
407 | return 1; | |
408 | } | |
409 | ||
410 | ||
411 | /* Return size in bits of bitset SRC. */ | |
412 | int | |
413 | bitset_size (src) | |
414 | bitset src; | |
415 | { | |
416 | return BITSET__SIZE (src); | |
417 | } | |
418 | ||
419 | ||
420 | /* DST = 0. */ | |
421 | int | |
422 | bitset_zero (dst) | |
423 | bitset dst; | |
424 | { | |
425 | return BITSET__OP1 (dst, BITSET_ZERO); | |
426 | } | |
427 | ||
428 | ||
429 | /* DST = ~0. */ | |
430 | int | |
431 | bitset_ones (dst) | |
432 | bitset dst; | |
433 | { | |
434 | return BITSET__OP1 (dst, BITSET_ONES); | |
435 | } | |
436 | ||
437 | ||
438 | /* Return non-zero if all bits in bitset SRC are reset. */ | |
439 | int | |
440 | bitset_empty_p (src) | |
441 | bitset src; | |
442 | { | |
443 | return BITSET__OP1 (src, BITSET_EMPTY_P); | |
444 | } | |
445 | ||
446 | ||
447 | /* Return DST == DST | SRC. */ | |
448 | int | |
449 | bitset_subset_p (dst, src) | |
450 | bitset dst; | |
451 | bitset src; | |
452 | { | |
453 | return BITSET__OP2 (dst, src, BITSET_SUBSET_P); | |
454 | } | |
455 | ||
456 | ||
457 | /* Return DST == SRC. */ | |
458 | int | |
459 | bitset_equal_p (dst, src) | |
460 | bitset dst; | |
461 | bitset src; | |
462 | { | |
463 | BITSET__CHECK2 (dst, src); | |
464 | return BITSET__OP2 (dst, src, BITSET_EQUAL_P); | |
465 | } | |
466 | ||
467 | ||
468 | /* DST = ~SRC. */ | |
469 | int | |
470 | bitset_not (dst, src) | |
471 | bitset dst; | |
472 | bitset src; | |
473 | { | |
474 | BITSET__CHECK2 (dst, src); | |
475 | return BITSET__OP2 (dst, src, BITSET_NOT); | |
476 | } | |
477 | ||
478 | ||
479 | /* DST = SRC1 | SRC2. Return non-zero if DST != SRC1 | SRC2. */ | |
480 | int | |
481 | bitset_or (dst, src1, src2) | |
482 | bitset dst; | |
483 | bitset src1; | |
484 | bitset src2; | |
485 | { | |
486 | BITSET__CHECK3 (dst, src1, src2); | |
487 | return BITSET__OP3 (dst, src1, src2, BITSET_OR); | |
488 | } | |
489 | ||
490 | ||
491 | /* DST = SRC1 & SRC2. Return non-zero if DST != SRC1 & SRC2. */ | |
492 | int | |
493 | bitset_and (dst, src1, src2) | |
494 | bitset dst; | |
495 | bitset src1; | |
496 | bitset src2; | |
497 | { | |
498 | BITSET__CHECK3 (dst, src1, src2); | |
499 | return BITSET__OP3 (dst, src1, src2, BITSET_AND); | |
500 | } | |
501 | ||
502 | ||
503 | /* DST = SRC1 ^ SRC2. Return non-zero if DST != SRC1 ^ SRC2. */ | |
504 | int | |
505 | bitset_xor (dst, src1, src2) | |
506 | bitset dst; | |
507 | bitset src1; | |
508 | bitset src2; | |
509 | { | |
510 | BITSET__CHECK3 (dst, src1, src2); | |
511 | return BITSET__OP3 (dst, src1, src2, BITSET_XOR); | |
512 | } | |
513 | ||
514 | ||
515 | /* DST = SRC1 & ~SRC2. Return non-zero if DST != SRC1 & ~SRC2. */ | |
516 | int | |
517 | bitset_andn (dst, src1, src2) | |
518 | bitset dst; | |
519 | bitset src1; | |
520 | bitset src2; | |
521 | { | |
522 | BITSET__CHECK3 (dst, src1, src2); | |
523 | return BITSET__OP3 (dst, src1, src2, BITSET_ANDN); | |
524 | } | |
525 | ||
526 | ||
527 | /* DST = SRC1 | ~SRC2. Return non-zero if DST != SRC1 | ~SRC2. */ | |
528 | int | |
529 | bitset_orn (dst, src1, src2) | |
530 | bitset dst; | |
531 | bitset src1; | |
532 | bitset src2; | |
533 | { | |
534 | BITSET__CHECK3 (dst, src1, src2); | |
535 | return BITSET__OP3 (dst, src1, src2, BITSET_ORN); | |
536 | } | |
537 | ||
538 | ||
539 | /* DST = (SRC1 | SRC2) & SRC3. Return non-zero if | |
540 | DST != (SRC1 | SRC2) & SRC3. */ | |
541 | int | |
542 | bitset_or_and (dst, src1, src2, src3) | |
543 | bitset dst; | |
544 | bitset src1; | |
545 | bitset src2; | |
546 | bitset src3; | |
547 | { | |
548 | BITSET__CHECK4 (dst, src1, src2, src3); | |
549 | return BITSET__OP4 (dst, src1, src2, src3, BITSET_OR_AND); | |
550 | } | |
551 | ||
552 | ||
553 | /* DST = (SRC1 & SRC2) | SRC3. Return non-zero if | |
554 | DST != (SRC1 & SRC2) | SRC3. */ | |
555 | int | |
556 | bitset_and_or (dst, src1, src2, src3) | |
557 | bitset dst; | |
558 | bitset src1; | |
559 | bitset src2; | |
560 | bitset src3; | |
561 | { | |
562 | BITSET__CHECK4 (dst, src1, src2, src3); | |
563 | return BITSET__OP4 (dst, src1, src2, src3, BITSET_AND_OR); | |
564 | } | |
565 | ||
566 | ||
567 | /* Dump bitset BSET to FILE. */ | |
568 | void | |
569 | bitset_dump (file, bset) | |
570 | FILE *file; | |
571 | bitset bset; | |
572 | { | |
573 | bitset_print (file, bset, 0); | |
574 | } | |
575 | ||
576 | ||
577 | /* Function to be called from debugger to print bitset. */ | |
578 | void | |
579 | debug_bitset (bset) | |
580 | bitset bset; | |
581 | { | |
582 | bitset_print (stderr, bset, 1); | |
583 | } | |
584 | ||
585 | ||
586 | /* Release memory associated with bitsets. */ | |
587 | void | |
588 | bitset_release_memory () | |
589 | { | |
590 | lbitset_release_memory (); | |
591 | ebitset_release_memory (); | |
592 | } | |
593 | ||
594 | ||
595 | #if BITSET_STATS | |
596 | int | |
597 | bitset_list (bset, list, num, next) | |
598 | bitset bset; | |
599 | bitset_bindex *list; | |
600 | bitset_bindex num; | |
601 | bitset_bindex *next; | |
602 | { | |
603 | bitset_bindex count; | |
604 | ||
605 | count = BITSET__LIST (bset, list, num, next); | |
606 | ||
607 | if (bitset_stats) | |
608 | { | |
609 | bitset_bindex tmp; | |
610 | bitset_bindex size; | |
611 | bitset_bindex i; | |
612 | enum bitset_type type; | |
613 | ||
614 | type = bset->ops->type; | |
615 | BITSET_STATS_LISTS_INC (bset); | |
616 | ||
617 | /* Log histogram of number of set bits. */ | |
618 | for (i = 0, tmp = count; tmp; tmp >>= 1, i++) | |
619 | continue; | |
620 | if (i >= BITSET_LOG_COUNT_BINS) | |
621 | i = BITSET_LOG_COUNT_BINS - 1; | |
622 | BITSET_STATS_LIST_COUNTS_INC (bset, i); | |
623 | ||
624 | /* Log histogram of number of bits in set. */ | |
625 | size = bitset_size (bset); | |
626 | for (i = 0, tmp = size; tmp; tmp >>= 1, i++) | |
627 | continue; | |
628 | if (i >= BITSET_LOG_SIZE_BINS) | |
629 | i = BITSET_LOG_SIZE_BINS - 1; | |
630 | BITSET_STATS_LIST_SIZES_INC (bset, i); | |
631 | ||
632 | /* Histogram of fraction of bits set. */ | |
633 | i = size ? (count * BITSET_DENSITY_BINS) / size : 0; | |
634 | if (i >= BITSET_DENSITY_BINS) | |
635 | i = BITSET_DENSITY_BINS - 1; | |
636 | BITSET_STATS_LIST_DENSITY_INC (bset, i); | |
637 | } | |
638 | return count; | |
639 | } | |
640 | ||
641 | ||
642 | /* Print a percentage histogram with message MSG to FILE. */ | |
643 | static void | |
644 | bitset_percent_histogram_print (file, name, msg, n_bins, bins) | |
645 | FILE *file; | |
646 | const char *name; | |
647 | const char *msg; | |
648 | unsigned int n_bins; | |
649 | unsigned int *bins; | |
650 | { | |
651 | unsigned int i; | |
652 | unsigned int total; | |
653 | ||
654 | total = 0; | |
655 | for (i = 0; i < n_bins; i++) | |
656 | total += bins[i]; | |
657 | ||
658 | if (!total) | |
659 | return; | |
660 | ||
661 | fprintf (file, "%s %s", name, msg); | |
662 | for (i = 0; i < n_bins; i++) | |
663 | fprintf (file, "%.0f-%.0f%%\t%8d (%5.1f%%)\n", | |
664 | i * 100.0 / n_bins, | |
665 | (i + 1) * 100.0 / n_bins, | |
666 | bins[i], (100.0 * bins[i]) / total); | |
667 | } | |
668 | ||
669 | ||
670 | /* Print a log histogram with message MSG to FILE. */ | |
671 | static void | |
672 | bitset_log_histogram_print (file, name, msg, n_bins, bins) | |
673 | FILE *file; | |
674 | const char *name; | |
675 | const char *msg; | |
676 | unsigned int n_bins; | |
677 | unsigned int *bins; | |
678 | { | |
679 | unsigned int i; | |
680 | unsigned int total; | |
681 | unsigned int max_width; | |
682 | ||
683 | total = 0; | |
684 | for (i = 0; i < n_bins; i++) | |
685 | total += bins[i]; | |
686 | ||
687 | if (!total) | |
688 | return; | |
689 | ||
690 | /* 2 * ceil (log10(2) * (N - 1)) + 1 */ | |
691 | max_width = 2 * (unsigned int)(0.30103 * (n_bins - 1) + 0.9999) + 1; | |
692 | ||
693 | fprintf (file, "%s %s", name, msg); | |
694 | for (i = 0; i < 2; i++) | |
695 | fprintf (file, "%*d\t%8d (%5.1f%%)\n", | |
696 | max_width, i, bins[i], 100.0 * bins[i] / total); | |
697 | ||
698 | /* Perhaps we should bail out once the histogram goes to zero. */ | |
699 | for (; i < n_bins; i++) | |
700 | fprintf (file, "%*d-%d\t%8d (%5.1f%%)\n", | |
701 | max_width - ((unsigned int) (0.30103 * (i) + 0.9999) + 1), | |
702 | 1 << (i - 1), (1 << i) - 1, bins[i], (100.0 * bins[i]) / total); | |
703 | } | |
704 | ||
705 | ||
706 | /* Print bitset statistics to FILE. */ | |
707 | static void | |
708 | bitset_stats_print_1 (file, name, stats) | |
709 | FILE *file; | |
710 | const char *name; | |
711 | struct bitset_type_stats_struct *stats; | |
712 | { | |
713 | if (!stats) | |
714 | return; | |
715 | ||
716 | fprintf (file, "%d %ss xmalloced, %d freed.\n", | |
717 | stats->xmallocs, name, stats->xfrees); | |
718 | fprintf (file, "%d %ss oballoced, %d freed.\n", | |
719 | stats->oballocs, name, stats->obfrees); | |
720 | ||
721 | fprintf (file, "%d bitset_lists\n", stats->lists); | |
722 | ||
723 | bitset_log_histogram_print (file, name, "count log histogram\n", | |
724 | BITSET_LOG_COUNT_BINS, stats->list_counts); | |
725 | ||
726 | bitset_log_histogram_print (file, name, "size log histogram\n", | |
727 | BITSET_LOG_SIZE_BINS, stats->list_sizes); | |
728 | ||
729 | bitset_percent_histogram_print (file, name, "density histogram\n", | |
730 | BITSET_DENSITY_BINS, stats->list_density); | |
731 | } | |
732 | ||
733 | ||
734 | /* Print all bitset statistics to FILE. */ | |
735 | static void | |
736 | bitset_stats_print (file, verbose) | |
737 | FILE *file; | |
738 | int verbose ATTRIBUTE_UNUSED; | |
739 | { | |
740 | int i; | |
741 | static const char *names[] = BITSET__TYPE_NAMES; | |
742 | ||
743 | if (!bitset_stats) | |
744 | return; | |
745 | ||
746 | fprintf (file, "Bitset statistics:\n\n"); | |
747 | ||
748 | if (bitset_stats->runs > 1) | |
749 | fprintf (file, "Accumulated runs = %d\n", bitset_stats->runs); | |
750 | ||
751 | for (i = 0; i < BITSET_TYPE_NUM; i++) | |
752 | bitset_stats_print_1 (file, names[i], &bitset_stats->types[i]); | |
753 | } | |
754 | #endif /* BITSET_STATS */ | |
755 | ||
756 | ||
757 | /* Initialise bitset statistics logging. */ | |
758 | void | |
759 | bitset_stats_init () | |
760 | { | |
761 | #if BITSET_STATS | |
762 | bitset_stats = &bitset_stats_data; | |
763 | bitset_stats_read (); | |
764 | #endif /* BITSET_STATS */ | |
765 | } | |
766 | ||
767 | ||
768 | /* Read bitset statistics file. */ | |
769 | static void | |
770 | bitset_stats_read () | |
771 | { | |
772 | FILE *file; | |
773 | ||
774 | if (!bitset_stats) | |
775 | return; | |
776 | ||
777 | file = fopen (BITSET_STATS_FILE, "r"); | |
778 | if (file) | |
779 | { | |
780 | if (fread (&bitset_stats_data, sizeof (bitset_stats_data), | |
781 | 1, file) != 1) | |
782 | { | |
783 | if (ferror (file)) | |
784 | perror ("Could not read stats file"); | |
785 | else | |
786 | fprintf (stderr, "Bad stats file size\n"); | |
787 | } | |
788 | fclose (file); | |
789 | } | |
790 | bitset_stats_data.runs++; | |
791 | } | |
792 | ||
793 | ||
794 | /* Write bitset statistics file. */ | |
795 | static void | |
796 | bitset_stats_write () | |
797 | { | |
798 | FILE *file; | |
799 | ||
800 | if (!bitset_stats) | |
801 | return; | |
802 | ||
803 | file = fopen (BITSET_STATS_FILE, "w"); | |
804 | if (file) | |
805 | { | |
806 | if (fwrite (&bitset_stats_data, sizeof (bitset_stats_data), | |
807 | 1, file) != 1) | |
808 | perror ("Could not write stats file"); | |
809 | fclose (file); | |
810 | } | |
811 | else | |
812 | perror ("Could not open stats file for writing"); | |
813 | } | |
814 | ||
815 | ||
816 | /* Dump bitset statistics to FILE. */ | |
817 | void | |
818 | bitset_stats_dump (file) | |
819 | FILE *file; | |
820 | { | |
821 | #if BITSET_STATS | |
822 | bitset_stats_print (file, 0); | |
823 | bitset_stats_write (); | |
824 | #endif /* BITSET_STATS */ | |
825 | } | |
826 | ||
827 | ||
828 | /* Function to be called from debugger to print bitset stats. */ | |
829 | void | |
830 | debug_bitset_stats (void) | |
831 | { | |
832 | #if BITSET_STATS | |
833 | bitset_stats_print (stderr, 1); | |
834 | #endif /* BITSET_STATS */ | |
835 | } |