firmstat.c
ifeq ($(enable_statistics),yes)
-SOURCES += pattern.c pattern.h counter.h pattern_dmp.c pattern_dmp.h
+SOURCES += firmstat_t.h pattern.c pattern.h dags.c dags.h counter.h \
+ pattern_dmp.c pattern_dmp.h distrib.c
endif
int i;
unsigned va, vb;
-
for (i = STAT_CNT_NUM - 1 ; i >= 0; --i) {
va = a->cnt[i];
vb = b->cnt[i];
return 0;
}
+/**
+ * convert a counter into a double
+ */
+static INLINE double cnt_to_dbl(const counter_t *a)
+{
+ int i;
+ double res = 0.0, scale = 1.0, tmp;
+
+ i = (1 << (sizeof(a->cnt[i]) * 4));
+ tmp = ((double)i) * ((double)i);
+
+ for (i = 0; i < STAT_CNT_NUM; ++i) {
+ res += scale * (double)a->cnt[i];
+
+ scale *= tmp;
+ }
+ return res;
+}
+
#endif /* _COUNTER_H_ */
--- /dev/null
+/*
+ * Project: libFIRM
+ * File name: ir/ir/dags.c
+ * Purpose: Statistics for Firm. DAG's in graphs.
+ * Author: Michael Beck
+ * Created:
+ * CVS-ID: $Id$
+ * Copyright: (c) 2004 Universität Karlsruhe
+ * Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+
+#include "dags.h"
+
+enum dag_counting_options_t {
+ FIRMSTAT_COPY_CONSTANTS = 0x00000001, /**< if set, constants will be treated as they are in
+ the same block as its successors */
+};
+
+/**
+ * walker for clearing node links
+ */
+static void clear_links(ir_node *node, void *env)
+{
+ set_irn_link(node, NULL);
+}
+
+typedef struct _dag_entry_t dag_entry_t;
+
+/**
+ * Environment for connecting DAG's
+ */
+typedef struct _dag_env_t {
+ struct obstack obst;
+ unsigned num_of_dags;
+ dag_entry_t *list_of_dags;
+ unsigned options; /**< DAG counting options */
+} dag_env_t;
+
+/**
+ * a DAG Entry
+ */
+struct _dag_entry_t {
+ ir_node *root;
+ unsigned num_roots;
+ unsigned num_nodes;
+ unsigned num_inner_nodes;
+ unsigned is_dead;
+ dag_entry_t *next;
+};
+
+/**
+ * a DAG Entry link
+ */
+typedef struct _dag_link_t {
+ dag_entry_t *entry;
+} dag_link_t;
+
+/**
+ * walker for connecting DAGs and counting.
+ */
+static void connect_dags(ir_node *node, void *env)
+{
+ dag_env_t *dag_env = env;
+ int i, arity;
+ ir_node *block;
+ dag_link_t *link;
+
+ if (is_Block(node))
+ return;
+
+ block = get_nodes_Block(node);
+
+ /* ignore start end end blocks */
+ if (block == get_irg_start_block(current_ir_graph) ||
+ block == get_irg_end_block(current_ir_graph))
+ return;
+
+ link = get_irn_link(node);
+
+ if (! link) {
+ /* not assigned node found, maybe a new root */
+ dag_entry_t *entry = obstack_alloc(&dag_env->obst, sizeof(*entry));
+
+ link = obstack_alloc(&dag_env->obst, sizeof(*link));
+ link->entry = entry;
+
+ entry->num_nodes = 1;
+ entry->num_roots = 1;
+ entry->num_inner_nodes = 0;
+ entry->root = node;
+ entry->is_dead = 0;
+ entry->next = dag_env->list_of_dags;
+
+ ++dag_env->num_of_dags;
+ dag_env->list_of_dags = entry;
+
+ set_irn_link(node, link);
+ }
+
+ /* put the predecessors into the same DAG as the current */
+ for (i = 0, arity = get_irn_arity(node); i < arity; ++i) {
+ ir_node *prev = get_irn_n(node, i);
+ int special = 0;
+
+ /*
+ * copy constants if requested into the DAG's
+ * beware, do NOT add a link, as this will result in
+ * wrong intersections
+ */
+ if (dag_env->options & FIRMSTAT_COPY_CONSTANTS) {
+ if (get_irn_op(prev) == op_Const || get_irn_op(prev) == op_SymConst) {
+ ++link->entry->num_nodes;
+ ++link->entry->num_inner_nodes;
+ }
+ }
+
+ if (get_nodes_Block(prev) == block) {
+ dag_link_t *prev_link = get_irn_link(prev);
+
+ if (! prev_link) {
+ /* not assigned node, do it */
+ set_irn_link(prev, link);
+ ++link->entry->num_nodes;
+ ++link->entry->num_inner_nodes;
+ }
+ else if (prev_link->entry != link->entry) {
+ /* two DAGs intersect */
+
+ assert(link->entry);
+
+ link->entry->num_roots += prev_link->entry->num_roots;
+ link->entry->num_nodes += prev_link->entry->num_nodes;
+ link->entry->num_inner_nodes += prev_link->entry->num_inner_nodes;
+
+ --dag_env->num_of_dags;
+
+ prev_link->entry->is_dead = 1;
+ prev_link->entry = link->entry;
+ }
+ }
+ }
+}
+
+/**
+ * count the DAG's size of a graph
+ */
+void count_dags_in_graph(graph_entry_t *global, graph_entry_t *graph)
+{
+ dag_env_t root_env;
+ dag_entry_t *entry;
+
+ /* do NOT check the const code irg */
+ if (graph->irg == get_const_code_irg())
+ return;
+
+ /* first step, clear the links */
+ irg_walk_graph(graph->irg, clear_links, NULL, NULL);
+
+ obstack_init(&root_env.obst);
+ root_env.num_of_dags = 0;
+ root_env.list_of_dags = NULL;
+ root_env.options = FIRMSTAT_COPY_CONSTANTS;
+
+ /* count them */
+ irg_walk_graph(graph->irg, connect_dags, NULL, &root_env);
+
+ printf("Graph %p %s --- %d\n", graph->irg, get_entity_name(get_irg_entity(graph->irg)),
+ root_env.num_of_dags);
+
+ for (entry = root_env.list_of_dags; entry; entry = entry->next) {
+ if (entry->is_dead)
+ continue;
+
+ printf("number of roots %d number of nodes %d inner %d %d\n",
+ entry->num_roots,
+ entry->num_nodes,
+ entry->num_inner_nodes,
+ get_irn_node_nr(entry->root));
+ }
+
+ obstack_free(&root_env.obst, NULL);
+}
--- /dev/null
+/*
+ * Project: libFIRM
+ * File name: ir/ir/dags.h
+ * Purpose: Statistics for Firm. DAG's in graphs.
+ * Author: Michael Beck
+ * Created:
+ * CVS-ID: $Id$
+ * Copyright: (c) 2004 Universität Karlsruhe
+ * Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
+ */
+#ifndef _DAGS_H_
+#define _DAGS_H_
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "firmstat_t.h"
+
+/*
+ * count the DAG's size of a graph
+ */
+void count_dags_in_graph(graph_entry_t *global, graph_entry_t *graph);
+
+#endif /* _DAGS_H_ */
--- /dev/null
+/*
+ * Project: libFIRM
+ * File name: ir/ir/distrib.c
+ * Purpose: Statistics for Firm. Distribution tables.
+ * Author: Michael Beck
+ * Created:
+ * CVS-ID: $Id$
+ * Copyright: (c) 2004 Universität Karlsruhe
+ * Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
+ */
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "firmstat_t.h"
+
+/**
+ * calculates a hash value for an address
+ * Addresses are typically aligned at 32bit, so we ignore the lowest bits
+ */
+static unsigned addr_hash(const void *object)
+{
+ return (unsigned)object >> 3;
+}
+
+/**
+ * calculates a hash value for an integer
+ */
+static unsigned int_hash(const void *object)
+{
+ return (unsigned)object;
+}
+
+/**
+ * compare function for integer distribution tables
+ */
+static int int_cmp_fun(const void *elt, const void *key)
+{
+ int p1 = (int)elt;
+ int p2 = (int)key;
+
+ return p1 - p2;
+}
+
+/*
+ * create a new distribution table
+ */
+distrib_tbl_t *stat_new_distrib_tbl(pset_cmp_fun cmp_func, distrib_hash_fun hash_func)
+{
+ distrib_tbl_t *res;
+
+ res = malloc(sizeof(*res));
+
+ if (! res)
+ return res;
+
+ obstack_init(&res->cnts);
+
+ /* create the hash-table */
+ res->hash_map = new_pset(cmp_func, 8);
+ res->hash_func = hash_func ? hash_func : addr_hash;
+ res->int_dist = 0;
+
+ return res;
+}
+
+/*
+ * create a new distribution table for an integer distribution
+ */
+distrib_tbl_t *stat_new_int_distrib_tbl(void)
+{
+ distrib_tbl_t *res = stat_new_distrib_tbl(int_cmp_fun, int_hash);
+
+ if (res)
+ res->int_dist = 1;
+
+ return res;
+}
+
+/*
+ * destroy a distribution table
+ */
+void stat_delete_distrib_tbl(distrib_tbl_t *tbl)
+{
+ if (tbl) {
+ /* free all entries */
+ obstack_free(&tbl->cnts, NULL);
+
+ /* delete the hash table */
+ del_pset(tbl->hash_map);
+ }
+}
+
+/**
+ * Returns the associates distrib_entry_t for an object
+ */
+static distrib_entry_t *distrib_get_entry(distrib_tbl_t *tbl, const void *object)
+{
+ distrib_entry_t key;
+ distrib_entry_t *elem;
+
+ key.object = object;
+
+ elem = pset_find(tbl->hash_map, &key, tbl->hash_func(object));
+ if (elem)
+ return elem;
+
+ elem = obstack_alloc(&tbl->cnts, sizeof(*elem));
+
+ /* clear counter */
+ cnt_clr(&elem->cnt);
+
+ elem->object = object;
+
+ return pset_insert(tbl->hash_map, elem, tbl->hash_func(object));
+}
+
+/*
+ * adds a new object count into the distribution table
+ */
+void stat_add_distrib_tbl(distrib_tbl_t *tbl, const void *object, const counter_t *cnt)
+{
+ distrib_entry_t *elem = distrib_get_entry(tbl, object);
+
+ cnt_add(&elem->cnt, cnt);
+}
+
+/**
+ * adds a new key count into the integer distribution table
+ */
+void stat_add_int_distrib_tbl(distrib_tbl_t *tbl, int key, const counter_t *cnt)
+{
+ stat_add_distrib_tbl(tbl, (const void *)key, cnt);
+}
+
+/*
+ * calculates the mean value of a distribution
+ */
+double stat_calc_mean_distrib_tbl(distrib_tbl_t *tbl)
+{
+ distrib_entry_t *entry;
+ unsigned count;
+ double sum;
+
+ if (tbl->int_dist) {
+ /* integer distribution, need min, max */
+ int min, max;
+
+ entry = pset_first(tbl->hash_map);
+
+ if (! entry)
+ return 0.0;
+
+ min =
+ max = (int)entry->object;
+ sum = cnt_to_dbl(&entry->cnt);
+
+
+ for (entry = pset_next(tbl->hash_map); entry; entry = pset_next(tbl->hash_map)) {
+ int value = (int)entry->object;
+
+ if (value < min)
+ min = value;
+ if (value > max);
+ max = value;
+
+ sum += cnt_to_dbl(&entry->cnt);
+ }
+ count = max - min + 1;
+ }
+ else {
+ sum = 0.0;
+ count = 0;
+ for (entry = pset_first(tbl->hash_map); entry; entry = pset_next(tbl->hash_map)) {
+ sum += cnt_to_dbl(&entry->cnt);
+ ++count;
+ }
+ }
+
+ return count ? sum / (double)count : 0.0;
+}
+
+/**
+ * iterates over all entries in a distribution table
+ */
+void stat_iterate_distrib_tbl(distrib_tbl_t *tbl, eval_distrib_entry_fun eval)
+{
+ distrib_entry_t *entry;
+
+ for (entry = pset_first(tbl->hash_map); entry; entry = pset_next(tbl->hash_map)) {
+ eval(entry);
+ }
+}
# include "config.h"
#endif
-# include <string.h>
+#ifdef FIRM_STATISTICS
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
-#ifdef FIRM_STATISTICS
-
-#include "firmstat.h"
-# include "irop_t.h"
-# include "irnode_t.h"
-# include "irgraph_t.h"
-# include "pset.h"
-# include "irprog.h"
-# include "irgwalk.h"
-# include "pattern.h"
-# include "counter.h"
-
-/*
- * just be make some things clear :-), the
- * poor man "generics"
- */
-#define HASH_MAP(type) hmap_##type
-
-typedef pset hmap_node_entry_t;
-typedef pset hmap_graph_entry_t;
-typedef pset hmap_opt_entry_t;
-typedef pset hmap_block_entry_t;
-typedef pset hmap_ir_op;
-
-/*
- * An entry for ir_nodes, used in ir_graph statistics.
- */
-typedef struct _node_entry_t {
- counter_t cnt_alive; /**< amount of nodes in this entry */
- counter_t new_node; /**< amount of new nodes for this entry */
- counter_t into_Id; /**< amount of nodes that turned into Id's for this entry */
- const ir_op *op; /**< the op for this entry */
-} node_entry_t;
-
-/*
- * An entry for ir_graphs
- */
-typedef struct _graph_entry_t {
- HASH_MAP(node_entry_t) *opcode_hash; /**< hash map containing the opcode counter */
- HASH_MAP(block_entry_t) *block_hash; /**< hash map countaining the block counter */
- counter_t cnt_walked; /**< walker walked over the graph */
- counter_t cnt_walked_blocks; /**< walker walked over the graph blocks */
- counter_t cnt_was_inlined; /**< number of times other graph were inlined */
- counter_t cnt_got_inlined; /**< number of times this graph was inlined */
- counter_t cnt_edges; /**< number of DF edges in this graph */
- HASH_MAP(opt_entry_t) *opt_hash[STAT_OPT_MAX]; /**< hash maps containing opcode counter for optimizations */
- ir_graph *irg; /**< the graph of this object */
- entity *ent; /**< the entity of this graph if one exists */
- int deleted; /**< set if this irg was deleted */
-} graph_entry_t;
-
-/**
- * An entry for optimized ir_nodes
- */
-typedef struct _opt_entry_t {
- counter_t count; /**< optimization counter */
- const ir_op *op; /**< the op for this entry */
-} opt_entry_t;
-
-/**
- * An entry for a block in a ir-graph
- */
-typedef struct _block_entry_t {
- counter_t cnt_nodes; /**< the counter of nodes in this block */
- counter_t cnt_edges; /**< the counter of edges in this block */
- counter_t cnt_in_edges; /**< the counter of edges incoming from other blocks to this block */
- counter_t cnt_out_edges; /**< the counter of edges outgoing from this block to other blocks */
- long block_nr; /**< block nr */
-} block_entry_t;
-
-/** forward */
-typedef struct _dumper_t dumper_t;
-
-/**
- * handler for dumping an IRG
- *
- * @param dmp the dumper
- * @param entry the IR-graph hash map entry
- */
-typedef void (*dump_graph_FUNC)(dumper_t *dmp, graph_entry_t *entry);
-
-/**
- * handler for dumper init
- *
- * @param dmp the dumper
- * @param name name of the file to dump to
- */
-typedef void (*dump_init_FUNC)(dumper_t *dmp, const char *name);
-
-/**
- * handler for dumper finish
- *
- * @param dmp the dumper
- */
-typedef void (*dump_finish_FUNC)(dumper_t *dmp);
-
-
-/**
- * a dumper description
- */
-struct _dumper_t {
- dump_graph_FUNC dump_graph; /**< handler for dumping an irg */
- dump_init_FUNC init; /**< handler for init */
- dump_finish_FUNC finish; /**< handler for finish */
- FILE *f; /**< the file to dump to */
- dumper_t *next; /**< link to the next dumper */
-};
-
-/**
- * statistics info
- */
-typedef struct _statistic_info_t {
- struct obstack cnts; /**< obstack containing the counters */
- HASH_MAP(graph_entry_t) *irg_hash; /**< hash map containing the counter for irgs */
- HASH_MAP(ir_op) *ir_op_hash; /**< hash map containing all ir_ops (accessible by op_codes) */
- int recursive; /**< flag for detecting recursive hook calls */
- int in_dead_node_elim; /**< set, if dead node elimination runs */
- ir_op *op_Phi0; /**< needed pseudo op */
- ir_op *op_PhiM; /**< needed pseudo op */
- dumper_t *dumper; /**< list of dumper */
- int enable; /**< if set, statistic is enabled */
-} stat_info_t;
+#include "firmstat_t.h"
+#include "pattern.h"
+#include "dags.h"
/**
* names of the optimizations
return e1->code != e2->code;
}
+/**
+ * clears all counter in a node_entry_t
+ */
+static void opcode_clear_entry(node_entry_t *elem)
+{
+ cnt_clr(&elem->cnt_alive);
+ cnt_clr(&elem->new_node);
+ cnt_clr(&elem->into_Id);
+}
+
/**
* Returns the associates node_entry_t for an ir_op
*/
elem = obstack_alloc(&status->cnts, sizeof(*elem));
/* clear counter */
- cnt_clr(&elem->cnt_alive);
- cnt_clr(&elem->new_node);
- cnt_clr(&elem->into_Id);
+ opcode_clear_entry(elem);
elem->op = op;
return (unsigned)irg >> 3;
}
+/**
+ * clears all counter in a graph_entry_t
+ */
+static void graph_clear_entry(graph_entry_t *elem)
+{
+ cnt_clr(&elem->cnt_walked);
+ cnt_clr(&elem->cnt_walked_blocks);
+ cnt_clr(&elem->cnt_got_inlined);
+ cnt_clr(&elem->cnt_was_inlined);
+ cnt_clr(&elem->cnt_edges);
+}
+
/**
* Returns the acssociates graph_entry_t for an irg
*/
elem = obstack_alloc(&status->cnts, sizeof(*elem));
- cnt_clr(&elem->cnt_walked);
- cnt_clr(&elem->cnt_walked_blocks);
- cnt_clr(&elem->cnt_got_inlined);
- cnt_clr(&elem->cnt_was_inlined);
- cnt_clr(&elem->cnt_edges);
+ /* clear counter */
+ graph_clear_entry(elem);
/* new hash table for opcodes here */
elem->opcode_hash = new_pset(opcode_cmp, 5);
return pset_insert(set, elem, irg_hash(irg));
}
+/**
+ * clears all counter in an opt_entry_t
+ */
+static void opt_clear_entry(opt_entry_t *elem)
+{
+ cnt_clr(&elem->count);
+}
+
/**
* Returns the associates opt_entry_t for an ir_op
*/
elem = obstack_alloc(&status->cnts, sizeof(*elem));
/* clear new counter */
- cnt_clr(&elem->count);
+ opt_clear_entry(elem);
elem->op = op;
return pset_insert(set, elem, op->code);
}
+/**
+ * clears all counter in a block_entry_t
+ */
+static void block_clear_entry(block_entry_t *elem)
+{
+ cnt_clr(&elem->cnt_nodes);
+ cnt_clr(&elem->cnt_edges);
+ cnt_clr(&elem->cnt_in_edges);
+ cnt_clr(&elem->cnt_out_edges);
+}
+
/**
* Returns the associates block_entry_t for an block
*/
elem = obstack_alloc(&status->cnts, sizeof(*elem));
/* clear new counter */
- cnt_clr(&elem->cnt_nodes);
- cnt_clr(&elem->cnt_edges);
- cnt_clr(&elem->cnt_in_edges);
- cnt_clr(&elem->cnt_out_edges);
+ block_clear_entry(elem);
elem->block_nr = block_nr;
{
node_entry_t *entry;
+ /* clear first the alive counter in the graph */
+ for (entry = pset_first(graph->opcode_hash); entry; entry = pset_next(graph->opcode_hash)) {
+ cnt_clr(&entry->cnt_alive);
+ }
+
+ /* count the nodes in the graph */
irg_walk_graph(graph->irg, count_nodes, NULL, graph);
/* assume we walk every graph only ONCE, we could sum here the global count */
/**
* register a dumper
*/
-static void stat_register_dumper(dumper_t *dumper, const char *name)
+static void stat_register_dumper(dumper_t *dumper)
{
dumper->next = status->dumper;
status->dumper = dumper;
-
- if (dumper->init)
- dumper->init(dumper, name);
}
/**
}
}
+/**
+ * initialise the dumper
+ */
+static void dump_init(const char *name)
+{
+ dumper_t *dumper;
+
+ for (dumper = status->dumper; dumper; dumper = dumper->next) {
+ if (dumper->init)
+ dumper->init(dumper, name);
+ }
+}
+
/**
* finish the dumper
*/
}
else {
fprintf(dmp->f, "\nGlobals counts:\n");
+ fprintf(dmp->f, "--------------\n");
dump_opts = 0;
}
for (i = 0; i < sizeof(entry->opt_hash)/sizeof(entry->opt_hash[0]); ++i) {
simple_dump_opt_hash(dmp, entry->opt_hash[i], i);
}
- }
- /* dump block info */
- fprintf(dmp->f, "\n%12s %12s %12s %12s %12s %12s\n", "Block Nr", "Nodes", "intern", "incoming", "outgoing", "quot");
- for (b_entry = pset_first(entry->block_hash);
- b_entry;
- b_entry = pset_next(entry->block_hash)) {
- fprintf(dmp->f, "%12ld %12u %12u %12u %12u %4.8f\n",
- b_entry->block_nr,
- b_entry->cnt_nodes.cnt[0],
- b_entry->cnt_edges.cnt[0],
- b_entry->cnt_in_edges.cnt[0],
- b_entry->cnt_out_edges.cnt[0],
- (double)b_entry->cnt_edges.cnt[0] / (double)b_entry->cnt_nodes.cnt[0]
- );
+ /* dump block info */
+ fprintf(dmp->f, "\n%12s %12s %12s %12s %12s %12s\n", "Block Nr", "Nodes", "intern E", "incoming E", "outgoing E", "quot");
+ for (b_entry = pset_first(entry->block_hash);
+ b_entry;
+ b_entry = pset_next(entry->block_hash)) {
+ fprintf(dmp->f, "BLK %12ld %12u %12u %12u %12u %4.8f\n",
+ b_entry->block_nr,
+ b_entry->cnt_nodes.cnt[0],
+ b_entry->cnt_edges.cnt[0],
+ b_entry->cnt_in_edges.cnt[0],
+ b_entry->cnt_out_edges.cnt[0],
+ (double)b_entry->cnt_edges.cnt[0] / (double)b_entry->cnt_nodes.cnt[0]
+ );
+ }
}
}
*/
static void simple_init(dumper_t *dmp, const char *name)
{
- dmp->f = fopen(name, "w");
+ char fname[2048];
+
+ snprintf(fname, sizeof(fname), "%s.txt", name);
+ dmp->f = fopen(fname, "w");
}
/**
*/
static void csv_init(dumper_t *dmp, const char *name)
{
- dmp->f = fopen(name, "a");
+ char fname[2048];
+
+ snprintf(fname, sizeof(fname), "%s.csv", name);
+ dmp->f = fopen(fname, "a");
}
/**
status->op_Phi0 = &_op_Phi0;
status->op_PhiM = &_op_PhiM;
- stat_register_dumper(&simple_dumper, "firmstat.txt");
- stat_register_dumper(&csv_dumper, "firmstat.csv");
+ stat_register_dumper(&simple_dumper);
+ stat_register_dumper(&csv_dumper);
/* initialize the pattern hash */
stat_init_pattern_history(enable_options & FIRMSTAT_PATTERN_ENABLED);
/* count the nodes of the graph yet, it will be destroyed later */
count_nodes_in_graph(global, graph);
+ /* count the DAG's */
+ count_dags_in_graph(global, graph);
+
/* calculate the pattern */
stat_calc_pattern_history(irg);
}
}
/* Finish the statistics */
-void stat_finish(void)
+void stat_finish(const char *name)
{
if (! status->enable)
return;
graph_entry_t *entry;
graph_entry_t *global = graph_get_entry(NULL, status->irg_hash);
+ dump_init(name);
+
/* dump per graph */
for (entry = pset_first(status->irg_hash); entry; entry = pset_next(status->irg_hash)) {
/* the graph is still alive, count the nodes on it */
count_nodes_in_graph(global, entry);
+ /* count the DAG's */
+ count_dags_in_graph(global, entry);
+
/* calculate the pattern */
stat_calc_pattern_history(entry->irg);
}
dump_graph(entry);
+
+ /* clear the counter here:
+ * we need only the edge counter to be cleared, all others are cumulative
+ */
+ cnt_clr(&entry->cnt_edges);
}
/* dump global */
- dump_graph(global);
+// dump_graph(global);
dump_finish();
stat_finish_pattern_history();
+ /* clear the global counter here */
+ {
+ node_entry_t *entry;
+
+ for (entry = pset_first(global->opcode_hash); entry; entry = pset_next(global->opcode_hash)) {
+ opcode_clear_entry(entry);
+ }
+ graph_clear_entry(global);
+ }
+
/* finished */
- status->enable = 0;
+// status->enable = 0;
}
STAT_LEAVE;
}
void init_stat(unsigned enable_options) {}
-void stat_finish(void) {}
+void stat_finish(const char *name) {}
void stat_new_ir_op(const ir_op *op) {}
/**
* Finish the statistics.
* Never called from libFirm should be called from user.
+ *
+ * @param name basename of the statistic output file
*/
-void stat_finish(void);
+void stat_finish(const char *name);
#ifdef FIRM_STATISTICS
*/
void init_stat(unsigned enable_options);
-/**
- * Finish the statistics.
- */
-void stat_finish(void);
-
/**
* A new IR op is registered.
*/
#else
#define init_stat(enable_options)
-#define stat_finish()
+#define stat_finish(name)
#define stat_new_ir_op(op)
#define stat_free_ir_op(op)
#define stat_new_node(node)
--- /dev/null
+/*
+ * Project: libFIRM
+ * File name: ir/stat/firmstat_t.h
+ * Purpose: Statistics for Firm. Internal data structures.
+ * Author: Michael Beck
+ * Created:
+ * CVS-ID: $Id$
+ * Copyright: (c) 2004 Universität Karlsruhe
+ * Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
+ */
+#ifndef _FIRMSTAT_T_H_
+#define _FIRMSTAT_T_H_
+
+/**
+ * @file firmstat_t.h
+ */
+#include "firmstat.h"
+
+#include "irop_t.h"
+#include "irnode_t.h"
+#include "irgraph_t.h"
+#include "pset.h"
+#include "irprog.h"
+#include "irgwalk.h"
+#include "counter.h"
+
+/*
+ * just be make some things clear :-), the
+ * poor man "generics"
+ */
+#define HASH_MAP(type) hmap_##type
+
+typedef pset hmap_node_entry_t;
+typedef pset hmap_graph_entry_t;
+typedef pset hmap_opt_entry_t;
+typedef pset hmap_block_entry_t;
+typedef pset hmap_ir_op;
+typedef pset hmap_distrib_entry_t;
+
+
+/**
+ * An entry for ir_nodes, used in ir_graph statistics.
+ */
+typedef struct _node_entry_t {
+ counter_t cnt_alive; /**< amount of nodes in this entry */
+ counter_t new_node; /**< amount of new nodes for this entry */
+ counter_t into_Id; /**< amount of nodes that turned into Id's for this entry */
+ const ir_op *op; /**< the op for this entry */
+} node_entry_t;
+
+/**
+ * An entry for ir_graphs
+ */
+typedef struct _graph_entry_t {
+ HASH_MAP(node_entry_t) *opcode_hash; /**< hash map containing the opcode counter */
+ HASH_MAP(block_entry_t) *block_hash; /**< hash map countaining the block counter */
+ counter_t cnt_walked; /**< walker walked over the graph */
+ counter_t cnt_walked_blocks; /**< walker walked over the graph blocks */
+ counter_t cnt_was_inlined; /**< number of times other graph were inlined */
+ counter_t cnt_got_inlined; /**< number of times this graph was inlined */
+ counter_t cnt_edges; /**< number of DF edges in this graph */
+ HASH_MAP(opt_entry_t) *opt_hash[STAT_OPT_MAX]; /**< hash maps containing opcode counter for optimizations */
+ ir_graph *irg; /**< the graph of this object */
+ entity *ent; /**< the entity of this graph if one exists */
+ int deleted; /**< set if this irg was deleted */
+} graph_entry_t;
+
+/**
+ * An entry for optimized ir_nodes
+ */
+typedef struct _opt_entry_t {
+ counter_t count; /**< optimization counter */
+ const ir_op *op; /**< the op for this entry */
+} opt_entry_t;
+
+/**
+ * An entry for a block in a ir-graph
+ */
+typedef struct _block_entry_t {
+ counter_t cnt_nodes; /**< the counter of nodes in this block */
+ counter_t cnt_edges; /**< the counter of edges in this block */
+ counter_t cnt_in_edges; /**< the counter of edges incoming from other blocks to this block */
+ counter_t cnt_out_edges; /**< the counter of edges outgoing from this block to other blocks */
+ long block_nr; /**< block nr */
+} block_entry_t;
+
+/** forward */
+typedef struct _dumper_t dumper_t;
+
+/**
+ * handler for dumping an IRG
+ *
+ * @param dmp the dumper
+ * @param entry the IR-graph hash map entry
+ */
+typedef void (*dump_graph_FUNC)(dumper_t *dmp, graph_entry_t *entry);
+
+/**
+ * handler for dumper init
+ *
+ * @param dmp the dumper
+ * @param name name of the file to dump to
+ */
+typedef void (*dump_init_FUNC)(dumper_t *dmp, const char *name);
+
+/**
+ * handler for dumper finish
+ *
+ * @param dmp the dumper
+ */
+typedef void (*dump_finish_FUNC)(dumper_t *dmp);
+
+
+/**
+ * a dumper description
+ */
+struct _dumper_t {
+ dump_graph_FUNC dump_graph; /**< handler for dumping an irg */
+ dump_init_FUNC init; /**< handler for init */
+ dump_finish_FUNC finish; /**< handler for finish */
+ FILE *f; /**< the file to dump to */
+ dumper_t *next; /**< link to the next dumper */
+};
+
+/**
+ * statistics info
+ */
+typedef struct _statistic_info_t {
+ struct obstack cnts; /**< obstack containing the counters */
+ HASH_MAP(graph_entry_t) *irg_hash; /**< hash map containing the counter for irgs */
+ HASH_MAP(ir_op) *ir_op_hash; /**< hash map containing all ir_ops (accessible by op_codes) */
+ int recursive; /**< flag for detecting recursive hook calls */
+ int in_dead_node_elim; /**< set, if dead node elimination runs */
+ ir_op *op_Phi0; /**< needed pseudo op */
+ ir_op *op_PhiM; /**< needed pseudo op */
+ dumper_t *dumper; /**< list of dumper */
+ int enable; /**< if set, statistic is enabled */
+} stat_info_t;
+
+/**
+ * An entry in a distribution table
+ */
+typedef struct _distrib_entry_t {
+ counter_t cnt; /**< the current count */
+ const void *object; /**< the object which is counted */
+} distrib_entry_t;
+
+/** The type of the hash function for objects in distribution tables. */
+typedef unsigned (*distrib_hash_fun)(const void *object);
+
+/**
+ * The distribution table.
+ */
+typedef struct _distrib_tbl_t {
+ struct obstack cnts; /**< obstack containing the distrib_entry_t entries */
+ HASH_MAP(distrib_entry_t) *hash_map; /**< the hash map containing the distribution */
+ distrib_hash_fun hash_func; /**< the hash function for object in this distribution */
+ unsigned int_dist; /**< non-zero, if it's a integer distribution */
+} distrib_tbl_t;
+
+/* API for distribution tables */
+
+/**
+ * creates a new distribution table
+ *
+ * @param cmp_func Compare function for objects in the distribution
+ * @param hash_func Hash function for objects in the distribution
+ */
+distrib_tbl_t *stat_new_distrib_tbl(pset_cmp_fun cmp_func, distrib_hash_fun hash_func);
+
+/**
+ * creates a new distribution table for an integer distribution
+ */
+distrib_tbl_t *stat_new_int_distrib_tbl(void);
+
+/**
+ * destroys a distribution table
+ */
+void stat_delete_distrib_tbl(distrib_tbl_t *tbl);
+
+/**
+ * adds a new object count into the distribution table
+ */
+void stat_add_distrib_tbl(distrib_tbl_t *tbl, const void *object, const counter_t *cnt);
+
+/**
+ * adds a new key count into the integer distribution table
+ */
+void stat_add_int_distrib_tbl(distrib_tbl_t *tbl, int key, const counter_t *cnt);
+
+/**
+ * calculates the mean value of a distribution
+ */
+double stat_calc_mean_distrib_tbl(distrib_tbl_t *tbl);
+
+/** evaluates each entry of a distribution table */
+typedef void (*eval_distrib_entry_fun)(const distrib_entry_t *entry);
+
+/**
+ * iterates over all entries in a distribution table
+ */
+void stat_iterate_distrib_tbl(distrib_tbl_t *tbl, eval_distrib_entry_fun eval);
+
+#endif /* _FIRMSTAT_T_H_ */