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