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