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"
23 # include "firmstat.h"
28 #undef obstack_chunk_alloc
29 #undef obstack_chunk_free
30 #define obstack_chunk_alloc malloc
31 #define obstack_chunk_free free
34 #ifdef FIRM_STATISTICS
37 * 64 bit should be enough for now
39 #define STAT_CNT_NUM 2
41 typedef struct _counter_t {
42 unsigned cnt[STAT_CNT_NUM];
46 * An entry for ir_nodes
48 typedef struct _node_entry_t {
49 counter_t new_node; /**< amount of new nodes for this entry */
50 counter_t into_Id; /**< amount of nodes that turned into Id's for this entry */
51 const ir_op *op; /**< the op for this entry */
55 * An entry for ir_graphs
57 typedef struct _graph_entry_t {
58 pset *opcode_hash; /**< hash map containing the opcode counter */
59 counter_t walked; /**< walker walked over the graph */
60 counter_t walked_blocks; /**< walker walked over the graph blocks */
61 pset *opt_hash[STAT_OPT_MAX]; /**< hash maps containing opcode counter for optimizations */
62 const ir_graph *irg; /**< the graph of this object */
63 entity *ent; /**< the entity of this graph if one exists */
64 int deleted; /**< set if this irg was deleted */
68 * An entry for optimized ir_nodes
70 typedef struct _opt_entry_t {
71 counter_t count; /**< optimization counter */
72 const ir_op *op; /**< the op for this entry */
78 typedef struct _statistic_info_t {
79 struct obstack cnts; /**< obstack containing the counters */
80 pset *opcode_hash; /**< hash map containing the opcode counter */
81 pset *irg_hash; /**< hash map containing the counter for irgs */
82 FILE *f; /**< outputfile */
83 ir_op *op_Phi0; /**< needed pseudo op */
89 static stat_info_t _status, *status = &_status;
94 static INLINE void cnt_inc(counter_t *cnt)
98 for (i = 0; i < STAT_CNT_NUM; ++i) {
107 static INLINE void cnt_dec(counter_t *cnt)
111 for (i = 0; i < STAT_CNT_NUM; ++i) {
112 if (--cnt->cnt[i] != -1)
118 * set a counter to zero
120 static INLINE void cnt_clr(counter_t *cnt)
122 memset(cnt->cnt, 0, sizeof(cnt->cnt));
126 * compare two elements of the opcode hash
128 static int opcode_cmp(const void *elt, const void *key)
130 const node_entry_t *e1 = elt;
131 const node_entry_t *e2 = key;
133 return e1->op->code - e2->op->code;
137 * compare two elements of the graph hash
139 static int graph_cmp(const void *elt, const void *key)
141 const graph_entry_t *e1 = elt;
142 const graph_entry_t *e2 = key;
144 return e1->irg != e2->irg;
148 * compare two elements of the optimization hash
150 static int opt_cmp(const void *elt, const void *key)
152 const opt_entry_t *e1 = elt;
153 const opt_entry_t *e2 = key;
155 return e1->op->code != e2->op->code;
159 * Returns the associates node_entry_t for an ir_op
161 static node_entry_t *opcode_get_entry(const ir_op *op, pset *set)
168 elem = pset_find(set, &key, op->code);
172 elem = obstack_alloc(&status->cnts, sizeof(*elem));
174 /* clear new counter */
175 cnt_clr(&elem->new_node);
176 cnt_clr(&elem->into_Id);
180 return pset_insert(set, elem, op->code);
184 * calculates a hash value for an irg
186 static INLINE unsigned irg_hash(const ir_graph *irg)
188 return (unsigned)irg;
192 * Returns the acssociates graph_entry_t for an irg
194 static graph_entry_t *graph_get_entry(const ir_graph *irg, pset *set)
202 elem = pset_find(set, &key, irg_hash(irg));
206 elem = obstack_alloc(&status->cnts, sizeof(*elem));
208 cnt_clr(&elem->walked);
209 cnt_clr(&elem->walked_blocks);
211 /* new hash table for opcodes here */
212 elem->opcode_hash = new_pset(opcode_cmp, 5);
215 for (i = 0; i < sizeof(elem->opt_hash)/sizeof(elem->opt_hash[0]); ++i)
216 elem->opt_hash[i] = new_pset(opt_cmp, 4);
218 return pset_insert(set, elem, irg_hash(irg));
222 * Returns the associates opt_entry_t for an ir_op
224 static opt_entry_t *opt_get_entry(const ir_op *op, pset *set)
231 elem = pset_find(set, &key, op->code);
235 elem = obstack_alloc(&status->cnts, sizeof(*elem));
237 /* clear new counter */
238 cnt_clr(&elem->count);
242 return pset_insert(set, elem, op->code);
245 /* ---------------------------------------------------------------------- */
247 /* initialize the statistics module. */
250 obstack_init(&status->cnts);
252 /* create the hash-tables */
253 status->opcode_hash = new_pset(opcode_cmp, 8);
254 status->irg_hash = new_pset(graph_cmp, 8);
256 status->f = fopen("firmstat.txt", "w");
257 status->op_Phi0 = NULL;
260 /* A new IR op is registered. */
261 void stat_new_ir_op(const ir_op *op)
263 /* execute for side effect :-) */
264 opcode_get_entry(op, status->opcode_hash);
267 /* An IR op is freed. */
268 void stat_free_ir_op(const ir_op *op)
272 /* A new node is created. */
273 void stat_new_node(const ir_node *node)
276 graph_entry_t *graph;
277 ir_op *op = get_irn_op(node);
279 if (op->code == iro_Phi && get_irn_arity(node) == 0) {
280 /* special case, a Phi0 node, count on extra counter */
281 if (! status->op_Phi0) {
282 ir_op *op_Phi = get_op_Phi();
284 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);
286 op = status->op_Phi0;
289 entry = opcode_get_entry(op, status->opcode_hash);
290 graph = graph_get_entry(current_ir_graph, status->irg_hash);
292 /* increase global value */
293 cnt_inc(&entry->new_node);
295 /* increase local value */
296 entry = opcode_get_entry(op, graph->opcode_hash);
297 cnt_inc(&entry->new_node);
300 /* A node is changed into a Id node */
301 void stat_turn_into_id(const ir_node *node)
304 graph_entry_t *graph;
305 ir_op *op = get_irn_op(node);
307 if (op->code == iro_Phi && get_irn_arity(node) == 0) {
308 /* special case, a Phi0 node, count on extra counter */
309 if (! status->op_Phi0) {
310 ir_op *op_Phi = get_op_Phi();
312 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);
314 op = status->op_Phi0;
317 entry = opcode_get_entry(op, status->opcode_hash);
318 graph = graph_get_entry(current_ir_graph, status->irg_hash);
320 /* increase global value */
321 cnt_inc(&entry->into_Id);
323 /* increase local value */
324 entry = opcode_get_entry(op, graph->opcode_hash);
325 cnt_inc(&entry->into_Id);
328 /* A new graph was created */
329 void stat_new_graph(const ir_graph *irg, entity *ent)
331 /* execute for side effect :-) */
332 graph_entry_t * graph = graph_get_entry(irg, status->irg_hash);
339 * A graph was deleted
341 void stat_free_graph(const ir_graph *irg)
343 graph_entry_t * graph = graph_get_entry(irg, status->irg_hash);
349 * A walk over a graph is initiated
351 void stat_irg_walk(const ir_graph *irg, void *pre, void *post)
353 graph_entry_t *graph = graph_get_entry(irg, status->irg_hash);
355 cnt_inc(&graph->walked);
359 * A walk over the graph's blocks is initiated
361 void stat_irg_block_walk(const ir_graph *irg, const ir_node *node, void *pre, void *post)
363 graph_entry_t *graph = graph_get_entry(irg, status->irg_hash);
365 cnt_inc(&graph->walked_blocks);
369 * called for every node that is removed due to an optimization
371 static void removed_due_opt(ir_node *n, pset *set)
373 ir_op *op = get_irn_op(n);
374 opt_entry_t *entry = opt_get_entry(op, set);
376 /* increase global value */
377 cnt_inc(&entry->count);
381 * Some nodes were optimized into some others due to an optimization
383 void stat_merge_nodes(
384 ir_node **new_node_array, int new_num_entries,
385 ir_node **old_node_array, int old_num_entries,
389 graph_entry_t *graph = graph_get_entry(current_ir_graph, status->irg_hash);
391 for (i = 0; i < old_num_entries; ++i) {
392 for (j = 0; j < new_num_entries; ++j)
393 if (old_node_array[i] == new_node_array[j])
396 /* nodes might be in new and old, these are NOT removed */
397 if (j >= new_num_entries) {
398 removed_due_opt(old_node_array[i], graph->opt_hash[opt]);
404 * A node was lowered into other nodes
406 void stat_lower(ir_node *node)
408 graph_entry_t *graph = graph_get_entry(current_ir_graph, status->irg_hash);
410 removed_due_opt(node, graph->opt_hash[STAT_LOWERED]);
414 * dumps a opcode hash
416 static void dump_opcode_hash(pset *set)
420 fprintf(status->f, "%-16s %-8s %-8s\n", "Opcode", "created", "->Id");
421 for (entry = pset_first(set); entry; entry = pset_next(set)) {
422 fprintf(status->f, "%-16s %8d %8d\n",
423 get_id_str(entry->op->name), entry->new_node.cnt[0], entry->into_Id.cnt[0]);
427 static const char *opt_names[] = {
428 "straightening optimization",
430 "algebraic simplification",
432 "Write-After-Write optimization",
433 "Write-After-Read optimization",
434 "Tuple optimization",
436 "Constant evaluation",
441 * dumps a optimization hash
443 static void dump_opt_hash(pset *set, int index)
445 opt_entry_t *entry = pset_first(set);
448 fprintf(status->f, "\n%s:\n", opt_names[index]);
449 fprintf(status->f, "%-16s %-8s\n", "Opcode", "deref");
451 for (; entry; entry = pset_next(set)) {
452 fprintf(status->f, "%-16s %8d\n",
453 get_id_str(entry->op->name), entry->count.cnt[0]);
458 /* Finish the statistics */
459 void stat_finish(void)
462 graph_entry_t *entry;
463 ir_graph *const_irg = get_const_code_irg();
466 fprintf(status->f, "\nGlobal counts:\n");
467 dump_opcode_hash(status->opcode_hash);
469 for (entry = pset_first(status->irg_hash); entry; entry = pset_next(status->irg_hash)) {
470 entity *ent = entry->ent;
472 if (entry->irg == const_irg) {
473 fprintf(status->f, "\nConst code Irg %p", entry->irg);
477 fprintf(status->f, "\nEntity %s, Irg %p", get_entity_name(ent), entry->irg);
479 fprintf(status->f, "\nIrg %p", entry->irg);
482 fprintf(status->f, " %swalked %d over blocks %d:\n",
483 entry->deleted ? "DELETED " : "",
484 entry->walked.cnt[0], entry->walked_blocks.cnt[0]);
486 dump_opcode_hash(entry->opcode_hash);
488 for (i = 0; i < sizeof(entry->opt_hash)/sizeof(entry->opt_hash[0]); ++i) {
489 dump_opt_hash(entry->opt_hash[i], i);
498 void stat_init(void) {}
500 void stat_finish(void) {}
502 void stat_new_ir_op(const ir_op *op) {}
504 void stat_free_ir_op(const ir_op *op) {}
506 void stat_new_node(const ir_node *node) {}
508 void stat_turn_into_id(const ir_node *node) {}
510 void stat_new_graph(const ir_graph *irg, entity *ent) {}
512 void stat_free_graph(const ir_graph *irg) {}
514 void stat_irg_walk(const ir_graph *irg, void *pre, void *post) {}
516 void stat_irg_block_walk(const ir_graph *irg, const ir_node *node, void *pre, void *post) {}
518 void stat_merge_nodes(
519 ir_node **new_node_array, int new_num_entries,
520 ir_node **old_node_array, int old_num_entries,
521 stat_opt_kind opt) {}
523 void stat_lower(ir_node *node) {}