Added support for DAG's and distribution tables
authorMichael Beck <beck@ipd.info.uni-karlsruhe.de>
Mon, 6 Sep 2004 13:59:00 +0000 (13:59 +0000)
committerMichael Beck <beck@ipd.info.uni-karlsruhe.de>
Mon, 6 Sep 2004 13:59:00 +0000 (13:59 +0000)
[r3830]

ir/stat/Makefile.in
ir/stat/counter.h
ir/stat/dags.c [new file with mode: 0644]
ir/stat/dags.h [new file with mode: 0644]
ir/stat/distrib.c [new file with mode: 0644]
ir/stat/firmstat.c
ir/stat/firmstat.h
ir/stat/firmstat_t.h [new file with mode: 0644]

index e4fff05..c8deadb 100644 (file)
@@ -25,7 +25,8 @@ SOURCES +=    Makefile.in \
                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
 
 
index adddb90..f6074ca 100644 (file)
@@ -111,7 +111,6 @@ static INLINE int cnt_cmp(const counter_t *a, const counter_t *b)
   int i;
   unsigned va, vb;
 
-
   for (i = STAT_CNT_NUM - 1 ; i >= 0; --i) {
     va = a->cnt[i];
     vb = b->cnt[i];
@@ -125,4 +124,23 @@ static INLINE int cnt_cmp(const counter_t *a, const counter_t *b)
   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_ */
diff --git a/ir/stat/dags.c b/ir/stat/dags.c
new file mode 100644 (file)
index 0000000..48aff25
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * 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);
+}
diff --git a/ir/stat/dags.h b/ir/stat/dags.h
new file mode 100644 (file)
index 0000000..322a848
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * 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_ */
diff --git a/ir/stat/distrib.c b/ir/stat/distrib.c
new file mode 100644 (file)
index 0000000..bebba63
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * 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);
+  }
+}
index 7ecaf62..a4c9391 100644 (file)
 # 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
@@ -229,6 +111,16 @@ static int opcode_cmp_2(const void *elt, const void *key)
   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
  */
@@ -246,9 +138,7 @@ static node_entry_t *opcode_get_entry(const ir_op *op, pset *set)
   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;
 
@@ -275,6 +165,18 @@ static INLINE unsigned irg_hash(const ir_graph *irg)
   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
  */
@@ -292,11 +194,8 @@ static graph_entry_t *graph_get_entry(ir_graph *irg, pset *set)
 
   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);
@@ -309,6 +208,14 @@ static graph_entry_t *graph_get_entry(ir_graph *irg, pset *set)
   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
  */
@@ -326,13 +233,24 @@ static opt_entry_t *opt_get_entry(const ir_op *op, pset *set)
   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
  */
@@ -350,10 +268,7 @@ static block_entry_t *block_get_entry(long block_nr, pset *set)
   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;
 
@@ -465,6 +380,12 @@ static void count_nodes_in_graph(graph_entry_t *global, graph_entry_t *graph)
 {
   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 */
@@ -482,13 +403,10 @@ static void count_nodes_in_graph(graph_entry_t *global, graph_entry_t *graph)
 /**
  * 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);
 }
 
 /**
@@ -504,6 +422,19 @@ static void dump_graph(graph_entry_t *entry)
   }
 }
 
+/**
+ * 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
  */
@@ -605,6 +536,7 @@ static void simple_dump_graph(dumper_t *dmp, graph_entry_t *entry)
   }
   else {
     fprintf(dmp->f, "\nGlobals counts:\n");
+    fprintf(dmp->f, "--------------\n");
     dump_opts = 0;
   }
 
@@ -618,21 +550,21 @@ static void simple_dump_graph(dumper_t *dmp, graph_entry_t *entry)
     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]
+      );
+    }
   }
 }
 
@@ -641,7 +573,10 @@ static void simple_dump_graph(dumper_t *dmp, graph_entry_t *entry)
  */
 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");
 }
 
 /**
@@ -743,7 +678,10 @@ static void csv_dump_graph(dumper_t *dmp, graph_entry_t *entry)
  */
 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");
 }
 
 /**
@@ -806,8 +744,8 @@ void init_stat(unsigned enable_options)
   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);
@@ -933,6 +871,9 @@ void stat_free_graph(ir_graph *irg)
     /* 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);
   }
@@ -1084,7 +1025,7 @@ void stat_dead_node_elim_stop(ir_graph *irg)
 }
 
 /* Finish the statistics */
-void stat_finish(void)
+void stat_finish(const char *name)
 {
   if (! status->enable)
     return;
@@ -1094,6 +1035,8 @@ void stat_finish(void)
     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)) {
 
@@ -1106,21 +1049,39 @@ void stat_finish(void)
         /* 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;
 }
@@ -1133,7 +1094,7 @@ void stat_finish(void)
 
 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) {}
 
index ef1593c..a8ce64b 100644 (file)
@@ -29,8 +29,10 @@ enum firmstat_options_t {
 /**
  * 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
 
@@ -57,11 +59,6 @@ typedef enum {
  */
 void init_stat(unsigned enable_options);
 
-/**
- * Finish the statistics.
- */
-void stat_finish(void);
-
 /**
  * A new IR op is registered.
  */
@@ -152,7 +149,7 @@ ir_op *stat_get_op_from_opcode(opcode code);
 #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)
diff --git a/ir/stat/firmstat_t.h b/ir/stat/firmstat_t.h
new file mode 100644 (file)
index 0000000..662d35f
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ * 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_ */