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