Fixed some size_t related warnings.
[libfirm] / ir / stat / distrib.c
1 /*
2  * Copyright (C) 1995-2011 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 #include "config.h"
27
28 #include "hashptr.h"
29 #include "irtools.h"
30 #include "xmalloc.h"
31 #include "firmstat_t.h"
32
33 /**
34  * calculates a hash value for an address
35  */
36 static unsigned addr_hash(const void *object)
37 {
38         return HASH_PTR(object);
39 }
40
41 /**
42  * calculates a hash value for an integer
43  */
44 static unsigned int_hash(const void *object)
45 {
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 {
54         const distrib_entry_t *p1 = (const distrib_entry_t*)elt;
55         const distrib_entry_t *p2 = (const distrib_entry_t*)key;
56
57         if (p1->object == p2->object)
58                 return 0;
59         return p1->object < p2->object ? -1 : 1;
60 }
61
62 /*
63  * create a new distribution table
64  */
65 distrib_tbl_t *stat_new_distrib_tbl(pset_cmp_fun cmp_func, distrib_hash_fun hash_func)
66 {
67         distrib_tbl_t *res = XMALLOC(distrib_tbl_t);
68
69         obstack_init(&res->cnts);
70
71         /* create the hash-table */
72         res->hash_map  = new_pset(cmp_func, 8);
73         res->hash_func = hash_func ? hash_func : addr_hash;
74         res->int_dist  = 0;
75
76         return res;
77 }
78
79 /*
80  * create a new distribution table for an integer distribution
81  */
82 distrib_tbl_t *stat_new_int_distrib_tbl(void)
83 {
84         distrib_tbl_t *res = stat_new_distrib_tbl(int_cmp_fun, int_hash);
85
86         if (res)
87                 res->int_dist = 1;
88
89         return res;
90 }
91
92 /*
93  * destroy a distribution table
94  */
95 void stat_delete_distrib_tbl(distrib_tbl_t *tbl)
96 {
97         if (tbl) {
98                 /* free all entries */
99                 obstack_free(&tbl->cnts, NULL);
100
101                 /* delete the hash table */
102                 del_pset(tbl->hash_map);
103         }
104 }
105
106 /**
107  * Returns the associates distrib_entry_t for an object
108  */
109 static distrib_entry_t *distrib_get_entry(distrib_tbl_t *tbl, const void *object)
110 {
111         distrib_entry_t key;
112         distrib_entry_t *elem;
113
114         key.object = object;
115
116         elem = (distrib_entry_t*)pset_find(tbl->hash_map, &key, tbl->hash_func(object));
117         if (elem)
118                 return elem;
119
120         elem = OALLOC(&tbl->cnts, distrib_entry_t);
121
122         /* clear counter */
123         cnt_clr(&elem->cnt);
124
125         elem->object = object;
126
127         return (distrib_entry_t*)pset_insert(tbl->hash_map, elem, tbl->hash_func(object));
128 }
129
130 /*
131  * adds a new object count into the distribution table
132  */
133 void stat_add_distrib_tbl(distrib_tbl_t *tbl, const void *object, const counter_t *cnt)
134 {
135         distrib_entry_t *elem = distrib_get_entry(tbl, object);
136
137         cnt_add(&elem->cnt, cnt);
138 }
139
140 /*
141  * adds a new key count into the integer distribution table
142  */
143 void stat_add_int_distrib_tbl(distrib_tbl_t *tbl, int key, const counter_t *cnt)
144 {
145         stat_add_distrib_tbl(tbl, INT_TO_PTR(key), cnt);
146 }
147
148 /*
149  * increases object count by one
150  */
151 void stat_inc_distrib_tbl(distrib_tbl_t *tbl, const void *object)
152 {
153         distrib_entry_t *elem = distrib_get_entry(tbl, object);
154
155         cnt_inc(&elem->cnt);
156 }
157
158 /*
159  * increases key count by one
160  */
161 void stat_inc_int_distrib_tbl(distrib_tbl_t *tbl, int key)
162 {
163         stat_inc_distrib_tbl(tbl, INT_TO_PTR(key));
164 }
165
166 /*
167  * inserts a new object with count 0 into the distribution table
168  * if object is already present, nothing happens
169  */
170 void stat_insert_distrib_tbl(distrib_tbl_t *tbl, const void *object)
171 {
172         /* executed for side effect */
173         (void)distrib_get_entry(tbl, object);
174 }
175
176 /*
177  * inserts a new key with count 0 into the integer distribution table
178  * if key is already present, nothing happens
179  */
180 void stat_insert_int_distrib_tbl(distrib_tbl_t *tbl, int key)
181 {
182         stat_insert_distrib_tbl(tbl, INT_TO_PTR(key));
183 }
184
185 /*
186  * returns the sum over all counters in a distribution table
187  */
188 int stat_get_count_distrib_tbl(distrib_tbl_t *tbl)
189 {
190         distrib_entry_t *entry;
191         counter_t cnt = ZERO_CNT;
192
193         foreach_pset(tbl->hash_map, distrib_entry_t*, entry)
194                 cnt_add(&cnt, &entry->cnt);
195         return cnt_to_uint(&cnt);
196 }
197
198 /*
199  * calculates the mean value of a distribution
200  */
201 double stat_calc_mean_distrib_tbl(distrib_tbl_t *tbl)
202 {
203         distrib_entry_t *entry;
204         size_t count;
205         double sum;
206
207         if (tbl->int_dist) {
208                 /* integer distribution, need min, max */
209                 int min, max;
210
211                 entry = (distrib_entry_t*)pset_first(tbl->hash_map);
212
213                 if (! entry)
214                         return 0.0;
215
216                 min =
217                 max = PTR_TO_INT(entry->object);
218                 sum = cnt_to_dbl(&entry->cnt);
219
220
221                 for (entry = (distrib_entry_t*)pset_next(tbl->hash_map); entry != NULL;
222                      entry = (distrib_entry_t*)pset_next(tbl->hash_map)) {
223                         int value = PTR_TO_INT(entry->object);
224
225                         if (value < min)
226                                 min = value;
227                         if (value > max)
228                                 max = value;
229
230                         sum += cnt_to_dbl(&entry->cnt);
231                 }
232                 count = max - min + 1;
233         } else {
234                 sum = 0.0;
235                 count = 0;
236                 foreach_pset(tbl->hash_map, distrib_entry_t*, entry) {
237                         sum += cnt_to_dbl(&entry->cnt);
238                         ++count;
239                 }
240         }
241
242         return count ? sum / (double)count : 0.0;
243 }
244
245 /*
246  * calculates the average value of a distribution
247  */
248 double stat_calc_avg_distrib_tbl(distrib_tbl_t *tbl)
249 {
250         distrib_entry_t *entry;
251         size_t          count = 0;
252         double          sum   = 0.0;
253
254         if (tbl->int_dist) {
255                 if (pset_count(tbl->hash_map) <= 0)
256                         return 0.0;
257
258                 foreach_pset(tbl->hash_map, distrib_entry_t*, entry) {
259                         sum   += cnt_to_dbl(&entry->cnt) * PTR_TO_INT(entry->object);
260                         count += cnt_to_uint(&entry->cnt);
261                 }
262         } else {
263                 foreach_pset(tbl->hash_map, distrib_entry_t*, entry) {
264                         sum += cnt_to_dbl(&entry->cnt);
265                         ++count;
266                 }
267         }
268
269         return count ? sum / (double)count : 0.0;
270 }
271
272 /**
273  * iterates over all entries in a distribution table
274  */
275 void stat_iterate_distrib_tbl(const distrib_tbl_t *tbl, eval_distrib_entry_fun eval, void *env)
276 {
277         distrib_entry_t *entry;
278
279         foreach_pset(tbl->hash_map, distrib_entry_t*, entry)
280                 eval(entry, env);
281 }