3 * File name: ir/ir/firmstat.c
4 * Purpose: Statistics for Firm.
8 * Copyright: (c) 2004 Universität Karlsruhe
9 * Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
19 # include "irnode_t.h"
20 # include "irgraph_t.h"
27 #undef obstack_chunk_alloc
28 #undef obstack_chunk_free
29 #define obstack_chunk_alloc malloc
30 #define obstack_chunk_free free
33 #ifdef FIRM_STATISTICS
38 * 32 bit should be enough for now
40 #define STAT_CNT_NUM 1
42 typedef struct _counter_t {
43 unsigned cnt[STAT_CNT_NUM];
47 * An entry for ir_nodes
49 typedef struct _node_entry_t {
50 counter_t new_node; /**< amount of new nodes for this entry */
51 counter_t into_Id; /**< amount of nodes that turned into Id's for this entry */
52 const ir_op *op; /**< the op for this entry */
56 * An entry for ir_graphs
58 typedef struct _graph_entry_t {
59 pset *opcode_hash; /**< hash map containing the opcode counter */
60 counter_t walked; /**< walker walked over the graph */
61 counter_t walked_blocks; /**< walker walked over the graph blocks */
62 counter_t was_inlined; /**< number of times other graph were inlined */
63 counter_t got_inlined; /**< number of times this graph was inlined */
64 pset *opt_hash[STAT_OPT_MAX]; /**< hash maps containing opcode counter for optimizations */
65 const ir_graph *irg; /**< the graph of this object */
66 entity *ent; /**< the entity of this graph if one exists */
67 int deleted; /**< set if this irg was deleted */
71 * An entry for optimized ir_nodes
73 typedef struct _opt_entry_t {
74 counter_t count; /**< optimization counter */
75 const ir_op *op; /**< the op for this entry */
81 typedef struct _statistic_info_t {
82 struct obstack cnts; /**< obstack containing the counters */
83 pset *opcode_hash; /**< hash map containing the opcode counter */
84 pset *irg_hash; /**< hash map containing the counter for irgs */
85 FILE *f; /**< outputfile */
86 ir_op *op_Phi0; /**< needed pseudo op */
92 static stat_info_t _status, *status = &_status;
97 static INLINE void cnt_inc(counter_t *cnt)
101 for (i = 0; i < STAT_CNT_NUM; ++i) {
110 static INLINE void cnt_dec(counter_t *cnt)
114 for (i = 0; i < STAT_CNT_NUM; ++i) {
115 if (--cnt->cnt[i] != -1)
121 * set a counter to zero
123 static INLINE void cnt_clr(counter_t *cnt)
125 memset(cnt->cnt, 0, sizeof(cnt->cnt));
129 * compare two elements of the opcode hash
131 static int opcode_cmp(const void *elt, const void *key)
133 const node_entry_t *e1 = elt;
134 const node_entry_t *e2 = key;
136 return e1->op->code - e2->op->code;
140 * compare two elements of the graph hash
142 static int graph_cmp(const void *elt, const void *key)
144 const graph_entry_t *e1 = elt;
145 const graph_entry_t *e2 = key;
147 return e1->irg != e2->irg;
151 * compare two elements of the optimization hash
153 static int opt_cmp(const void *elt, const void *key)
155 const opt_entry_t *e1 = elt;
156 const opt_entry_t *e2 = key;
158 return e1->op->code != e2->op->code;
162 * Returns the associates node_entry_t for an ir_op
164 static node_entry_t *opcode_get_entry(const ir_op *op, pset *set)
171 elem = pset_find(set, &key, op->code);
175 elem = obstack_alloc(&status->cnts, sizeof(*elem));
177 /* clear new counter */
178 cnt_clr(&elem->new_node);
179 cnt_clr(&elem->into_Id);
183 return pset_insert(set, elem, op->code);
187 * calculates a hash value for an irg
189 static INLINE unsigned irg_hash(const ir_graph *irg)
191 return (unsigned)irg;
195 * Returns the acssociates graph_entry_t for an irg
197 static graph_entry_t *graph_get_entry(const ir_graph *irg, pset *set)
205 elem = pset_find(set, &key, irg_hash(irg));
209 elem = obstack_alloc(&status->cnts, sizeof(*elem));
211 cnt_clr(&elem->walked);
212 cnt_clr(&elem->walked_blocks);
213 cnt_clr(&elem->got_inlined);
214 cnt_clr(&elem->was_inlined);
216 /* new hash table for opcodes here */
217 elem->opcode_hash = new_pset(opcode_cmp, 5);
220 for (i = 0; i < sizeof(elem->opt_hash)/sizeof(elem->opt_hash[0]); ++i)
221 elem->opt_hash[i] = new_pset(opt_cmp, 4);
223 return pset_insert(set, elem, irg_hash(irg));
227 * Returns the associates opt_entry_t for an ir_op
229 static opt_entry_t *opt_get_entry(const ir_op *op, pset *set)
236 elem = pset_find(set, &key, op->code);
240 elem = obstack_alloc(&status->cnts, sizeof(*elem));
242 /* clear new counter */
243 cnt_clr(&elem->count);
247 return pset_insert(set, elem, op->code);
250 /* ---------------------------------------------------------------------- */
252 /* initialize the statistics module. */
255 obstack_init(&status->cnts);
257 /* create the hash-tables */
258 status->opcode_hash = new_pset(opcode_cmp, 8);
259 status->irg_hash = new_pset(graph_cmp, 8);
261 status->f = fopen("firmstat.txt", "w");
262 status->op_Phi0 = NULL;
265 /* A new IR op is registered. */
266 void stat_new_ir_op(const ir_op *op)
268 /* execute for side effect :-) */
269 opcode_get_entry(op, status->opcode_hash);
272 /* An IR op is freed. */
273 void stat_free_ir_op(const ir_op *op)
277 /* A new node is created. */
278 void stat_new_node(const ir_node *node)
281 graph_entry_t *graph;
282 ir_op *op = get_irn_op(node);
284 if (op->code == iro_Phi && get_irn_arity(node) == 0) {
285 /* special case, a Phi0 node, count on extra counter */
286 if (! status->op_Phi0) {
287 ir_op *op_Phi = get_op_Phi();
289 status->op_Phi0 = new_ir_op(0xFFFF, "Phi0", op_Phi->pinned, op_Phi->flags, op_Phi->opar, op_Phi->op_index, op_Phi->attr_size);
291 op = status->op_Phi0;
294 entry = opcode_get_entry(op, status->opcode_hash);
295 graph = graph_get_entry(current_ir_graph, status->irg_hash);
297 /* increase global value */
298 cnt_inc(&entry->new_node);
300 /* increase local value */
301 entry = opcode_get_entry(op, graph->opcode_hash);
302 cnt_inc(&entry->new_node);
305 /* A node is changed into a Id node */
306 void stat_turn_into_id(const ir_node *node)
309 graph_entry_t *graph;
310 ir_op *op = get_irn_op(node);
312 if (op->code == iro_Phi && get_irn_arity(node) == 0) {
313 /* special case, a Phi0 node, count on extra counter */
314 if (! status->op_Phi0) {
315 ir_op *op_Phi = get_op_Phi();
317 status->op_Phi0 = new_ir_op(0xFFFF, "Phi0", op_Phi->pinned, op_Phi->flags, op_Phi->opar, op_Phi->op_index, op_Phi->attr_size);
319 op = status->op_Phi0;
322 entry = opcode_get_entry(op, status->opcode_hash);
323 graph = graph_get_entry(current_ir_graph, status->irg_hash);
325 /* increase global value */
326 cnt_inc(&entry->into_Id);
328 /* increase local value */
329 entry = opcode_get_entry(op, graph->opcode_hash);
330 cnt_inc(&entry->into_Id);
333 /* A new graph was created */
334 void stat_new_graph(const ir_graph *irg, entity *ent)
336 /* execute for side effect :-) */
337 graph_entry_t * graph = graph_get_entry(irg, status->irg_hash);
344 * A graph was deleted
346 void stat_free_graph(const ir_graph *irg)
348 graph_entry_t * graph = graph_get_entry(irg, status->irg_hash);
354 * A walk over a graph is initiated
356 void stat_irg_walk(const ir_graph *irg, void *pre, void *post)
358 graph_entry_t *graph = graph_get_entry(irg, status->irg_hash);
360 cnt_inc(&graph->walked);
364 * A walk over the graph's blocks is initiated
366 void stat_irg_block_walk(const ir_graph *irg, const ir_node *node, void *pre, void *post)
368 graph_entry_t *graph = graph_get_entry(irg, status->irg_hash);
370 cnt_inc(&graph->walked_blocks);
374 * called for every node that is removed due to an optimization
376 static void removed_due_opt(ir_node *n, pset *set)
378 ir_op *op = get_irn_op(n);
379 opt_entry_t *entry = opt_get_entry(op, set);
381 /* increase global value */
382 cnt_inc(&entry->count);
386 * Some nodes were optimized into some others due to an optimization
388 void stat_merge_nodes(
389 ir_node **new_node_array, int new_num_entries,
390 ir_node **old_node_array, int old_num_entries,
394 graph_entry_t *graph = graph_get_entry(current_ir_graph, status->irg_hash);
396 for (i = 0; i < old_num_entries; ++i) {
397 for (j = 0; j < new_num_entries; ++j)
398 if (old_node_array[i] == new_node_array[j])
401 /* nodes might be in new and old, these are NOT removed */
402 if (j >= new_num_entries) {
403 removed_due_opt(old_node_array[i], graph->opt_hash[opt]);
409 * A node was lowered into other nodes
411 void stat_lower(ir_node *node)
413 graph_entry_t *graph = graph_get_entry(current_ir_graph, status->irg_hash);
415 removed_due_opt(node, graph->opt_hash[STAT_LOWERED]);
419 * A graph was inlined
421 void stat_inline(ir_node *call, const ir_graph *called_irg)
423 ir_graph *irg = get_irn_irg(call);
424 graph_entry_t *i_graph = graph_get_entry(called_irg, status->irg_hash);
425 graph_entry_t *graph = graph_get_entry(irg, status->irg_hash);
427 cnt_inc(&graph->got_inlined);
428 cnt_inc(&i_graph->was_inlined);
432 * dumps a opcode hash
434 static void dump_opcode_hash(pset *set)
438 fprintf(status->f, "%-16s %-8s %-8s\n", "Opcode", "created", "->Id");
439 for (entry = pset_first(set); entry; entry = pset_next(set)) {
440 fprintf(status->f, "%-16s %8d %8d\n",
441 get_id_str(entry->op->name), entry->new_node.cnt[0], entry->into_Id.cnt[0]);
445 static const char *opt_names[] = {
446 "straightening optimization",
448 "algebraic simplification",
450 "Write-After-Write optimization",
451 "Write-After-Read optimization",
452 "Tuple optimization",
454 "Constant evaluation",
459 * dumps a optimization hash
461 static void dump_opt_hash(pset *set, int index)
463 opt_entry_t *entry = pset_first(set);
466 fprintf(status->f, "\n%s:\n", opt_names[index]);
467 fprintf(status->f, "%-16s %-8s\n", "Opcode", "deref");
469 for (; entry; entry = pset_next(set)) {
470 fprintf(status->f, "%-16s %8d\n",
471 get_id_str(entry->op->name), entry->count.cnt[0]);
476 /* Finish the statistics */
477 void stat_finish(void)
480 graph_entry_t *entry;
481 ir_graph *const_irg = get_const_code_irg();
484 fprintf(status->f, "\nGlobal counts:\n");
485 dump_opcode_hash(status->opcode_hash);
487 for (entry = pset_first(status->irg_hash); entry; entry = pset_next(status->irg_hash)) {
488 entity *ent = entry->ent;
490 if (entry->irg == const_irg) {
491 fprintf(status->f, "\nConst code Irg %p", entry->irg);
495 fprintf(status->f, "\nEntity %s, Irg %p", get_entity_name(ent), entry->irg);
497 fprintf(status->f, "\nIrg %p", entry->irg);
500 fprintf(status->f, " %swalked %d over blocks %d was inlined %d got inlined %d:\n",
501 entry->deleted ? "DELETED " : "",
502 entry->walked.cnt[0], entry->walked_blocks.cnt[0],
503 entry->was_inlined.cnt[0],
504 entry->got_inlined.cnt[0]
507 dump_opcode_hash(entry->opcode_hash);
509 for (i = 0; i < sizeof(entry->opt_hash)/sizeof(entry->opt_hash[0]); ++i) {
510 dump_opt_hash(entry->opt_hash[i], i);
519 /* need this for prototypes */
520 #define FIRM_STATISTICS
521 #include "firmstat.h"
523 void stat_init(void) {}
525 void stat_finish(void) {}
527 void stat_new_ir_op(const ir_op *op) {}
529 void stat_free_ir_op(const ir_op *op) {}
531 void stat_new_node(const ir_node *node) {}
533 void stat_turn_into_id(const ir_node *node) {}
535 void stat_new_graph(const ir_graph *irg, entity *ent) {}
537 void stat_free_graph(const ir_graph *irg) {}
539 void stat_irg_walk(const ir_graph *irg, void *pre, void *post) {}
541 void stat_irg_block_walk(const ir_graph *irg, const ir_node *node, void *pre, void *post) {}
543 void stat_merge_nodes(
544 ir_node **new_node_array, int new_num_entries,
545 ir_node **old_node_array, int old_num_entries,
546 stat_opt_kind opt) {}
548 void stat_lower(ir_node *node) {}
550 void stat_inline(const ir_node *call, const ir_graph *irg) {}