b0d92d6fcd3b524c8e31d264b52cbca3ad9f2ab8
[libfirm] / ir / stat / stat_dmp.c
1 /*
2  * Project:     libFIRM
3  * File name:   ir/ir/stat_dmp.c
4  * Purpose:     Statistics for Firm.
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 "stat_dmp.h"
16
17 /**
18  * names of the optimizations
19  */
20 static const char *opt_names[] = {
21   "straightening optimization",
22   "if simplification",
23   "constant evaluation",
24   "algebraic simplification",
25   "Phi optmization",
26   "Write-After-Write optimization",
27   "Write-After-Read optimization",
28   "Read-After-Write optimization",
29   "Read-After-Read optimization",
30   "Read-a-Const optimization",
31   "Tuple optimization",
32   "ID optimization",
33   "Common subexpression elimination",
34   "Strength reduction",
35   "Architecture dependant optimization",
36   "Reassociation optimization",
37   "Polymorphic call optimization",
38   "an if conversion was tried",
39   "Lowered",
40 };
41
42 static const char *if_conv_names[] = {
43   "if conv done             ",
44   "if conv side effect      ",
45   "if conv Phi node found   ",
46   "if conv to deep DAG's    ",
47   "if conv bad control flow ",
48 };
49
50 /**
51  * dumps a opcode hash into human readable form
52  */
53 static void simple_dump_opcode_hash(dumper_t *dmp, pset *set)
54 {
55   node_entry_t *entry;
56   counter_t f_alive;
57   counter_t f_new_node;
58   counter_t f_Id;
59
60   cnt_clr(&f_alive);
61   cnt_clr(&f_new_node);
62   cnt_clr(&f_Id);
63
64   fprintf(dmp->f, "%-16s %-8s %-8s %-8s\n", "Opcode", "alive", "created", "->Id");
65   for (entry = pset_first(set); entry; entry = pset_next(set)) {
66     fprintf(dmp->f, "%-16s %8u %8u %8u\n",
67       get_id_str(entry->op->name), entry->cnt_alive.cnt[0], entry->new_node.cnt[0], entry->into_Id.cnt[0]);
68
69     cnt_add(&f_alive,    &entry->cnt_alive);
70     cnt_add(&f_new_node, &entry->new_node);
71     cnt_add(&f_Id,       &entry->into_Id);
72   }
73   fprintf(dmp->f, "-------------------------------------------\n");
74   fprintf(dmp->f, "%-16s %8u %8u %8u\n", "Sum",
75      f_alive.cnt[0],
76      f_new_node.cnt[0],
77      f_Id.cnt[0]);
78 }
79
80 /**
81  * dumps an optimization hash into human readable form
82  */
83 static void simple_dump_opt_hash(dumper_t *dmp, pset *set, int index)
84 {
85   opt_entry_t *entry = pset_first(set);
86
87   if (entry) {
88     fprintf(dmp->f, "\n%s:\n", opt_names[index]);
89     fprintf(dmp->f, "%-16s %-8s\n", "Opcode", "deref");
90
91     for (; entry; entry = pset_next(set)) {
92       fprintf(dmp->f, "%-16s %8u\n",
93         get_id_str(entry->op->name), entry->count.cnt[0]);
94     }
95   }
96 }
97
98 /**
99  * dumps the number of real_function_call optimization
100  */
101 static void simple_dump_real_func_calls(dumper_t *dmp, counter_t *cnt)
102 {
103   if (! cnt_eq(cnt, 0)) {
104     fprintf(dmp->f, "\nReal Function Calls optimized:\n");
105     fprintf(dmp->f, "%-16s %8u\n",
106       "Call", cnt->cnt[0]);
107   }
108 }
109
110 /**
111  * dumps the number of tail_recursion optimization
112  */
113 static void simple_dump_tail_recursion(dumper_t *dmp, unsigned num_tail_recursion)
114 {
115   if (num_tail_recursion > 0) {
116     fprintf(dmp->f, "\nTail recursion optimized:\n");
117     fprintf(dmp->f, "%-16s %8u\n", "Call", num_tail_recursion);
118   }
119 }
120
121 /**
122  * dumps the edges count
123  */
124 static void simple_dump_edges(dumper_t *dmp, counter_t *cnt)
125 {
126   fprintf(dmp->f, "%-16s %8d\n", "Edges", cnt->cnt[0]);
127 }
128
129 /**
130  * dumps the IRG
131  */
132 static void simple_dump_graph(dumper_t *dmp, graph_entry_t *entry)
133 {
134   int i, dump_opts = 1;
135   block_entry_t *b_entry;
136
137   if (entry->irg) {
138     ir_graph *const_irg = get_const_code_irg();
139
140     if (entry->irg == const_irg) {
141       fprintf(dmp->f, "\nConst code Irg %p", (void *)entry->irg);
142     }
143     else {
144       if (entry->ent)
145         fprintf(dmp->f, "\nEntity %s, Irg %p", get_entity_name(entry->ent), (void *)entry->irg);
146       else
147         fprintf(dmp->f, "\nIrg %p", (void *)entry->irg);
148     }
149
150     fprintf(dmp->f, " %swalked %u over blocks %u:\n"
151                     " was inlined               : %u\n"
152                     " got inlined               : %u\n"
153                     " strength red              : %u\n"
154                     " leaf function             : %s\n"
155                     " calls only leaf functions : %s\n"
156                     " recursive                 : %s\n"
157                     " chain call                : %s\n"
158         " calls                     : %u\n"
159         " indirect calls            : %u\n",
160         entry->is_deleted ? "DELETED " : "",
161         entry->cnt_walked.cnt[0], entry->cnt_walked_blocks.cnt[0],
162         entry->cnt_was_inlined.cnt[0],
163         entry->cnt_got_inlined.cnt[0],
164               entry->cnt_strength_red.cnt[0],
165               entry->is_leaf ? "YES" : "NO",
166               entry->is_leaf_call == LCS_NON_LEAF_CALL ? "NO" : (entry->is_leaf_call == LCS_LEAF_CALL ? "Yes" : "Maybe"),
167               entry->is_recursive ? "YES" : "NO",
168               entry->is_chain_call ? "YES" : "NO",
169         entry->cnt_all_calls.cnt[0],
170         entry->cnt_indirect_calls.cnt[0]
171     );
172
173     for (i = 0; i < sizeof(entry->cnt_if_conv)/sizeof(entry->cnt_if_conv[0]); ++i) {
174       fprintf(dmp->f, " %s : %u\n", if_conv_names[i], entry->cnt_if_conv[i].cnt[0]);
175     }
176
177   }
178   else {
179     fprintf(dmp->f, "\nGlobals counts:\n");
180     fprintf(dmp->f, "--------------\n");
181     dump_opts = 0;
182   }
183
184   simple_dump_opcode_hash(dmp, entry->opcode_hash);
185   simple_dump_edges(dmp, &entry->cnt_edges);
186
187   /* effects of optimizations */
188   if (dump_opts) {
189     int i;
190
191     simple_dump_real_func_calls(dmp, &entry->cnt_real_func_call);
192     simple_dump_tail_recursion(dmp, entry->num_tail_recursion);
193
194     for (i = 0; i < sizeof(entry->opt_hash)/sizeof(entry->opt_hash[0]); ++i) {
195       simple_dump_opt_hash(dmp, entry->opt_hash[i], i);
196     }
197
198     /* dump block info */
199     fprintf(dmp->f, "\n%12s %12s %12s %12s %12s %12s\n", "Block Nr", "Nodes", "intern E", "incoming E", "outgoing E", "quot");
200     for (b_entry = pset_first(entry->block_hash);
201                b_entry;
202                b_entry = pset_next(entry->block_hash)) {
203       fprintf(dmp->f, "BLK %12ld %12u %12u %12u %12u %4.8f\n",
204               b_entry->block_nr,
205               b_entry->cnt_nodes.cnt[0],
206               b_entry->cnt_edges.cnt[0],
207               b_entry->cnt_in_edges.cnt[0],
208               b_entry->cnt_out_edges.cnt[0],
209               (double)b_entry->cnt_edges.cnt[0] / (double)b_entry->cnt_nodes.cnt[0]
210       );
211     }
212   }
213 }
214
215 /**
216  * initialize the simple dumper
217  */
218 static void simple_init(dumper_t *dmp, const char *name)
219 {
220   char fname[2048];
221
222   snprintf(fname, sizeof(fname), "%s.txt", name);
223   dmp->f = fopen(fname, "w");
224 }
225
226 /**
227  * finishes the simple dumper
228  */
229 static void simple_finish(dumper_t *dmp)
230 {
231   fclose(dmp->f);
232   dmp->f = NULL;
233 }
234
235 /**
236  * the simple human readable dumper
237  */
238 const dumper_t simple_dumper = {
239   simple_dump_graph,
240   simple_init,
241   simple_finish,
242   NULL,
243   NULL,
244   NULL,
245 };
246
247 /* ---------------------------------------------------------------------- */
248
249 /**
250  * count the nodes as needed:
251  *
252  * 1 normal (data) Phi's
253  * 2 memory Phi's
254  * 3 Proj
255  * 0 all other nodes
256  */
257 static void csv_count_nodes(dumper_t *dmp, graph_entry_t *graph, counter_t cnt[])
258 {
259   node_entry_t *entry;
260   int i;
261
262   for (i = 0; i < 4; ++i)
263     cnt_clr(&cnt[i]);
264
265   for (entry = pset_first(graph->opcode_hash); entry; entry = pset_next(graph->opcode_hash)) {
266     if (entry->op == op_Phi) {
267       /* normal Phi */
268       cnt_add(&cnt[1], &entry->cnt_alive);
269     }
270     else if (entry->op == dmp->status->op_PhiM) {
271       /* memory Phi */
272       cnt_add(&cnt[2], &entry->cnt_alive);
273     }
274     else if (entry->op == op_Proj) {
275       /* Proj */
276       cnt_add(&cnt[3], &entry->cnt_alive);
277     }
278     else {
279       /* all other nodes */
280       cnt_add(&cnt[0], &entry->cnt_alive);
281     }
282   }
283 }
284
285 /**
286  * dumps the IRG
287  */
288 static void csv_dump_graph(dumper_t *dmp, graph_entry_t *entry)
289 {
290   const char *name;
291
292   counter_t cnt[4];
293
294   if (entry->irg && !entry->is_deleted) {
295     ir_graph *const_irg = get_const_code_irg();
296
297     if (entry->irg == const_irg) {
298       name = "<Const code Irg>";
299       return;
300     }
301     else {
302       if (entry->ent)
303         name = get_entity_name(entry->ent);
304       else
305         name = "<UNKNOWN IRG>";
306     }
307
308     csv_count_nodes(dmp, entry, cnt);
309
310     fprintf(dmp->f, "%-40s, %p, %d, %d, %d, %d\n",
311         name,
312         (void *)entry->irg,
313         cnt[0].cnt[0],
314         cnt[1].cnt[0],
315         cnt[2].cnt[0],
316         cnt[3].cnt[0]
317     );
318   }
319 }
320
321 /**
322  * initialize the simple dumper
323  */
324 static void csv_init(dumper_t *dmp, const char *name)
325 {
326   char fname[2048];
327
328   snprintf(fname, sizeof(fname), "%s.csv", name);
329   dmp->f = fopen(fname, "a");
330 }
331
332 /**
333  * finishes the simple dumper
334  */
335 static void csv_finish(dumper_t *dmp)
336 {
337   fclose(dmp->f);
338   dmp->f = NULL;
339 }
340
341 /**
342  * the simple human readable dumper
343  */
344 const dumper_t csv_dumper = {
345   csv_dump_graph,
346   csv_init,
347   csv_finish,
348   NULL,
349   NULL,
350   NULL,
351 };