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