statistics.c: New file.
authorRichard Biener <rguenth@gcc.gnu.org>
Thu, 15 May 2008 14:00:22 +0000 (14:00 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Thu, 15 May 2008 14:00:22 +0000 (14:00 +0000)
2008-05-15  Richard Guenther  <rguenther@suse.de>

        * statistics.c: New file.

From-SVN: r135359

gcc/statistics.c [new file with mode: 0644]

diff --git a/gcc/statistics.c b/gcc/statistics.c
new file mode 100644 (file)
index 0000000..1f0090c
--- /dev/null
@@ -0,0 +1,342 @@
+/* Optimization statistics functions.
+   Copyright (C) 2008
+   Free Software Foundation, Inc.
+   Contributed by Richard Guenther  <rguenther@suse.de>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree-pass.h"
+#include "tree-dump.h"
+#include "statistics.h"
+#include "hashtab.h"
+#include "tm.h"
+#include "function.h"
+
+static int statistics_dump_nr;
+static int statistics_dump_flags;
+static FILE *statistics_dump_file;
+
+/* Statistics entry.  A integer counter associated to a string ID
+   and value.  */
+
+typedef struct statistics_counter_s {
+  const char *id;
+  int val;
+  bool histogram_p;
+  unsigned HOST_WIDE_INT count;
+  unsigned HOST_WIDE_INT prev_dumped_count;
+} statistics_counter_t;
+
+/* Array of statistic hashes, indexed by pass id.  */
+static htab_t *statistics_hashes;
+static unsigned nr_statistics_hashes;
+
+/* Hash a statistic counter by its string ID.  */
+
+static hashval_t
+hash_statistics_hash (const void *p)
+{
+  statistics_counter_t *c = (statistics_counter_t *)p;
+  return htab_hash_string (c->id) + c->val;
+}
+
+/* Compare two statistic counters by their string IDs.  */
+
+static int
+hash_statistics_eq (const void *p, const void *q)
+{
+  statistics_counter_t *c1 = (statistics_counter_t *)p;
+  statistics_counter_t *c2 = (statistics_counter_t *)q;
+  return c1->val == c2->val && strcmp (c1->id, c2->id) == 0;
+}
+
+/* Free a statistics entry.  */
+
+static void
+hash_statistics_free (void *p)
+{
+  free ((void *)((statistics_counter_t *)p)->id);
+  free (p);
+}
+
+/* Return the current hashtable to be used for recording or printing
+   statistics.  */
+
+static htab_t
+curr_statistics_hash (void)
+{
+  unsigned idx = current_pass->static_pass_number;
+
+  if (idx < nr_statistics_hashes
+      && statistics_hashes[idx] != NULL)
+    return statistics_hashes[idx];
+
+  if (idx >= nr_statistics_hashes)
+    {
+      statistics_hashes = xrealloc (statistics_hashes,
+                                   (idx + 1) * sizeof (htab_t));
+      memset (statistics_hashes + nr_statistics_hashes, 0,
+             (idx + 1 - nr_statistics_hashes) * sizeof (htab_t));
+      nr_statistics_hashes = idx + 1;
+    }
+
+  statistics_hashes[idx] = htab_create (15, hash_statistics_hash,
+                                       hash_statistics_eq,
+                                       hash_statistics_free);
+
+  return statistics_hashes[idx];
+}
+
+/* Helper for statistics_fini_pass.  Print the counter difference
+   since the last dump for the pass dump files.  */
+
+static int
+statistics_fini_pass_1 (void **slot, void *data ATTRIBUTE_UNUSED)
+{
+  statistics_counter_t *counter = (statistics_counter_t *)*slot;
+  unsigned HOST_WIDE_INT count = counter->count - counter->prev_dumped_count;
+  if (count == 0)
+    return 1;
+  if (counter->histogram_p)
+    fprintf (dump_file, "%s == %d: " HOST_WIDE_INT_PRINT_DEC "\n",
+            counter->id, counter->val, count);
+  else
+    fprintf (dump_file, "%s: " HOST_WIDE_INT_PRINT_DEC "\n",
+            counter->id, count);
+  counter->prev_dumped_count = counter->count;
+  return 1;
+}
+
+/* Helper for statistics_fini_pass.  Print the counter difference
+   since the last dump for the statistics dump.  */
+
+static int
+statistics_fini_pass_2 (void **slot, void *data ATTRIBUTE_UNUSED)
+{
+  statistics_counter_t *counter = (statistics_counter_t *)*slot;
+  unsigned HOST_WIDE_INT count = counter->count - counter->prev_dumped_count;
+  if (count == 0)
+    return 1;
+  counter->prev_dumped_count = counter->count;
+  if (counter->histogram_p)
+    fprintf (statistics_dump_file,
+            "%d %s \"%s == %d\" \"%s\" " HOST_WIDE_INT_PRINT_DEC "\n",
+            current_pass->static_pass_number,
+            current_pass->name,
+            counter->id, counter->val,
+            cfun ? IDENTIFIER_POINTER (DECL_NAME (cfun->decl)) : "(nofn)",
+            count);
+  else
+    fprintf (statistics_dump_file,
+            "%d %s \"%s\" \"%s\" " HOST_WIDE_INT_PRINT_DEC "\n",
+            current_pass->static_pass_number,
+            current_pass->name,
+            counter->id,
+            cfun ? IDENTIFIER_POINTER (DECL_NAME (cfun->decl)) : "(nofn)",
+            count);
+  counter->prev_dumped_count = counter->count;
+  return 1;
+}
+
+/* Helper for statistics_fini_pass, reset the counters.  */
+
+static int
+statistics_fini_pass_3 (void **slot, void *data ATTRIBUTE_UNUSED)
+{
+  statistics_counter_t *counter = (statistics_counter_t *)*slot;
+  counter->prev_dumped_count = counter->count;
+  return 1;
+}
+
+/* Dump the current statistics incrementally.  */
+
+void
+statistics_fini_pass (void)
+{
+  if (current_pass->static_pass_number == -1)
+    return;
+
+  if (dump_file
+      && dump_flags & TDF_STATS)
+    {
+      fprintf (dump_file, "\n");
+      fprintf (dump_file, "Pass statistics:\n");
+      fprintf (dump_file, "----------------\n");
+      htab_traverse_noresize (curr_statistics_hash (),
+                             statistics_fini_pass_1, NULL);
+      fprintf (dump_file, "\n");
+    }
+  if (statistics_dump_file
+      && !(statistics_dump_flags & TDF_STATS
+          || statistics_dump_flags & TDF_DETAILS))
+    htab_traverse_noresize (curr_statistics_hash (),
+                           statistics_fini_pass_2, NULL);
+  htab_traverse_noresize (curr_statistics_hash (),
+                         statistics_fini_pass_3, NULL);
+}
+
+/* Helper for printing summary information.  */
+
+static int
+statistics_fini_1 (void **slot, void *data)
+{
+  struct opt_pass *pass = (struct opt_pass *)data;
+  statistics_counter_t *counter = (statistics_counter_t *)*slot;
+  if (counter->count == 0)
+    return 1;
+  if (counter->histogram_p)
+    fprintf (statistics_dump_file,
+            "%d %s \"%s == %d\" " HOST_WIDE_INT_PRINT_DEC "\n",
+            pass->static_pass_number,
+            pass->name,
+            counter->id, counter->val,
+            counter->count);
+  else
+    fprintf (statistics_dump_file,
+            "%d %s \"%s\" " HOST_WIDE_INT_PRINT_DEC "\n",
+            pass->static_pass_number,
+            pass->name,
+            counter->id,
+            counter->count);
+  return 1;
+}
+
+/* Finish the statistics and dump summary information.  */
+
+void
+statistics_fini (void)
+{
+  if (!statistics_dump_file)
+    return;
+
+  if (statistics_dump_flags & TDF_STATS)
+    {
+      unsigned i;
+      for (i = 0; i < nr_statistics_hashes; ++i)
+       if (statistics_hashes[i] != NULL
+           && get_pass_for_id (i) != NULL)
+         htab_traverse_noresize (statistics_hashes[i],
+                                 statistics_fini_1, get_pass_for_id (i));
+    }
+
+  dump_end (statistics_dump_nr, statistics_dump_file);
+}
+
+/* Register the statistics dump file.  */
+
+void
+statistics_early_init (void)
+{
+  statistics_dump_nr = dump_register (".statistics", "statistics",
+                                     "statistics", TDF_TREE);
+}
+
+/* Init the statistics.  */
+
+void
+statistics_init (void)
+{
+  statistics_dump_file = dump_begin (statistics_dump_nr, NULL);
+  statistics_dump_flags = get_dump_file_info (statistics_dump_nr)->flags;
+}
+
+/* Lookup or add a statistics counter in the hashtable HASH with ID, VAL
+   and HISTOGRAM_P.  */
+
+static statistics_counter_t *
+lookup_or_add_counter (htab_t hash, const char *id, int val,
+                      bool histogram_p)
+{
+  statistics_counter_t **counter;
+  statistics_counter_t c;
+  c.id = id;
+  c.val = val;
+  counter = (statistics_counter_t **) htab_find_slot (hash, &c, INSERT);
+  if (!*counter)
+    {
+      *counter = XNEW (struct statistics_counter_s);
+      (*counter)->id = xstrdup (id);
+      (*counter)->val = val;
+      (*counter)->histogram_p = histogram_p;
+      (*counter)->prev_dumped_count = 0;
+      (*counter)->count = 0;
+    }
+  return *counter;
+}
+
+/* Add statistics information about event ID in function FN.
+   This will increment the counter associated with ID by INCR.
+   It will also dump the event to the global statistics file if requested.  */
+
+void
+statistics_counter_event (struct function *fn, const char *id, int incr)
+{
+  statistics_counter_t *counter;
+
+  if ((!(dump_flags & TDF_STATS)
+       && !statistics_dump_file)
+      || incr == 0)
+    return;
+
+  counter = lookup_or_add_counter (curr_statistics_hash (), id, 0, false);
+  gcc_assert (!counter->histogram_p);
+  counter->count += incr;
+
+  if (!statistics_dump_file
+      || !(statistics_dump_flags & TDF_DETAILS))
+    return;
+
+  fprintf (statistics_dump_file,
+          "%d %s \"%s\" \"%s\" %d\n",
+          current_pass->static_pass_number,
+          current_pass->name,
+          id,
+          fn ? IDENTIFIER_POINTER (DECL_NAME (fn->decl)) : "(nofn)",
+          incr);
+}
+
+/* Add statistics information about event ID in function FN with the
+   histogram value VAL.
+   It will dump the event to the global statistics file if requested.  */
+
+void
+statistics_histogram_event (struct function *fn, const char *id, int val)
+{
+  statistics_counter_t *counter;
+
+  if (!(dump_flags & TDF_STATS)
+      && !statistics_dump_file)
+    return;
+
+  counter = lookup_or_add_counter (curr_statistics_hash (), id, val, true);
+  gcc_assert (counter->histogram_p);
+  counter->count += 1;
+
+  if (!statistics_dump_file
+      || !(statistics_dump_flags & TDF_DETAILS))
+    return;
+
+  fprintf (statistics_dump_file,
+          "%d %s \"%s == %d\" \"%s\" 1\n",
+          current_pass->static_pass_number,
+          current_pass->name,
+          id, val,
+          fn ? IDENTIFIER_POINTER (DECL_NAME (fn->decl)) : "(nofn)");
+}