added get_count function for distribution tables
[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 (int)(p1->object) - (int)(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   for (entry = pset_first(tbl->hash_map); entry; entry = pset_next(tbl->hash_map)) {
185     sum += cnt_to_int(&entry->cnt);
186   }
187
188   return sum;
189 }
190
191 /*
192  * calculates the mean value of a distribution
193  */
194 double stat_calc_mean_distrib_tbl(distrib_tbl_t *tbl)
195 {
196   distrib_entry_t *entry;
197   unsigned count;
198   double sum;
199
200   if (tbl->int_dist) {
201     /* integer distribution, need min, max */
202     int min, max;
203
204     entry = pset_first(tbl->hash_map);
205
206     if (! entry)
207       return 0.0;
208
209     min =
210     max = (int)entry->object;
211     sum = cnt_to_dbl(&entry->cnt);
212
213
214     for (entry = pset_next(tbl->hash_map); entry; entry = pset_next(tbl->hash_map)) {
215       int value = (int)entry->object;
216
217       if (value < min)
218         min = value;
219       if (value > max);
220         max = value;
221
222       sum += cnt_to_dbl(&entry->cnt);
223     }
224     count = max - min + 1;
225   }
226   else {
227     sum = 0.0;
228     count = 0;
229     for (entry = pset_first(tbl->hash_map); entry; entry = pset_next(tbl->hash_map)) {
230       sum += cnt_to_dbl(&entry->cnt);
231       ++count;
232     }
233   }
234
235   return count ? sum / (double)count : 0.0;
236 }
237
238 /*
239  * calculates the average value of a distribution
240  */
241 double stat_calc_avg_distrib_tbl(distrib_tbl_t *tbl)
242 {
243   distrib_entry_t *entry;
244   unsigned         count = 0;
245   double           sum   = 0.0;
246
247   if (tbl->int_dist) {
248     entry = pset_first(tbl->hash_map);
249
250     if (! entry)
251       return 0.0;
252
253     sum   = cnt_to_dbl(&entry->cnt);
254         count = cnt_to_int(&entry->cnt);
255
256     for (entry = pset_next(tbl->hash_map); entry; entry = pset_next(tbl->hash_map)) {
257       sum   += cnt_to_dbl(&entry->cnt) * (int)entry->object;
258       count += cnt_to_int(&entry->cnt);
259     }
260   }
261   else {
262     for (entry = pset_first(tbl->hash_map); entry; entry = pset_next(tbl->hash_map)) {
263       sum += cnt_to_dbl(&entry->cnt);
264       ++count;
265     }
266   }
267
268   return count ? sum / (double)count : 0.0;
269 }
270
271 /**
272  * iterates over all entries in a distribution table
273  */
274 void stat_iterate_distrib_tbl(distrib_tbl_t *tbl, eval_distrib_entry_fun eval, void *env)
275 {
276   distrib_entry_t *entry;
277
278   for (entry = pset_first(tbl->hash_map); entry; entry = pset_next(tbl->hash_map)) {
279     eval(entry, env);
280   }
281 }