Good day and welcome to the FIRM XMALLOC*() macros. These macros are provided for...
[libfirm] / ir / stat / distrib.c
1 /*
2  * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
3  *
4  * This file is part of libFirm.
5  *
6  * This file may be distributed and/or modified under the terms of the
7  * GNU General Public License version 2 as published by the Free Software
8  * Foundation and appearing in the file LICENSE.GPL included in the
9  * packaging of this file.
10  *
11  * Licensees holding valid libFirm Professional Edition licenses may use
12  * this file in accordance with the libFirm Commercial License.
13  * Agreement provided with the Software.
14  *
15  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE.
18  */
19
20 /**
21  * @file
22  * @brief   Statistics for Firm. Distribution tables.
23  * @author  Michael Beck
24  * @version $Id$
25  */
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include "hashptr.h"
31 #include "irtools.h"
32 #include "xmalloc.h"
33 #include "firmstat_t.h"
34
35 /**
36  * calculates a hash value for an address
37  */
38 static unsigned addr_hash(const void *object) {
39         return HASH_PTR(object);
40 }
41
42 /**
43  * calculates a hash value for an integer
44  */
45 static unsigned int_hash(const void *object) {
46         return (unsigned)PTR_TO_INT(object);
47 }
48
49 /**
50  * compare function for integer distribution tables
51  */
52 static int int_cmp_fun(const void *elt, const void *key) {
53         const distrib_entry_t *p1 = elt;
54         const distrib_entry_t *p2 = key;
55
56         return (char *)p1->object - (char *)p2->object;
57 }
58
59 /*
60  * create a new distribution table
61  */
62 distrib_tbl_t *stat_new_distrib_tbl(pset_cmp_fun cmp_func, distrib_hash_fun hash_func) {
63         distrib_tbl_t *res = XMALLOC(distrib_tbl_t);
64
65         obstack_init(&res->cnts);
66
67         /* create the hash-table */
68         res->hash_map  = new_pset(cmp_func, 8);
69         res->hash_func = hash_func ? hash_func : addr_hash;
70         res->int_dist  = 0;
71
72         return res;
73 }
74
75 /*
76  * create a new distribution table for an integer distribution
77  */
78 distrib_tbl_t *stat_new_int_distrib_tbl(void) {
79         distrib_tbl_t *res = stat_new_distrib_tbl(int_cmp_fun, int_hash);
80
81         if (res)
82                 res->int_dist = 1;
83
84         return res;
85 }
86
87 /*
88  * destroy a distribution table
89  */
90 void stat_delete_distrib_tbl(distrib_tbl_t *tbl) {
91         if (tbl) {
92                 /* free all entries */
93                 obstack_free(&tbl->cnts, NULL);
94
95                 /* delete the hash table */
96                 del_pset(tbl->hash_map);
97         }
98 }
99
100 /**
101  * Returns the associates distrib_entry_t for an object
102  */
103 static distrib_entry_t *distrib_get_entry(distrib_tbl_t *tbl, const void *object) {
104         distrib_entry_t key;
105         distrib_entry_t *elem;
106
107         key.object = object;
108
109         elem = pset_find(tbl->hash_map, &key, tbl->hash_func(object));
110         if (elem)
111                 return elem;
112
113         elem = obstack_alloc(&tbl->cnts, sizeof(*elem));
114
115         /* clear counter */
116         cnt_clr(&elem->cnt);
117
118         elem->object = object;
119
120         return pset_insert(tbl->hash_map, elem, tbl->hash_func(object));
121 }
122
123 /*
124  * adds a new object count into the distribution table
125  */
126 void stat_add_distrib_tbl(distrib_tbl_t *tbl, const void *object, const counter_t *cnt) {
127         distrib_entry_t *elem = distrib_get_entry(tbl, object);
128
129         cnt_add(&elem->cnt, cnt);
130 }
131
132 /*
133  * adds a new key count into the integer distribution table
134  */
135 void stat_add_int_distrib_tbl(distrib_tbl_t *tbl, int key, const counter_t *cnt) {
136         stat_add_distrib_tbl(tbl, INT_TO_PTR(key), cnt);
137 }
138
139 /*
140  * increases object count by one
141  */
142 void stat_inc_distrib_tbl(distrib_tbl_t *tbl, const void *object) {
143         distrib_entry_t *elem = distrib_get_entry(tbl, object);
144
145         cnt_inc(&elem->cnt);
146 }
147
148 /*
149  * increases key count by one
150  */
151 void stat_inc_int_distrib_tbl(distrib_tbl_t *tbl, int key) {
152         stat_inc_distrib_tbl(tbl, INT_TO_PTR(key));
153 }
154
155 /*
156  * inserts a new object with count 0 into the distribution table
157  * if object is already present, nothing happens
158  */
159 void stat_insert_distrib_tbl(distrib_tbl_t *tbl, const void *object) {
160         /* executed for side effect */
161         (void)distrib_get_entry(tbl, object);
162 }
163
164 /*
165  * inserts a new key with count 0 into the integer distribution table
166  * if key is already present, nothing happens
167  */
168 void stat_insert_int_distrib_tbl(distrib_tbl_t *tbl, int key) {
169         stat_insert_distrib_tbl(tbl, INT_TO_PTR(key));
170 }
171
172 /*
173  * returns the sum over all counters in a distribution table
174  */
175 int stat_get_count_distrib_tbl(distrib_tbl_t *tbl) {
176         distrib_entry_t *entry;
177         counter_t cnt = ZERO_CNT;
178
179         foreach_pset(tbl->hash_map, entry)
180                 cnt_add(&cnt, &entry->cnt);
181         return cnt_to_uint(&cnt);
182 }
183
184 /*
185  * calculates the mean value of a distribution
186  */
187 double stat_calc_mean_distrib_tbl(distrib_tbl_t *tbl) {
188         distrib_entry_t *entry;
189         unsigned count;
190         double sum;
191
192         if (tbl->int_dist) {
193                 /* integer distribution, need min, max */
194                 int min, max;
195
196                 entry = pset_first(tbl->hash_map);
197
198                 if (! entry)
199                         return 0.0;
200
201                 min =
202                 max = PTR_TO_INT(entry->object);
203                 sum = cnt_to_dbl(&entry->cnt);
204
205
206                 for (entry = pset_next(tbl->hash_map); entry; entry = pset_next(tbl->hash_map)) {
207                         int value = PTR_TO_INT(entry->object);
208
209                         if (value < min)
210                                 min = value;
211                         if (value > max)
212                                 max = value;
213
214                         sum += cnt_to_dbl(&entry->cnt);
215                 }
216                 count = max - min + 1;
217         } else {
218                 sum = 0.0;
219                 count = 0;
220                 foreach_pset(tbl->hash_map, entry) {
221                         sum += cnt_to_dbl(&entry->cnt);
222                         ++count;
223                 }
224         }
225
226         return count ? sum / (double)count : 0.0;
227 }
228
229 /*
230  * calculates the average value of a distribution
231  */
232 double stat_calc_avg_distrib_tbl(distrib_tbl_t *tbl) {
233         distrib_entry_t *entry;
234         unsigned        count = 0;
235         double          sum   = 0.0;
236
237         if (tbl->int_dist) {
238                 if (pset_count(tbl->hash_map) <= 0)
239                         return 0.0;
240
241                 foreach_pset(tbl->hash_map, entry) {
242                         sum   += cnt_to_dbl(&entry->cnt) * PTR_TO_INT(entry->object);
243                         count += cnt_to_uint(&entry->cnt);
244                 }
245         } else {
246                 foreach_pset(tbl->hash_map, entry) {
247                         sum += cnt_to_dbl(&entry->cnt);
248                         ++count;
249                 }
250         }
251
252         return count ? sum / (double)count : 0.0;
253 }
254
255 /**
256  * iterates over all entries in a distribution table
257  */
258 void stat_iterate_distrib_tbl(const distrib_tbl_t *tbl, eval_distrib_entry_fun eval, void *env) {
259         distrib_entry_t *entry;
260
261         foreach_pset(tbl->hash_map, entry)
262                 eval(entry, env);
263 }