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