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